Skip to content

Commit

Permalink
Rework traces
Browse files Browse the repository at this point in the history
  • Loading branch information
cedi committed Mar 8, 2023
1 parent 7d59235 commit d863486
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 171 deletions.
15 changes: 11 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@ require (
github.com/swaggo/gin-swagger v1.5.3
github.com/swaggo/swag v1.8.10
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.39.0
go.opentelemetry.io/otel v1.13.0
go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.13.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.13.0
go.opentelemetry.io/otel/sdk v1.13.0
go.opentelemetry.io/otel/trace v1.13.0
go.opentelemetry.io/otel/sdk v1.14.0
go.opentelemetry.io/otel/trace v1.14.0
golang.org/x/exp v0.0.0-20230304125523-9ff063c70017
k8s.io/api v0.26.2
k8s.io/apimachinery v0.26.2
k8s.io/client-go v0.26.2
sigs.k8s.io/controller-runtime v0.14.5
)

require (
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0 // indirect
go.opentelemetry.io/otel/metric v0.37.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.37.0 // indirect
)

require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
Expand Down Expand Up @@ -77,7 +83,8 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.37.0
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
Expand Down
82 changes: 16 additions & 66 deletions go.sum

Large diffs are not rendered by default.

30 changes: 19 additions & 11 deletions pkg/client/authenticated_shortlink_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import (
"context"

"github.com/cedi/urlshortener/api/v1alpha1"
"github.com/cedi/urlshortener/pkg/model"

"github.com/go-logr/logr"
"github.com/pkg/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"golang.org/x/exp/slices"
)

type ShortlinkClientAuth struct {
Expand All @@ -27,6 +30,8 @@ func (c *ShortlinkClientAuth) List(ct context.Context, username string) (*v1alph
ctx, span := c.tracer.Start(ct, "ShortlinkClientAuth.List")
defer span.End()

span.SetAttributes(attribute.String("username", username))

list, err := c.client.List(ctx)
if err != nil {
return nil, err
Expand All @@ -51,13 +56,15 @@ func (c *ShortlinkClientAuth) Get(ct context.Context, username string, name stri
ctx, span := c.tracer.Start(ct, "ShortlinkClientAuth.Get")
defer span.End()

span.SetAttributes(attribute.String("username", username))

shortLink, err := c.client.Get(ctx, name)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Unable to get shortlink")
}

if !shortLink.IsOwnedBy(username) {
return nil, nil
return nil, model.NewNotAllowedError(username, "delete", shortLink.Name)
}

return shortLink, nil
Expand All @@ -67,21 +74,20 @@ func (c *ShortlinkClientAuth) Create(ct context.Context, username string, shortL
ctx, span := c.tracer.Start(ct, "ShortlinkClientAuth.Create")
defer span.End()

shortLink.Spec.Owner = username
span.SetAttributes(attribute.String("username", username))

shortLink.Spec.Owner = username
return c.client.Create(ctx, shortLink)
}

func (c *ShortlinkClientAuth) Update(ct context.Context, username string, shortLink *v1alpha1.ShortLink) error {
ctx, span := c.tracer.Start(ct, "ShortlinkClientAuth.Update")
defer span.End()

// When someone updates a shortlink and removes himself as the owner
// add him to the CoOwner
if shortLink.Spec.Owner != username {
if !slices.Contains(shortLink.Spec.CoOwners, username) {
shortLink.Spec.CoOwners = append(shortLink.Spec.CoOwners, username)
}
span.SetAttributes(attribute.String("username", username))

if !shortLink.IsOwnedBy(username) {
return model.NewNotAllowedError(username, "delete", shortLink.Name)
}

if err := c.client.Update(ctx, shortLink); err != nil {
Expand All @@ -96,8 +102,10 @@ func (c *ShortlinkClientAuth) Delete(ct context.Context, username string, shortL
ctx, span := c.tracer.Start(ct, "ShortlinkClientAuth.Update")
defer span.End()

span.SetAttributes(attribute.String("username", username))

if !shortLink.IsOwnedBy(username) {
return nil
return model.NewNotAllowedError(username, "delete", shortLink.Name)
}

return c.client.Delete(ctx, shortLink)
Expand Down
7 changes: 3 additions & 4 deletions pkg/client/shortlink_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (c *ShortlinkClient) ListNamespaced(ct context.Context, namespace string) (
}

func (c *ShortlinkClient) Update(ct context.Context, shortlink *v1alpha1.ShortLink) error {
ctx, span := c.tracer.Start(ct, "ShortlinkClient.Save", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
ctx, span := c.tracer.Start(ct, "ShortlinkClient.Update", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
defer span.End()

if err := c.client.Update(ctx, shortlink); err != nil {
Expand All @@ -116,7 +116,7 @@ func (c *ShortlinkClient) Update(ct context.Context, shortlink *v1alpha1.ShortLi
}

func (c *ShortlinkClient) UpdateStatus(ct context.Context, shortlink *v1alpha1.ShortLink) error {
ctx, span := c.tracer.Start(ct, "ShortlinkClient.SaveStatus", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
ctx, span := c.tracer.Start(ct, "ShortlinkClient.UpdateStatus", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
defer span.End()

err := c.client.Status().Update(ctx, shortlink)
Expand All @@ -128,7 +128,7 @@ func (c *ShortlinkClient) UpdateStatus(ct context.Context, shortlink *v1alpha1.S
}

func (c *ShortlinkClient) IncrementInvocationCount(ct context.Context, shortlink *v1alpha1.ShortLink) error {
ctx, span := c.tracer.Start(ct, "ShortlinkClient.SaveStatus", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
ctx, span := c.tracer.Start(ct, "ShortlinkClient.IncrementInvocationCount", trace.WithAttributes(attribute.String("shortlink", shortlink.ObjectMeta.Name), attribute.String("namespace", shortlink.ObjectMeta.Namespace)))
defer span.End()

shortlink.Status.Count = shortlink.Status.Count + 1
Expand All @@ -141,7 +141,6 @@ func (c *ShortlinkClient) IncrementInvocationCount(ct context.Context, shortlink
return nil
}

// Delete deletes a Shortlink object
func (c *ShortlinkClient) Delete(ct context.Context, shortlink *v1alpha1.ShortLink) error {
ctx, span := c.tracer.Start(ct, "ShortlinkClient.Delete", trace.WithAttributes(attribute.String("name", shortlink.Name), attribute.String("namespace", shortlink.Namespace)))
defer span.End()
Expand Down
34 changes: 19 additions & 15 deletions pkg/controller/handle_create_shortlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,32 @@ import (
// @Tags api/v1/
// @Router /api/v1/shortlink/{shortlink} [post]
// @Security bearerAuth
func (s *ShortlinkController) HandleCreateShortLink(c *gin.Context) {
shortlinkName := c.Param("shortlink")
contentType := c.Request.Header.Get("accept")
func (s *ShortlinkController) HandleCreateShortLink(ctx *gin.Context) {
shortlinkName := ctx.Param("shortlink")
contentType := ctx.Request.Header.Get("accept")

// Call the HTML method of the Context to render a template
ctx, span := s.tracer.Start(c.Request.Context(), "ShortlinkController.HandleGetShortLink", trace.WithAttributes(attribute.String("shortlink", shortlinkName), attribute.String("accepted_content_type", contentType)))
defer span.End()
span := trace.SpanFromContext(ctx)

bearerToken := c.Request.Header.Get("Authorization")
span.SetAttributes(
attribute.String("shortlink", shortlinkName),
attribute.String("content_type", contentType),
attribute.String("referrer", ctx.Request.Referer()),
)

bearerToken := ctx.Request.Header.Get("Authorization")
bearerToken = strings.TrimPrefix(bearerToken, "Bearer")
bearerToken = strings.TrimPrefix(bearerToken, "token")
if len(bearerToken) == 0 {
err := fmt.Errorf("no credentials provided")
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

githubUser, err := getGitHubUserInfo(ctx, bearerToken)
if err != nil {
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

Expand All @@ -68,29 +72,29 @@ func (s *ShortlinkController) HandleCreateShortLink(c *gin.Context) {
Spec: v1alpha1.ShortLinkSpec{},
}

jsonData, err := io.ReadAll(c.Request.Body)
jsonData, err := io.ReadAll(ctx.Request.Body)
if err != nil {
observability.RecordError(span, s.log, err, "Failed to read request-body")
ginReturnError(c, http.StatusInternalServerError, contentType, err.Error())
ginReturnError(ctx, http.StatusInternalServerError, contentType, err.Error())
return
}

if err := json.Unmarshal([]byte(jsonData), &shortlink.Spec); err != nil {
observability.RecordError(span, s.log, err, "Failed to read spec-json")
ginReturnError(c, http.StatusInternalServerError, contentType, err.Error())
ginReturnError(ctx, http.StatusInternalServerError, contentType, err.Error())
return
}

if err := s.authenticatedClient.Create(ctx, githubUser.Login, &shortlink); err != nil {
observability.RecordError(span, s.log, err, "Failed to create ShortLink")
ginReturnError(c, http.StatusInternalServerError, contentType, err.Error())
ginReturnError(ctx, http.StatusInternalServerError, contentType, err.Error())
return
}

if contentType == ContentTypeTextPlain {
c.Data(http.StatusOK, contentType, []byte(fmt.Sprintf("%s: %s\n", shortlink.Name, shortlink.Spec.Target)))
ctx.Data(http.StatusOK, contentType, []byte(fmt.Sprintf("%s: %s\n", shortlink.Name, shortlink.Spec.Target)))
} else if contentType == ContentTypeApplicationJSON {
c.JSON(http.StatusOK, ShortLink{
ctx.JSON(http.StatusOK, ShortLink{
Name: shortlink.Name,
Spec: shortlink.Spec,
Status: shortlink.Status,
Expand Down
28 changes: 16 additions & 12 deletions pkg/controller/handle_delete_shortlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,33 @@ import (
// @Tags api/v1/
// @Router /api/v1/shortlink/{shortlink} [delete]
// @Security bearerAuth
func (s *ShortlinkController) HandleDeleteShortLink(c *gin.Context) {
shortlinkName := c.Param("shortlink")
func (s *ShortlinkController) HandleDeleteShortLink(ctx *gin.Context) {
shortlinkName := ctx.Param("shortlink")

contentType := c.Request.Header.Get("accept")
contentType := ctx.Request.Header.Get("accept")

// Call the HTML method of the Context to render a template
ctx, span := s.tracer.Start(c.Request.Context(), "ShortlinkController.HandleGetShortLink", trace.WithAttributes(attribute.String("shortlink", shortlinkName), attribute.String("accepted_content_type", contentType)))
defer span.End()
span := trace.SpanFromContext(ctx)

bearerToken := c.Request.Header.Get("Authorization")
span.SetAttributes(
attribute.String("shortlink", shortlinkName),
attribute.String("content_type", contentType),
attribute.String("referrer", ctx.Request.Referer()),
)

bearerToken := ctx.Request.Header.Get("Authorization")
bearerToken = strings.TrimPrefix(bearerToken, "Bearer")
bearerToken = strings.TrimPrefix(bearerToken, "token")
if len(bearerToken) == 0 {
err := fmt.Errorf("no credentials provided")
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

githubUser, err := getGitHubUserInfo(ctx, bearerToken)
if err != nil {
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

Expand All @@ -62,13 +66,13 @@ func (s *ShortlinkController) HandleDeleteShortLink(c *gin.Context) {
statusCode = http.StatusNotFound
}

ginReturnError(c, statusCode, contentType, err.Error())
ginReturnError(ctx, statusCode, contentType, err.Error())
return
}

// When shortlink was not found
if shortlink == nil {
ginReturnError(c, http.StatusNotFound, contentType, "Shortlink not found")
ginReturnError(ctx, http.StatusNotFound, contentType, "Shortlink not found")
return
}

Expand All @@ -81,7 +85,7 @@ func (s *ShortlinkController) HandleDeleteShortLink(c *gin.Context) {

observability.RecordError(span, s.log, err, "Failed to delete ShortLink")

ginReturnError(c, statusCode, contentType, err.Error())
ginReturnError(ctx, statusCode, contentType, err.Error())
return
}
}
27 changes: 15 additions & 12 deletions pkg/controller/handle_get_shortlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,32 @@ import (
// @Tags api/v1/
// @Router /api/v1/shortlink/{shortlink} [get]
// @Security bearerAuth
func (s *ShortlinkController) HandleGetShortLink(c *gin.Context) {
shortlinkName := c.Param("shortlink")
func (s *ShortlinkController) HandleGetShortLink(ctx *gin.Context) {
shortlinkName := ctx.Param("shortlink")
contentType := ctx.Request.Header.Get("accept")

contentType := c.Request.Header.Get("accept")
span := trace.SpanFromContext(ctx)

// Call the HTML method of the Context to render a template
ctx, span := s.tracer.Start(c.Request.Context(), "ShortlinkController.HandleGetShortLink", trace.WithAttributes(attribute.String("shortlink", shortlinkName), attribute.String("accepted_content_type", contentType)))
defer span.End()
span.SetAttributes(
attribute.String("shortlink", shortlinkName),
attribute.String("content_type", contentType),
attribute.String("referrer", ctx.Request.Referer()),
)

bearerToken := c.Request.Header.Get("Authorization")
bearerToken := ctx.Request.Header.Get("Authorization")
bearerToken = strings.TrimPrefix(bearerToken, "Bearer")
bearerToken = strings.TrimPrefix(bearerToken, "token")
if len(bearerToken) == 0 {
err := fmt.Errorf("no credentials provided")
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

githubUser, err := getGitHubUserInfo(ctx, bearerToken)
if err != nil {
span.RecordError(err)
ginReturnError(c, http.StatusUnauthorized, contentType, err.Error())
ginReturnError(ctx, http.StatusUnauthorized, contentType, err.Error())
return
}

Expand All @@ -62,14 +65,14 @@ func (s *ShortlinkController) HandleGetShortLink(c *gin.Context) {
statusCode = http.StatusNotFound
}

ginReturnError(c, statusCode, contentType, err.Error())
ginReturnError(ctx, statusCode, contentType, err.Error())
return
}

if contentType == ContentTypeTextPlain {
c.Data(http.StatusOK, contentType, []byte(shortlink.Spec.Target))
ctx.Data(http.StatusOK, contentType, []byte(shortlink.Spec.Target))
} else if contentType == ContentTypeApplicationJSON {
c.JSON(http.StatusOK, ShortLink{
ctx.JSON(http.StatusOK, ShortLink{
Name: shortlink.Name,
Spec: shortlink.Spec,
Status: shortlink.Status,
Expand Down
Loading

0 comments on commit d863486

Please sign in to comment.