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 57594dc
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 165 deletions.
66 changes: 0 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
32 changes: 20 additions & 12 deletions pkg/controller/handle_list_shortlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,37 @@ import (
// @Tags api/v1/
// @Router /api/v1/shortlink/ [get]
// @Security bearerAuth
func (s *ShortlinkController) HandleListShortLink(c *gin.Context) {
contentType := c.Request.Header.Get("accept")
func (s *ShortlinkController) HandleListShortLink(ct *gin.Context) {
contentType := ct.Request.Header.Get("accept")

trace.SpanFromContext(c)
// Extract span from the request context
ctx := ct.Request.Context()
span := trace.SpanFromContext(ctx)

// Call the HTML method of the Context to render a template
ctx, span := s.tracer.Start(c.Request.Context(), "ShortlinkController.HandleListShortLink", trace.WithAttributes(attribute.String("accepted_content_type", contentType)))
defer span.End()
// Check if the span was sampled and is recording the data
if !span.IsRecording() {
ctx, span = s.tracer.Start(ctx, "ShortlinkController.HandleListShortLink")
}

span.SetAttributes(
attribute.String("content_type", contentType),
attribute.String("referrer", ct.Request.Referer()),
)

bearerToken := c.Request.Header.Get("Authorization")
bearerToken := ct.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(ct, 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(ct, http.StatusUnauthorized, contentType, err.Error())
return
}

Expand All @@ -61,7 +69,7 @@ func (s *ShortlinkController) HandleListShortLink(c *gin.Context) {
statusCode = http.StatusNotFound
}

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

Expand All @@ -76,12 +84,12 @@ func (s *ShortlinkController) HandleListShortLink(c *gin.Context) {
}

if contentType == ContentTypeApplicationJSON {
c.JSON(http.StatusOK, targetList)
ct.JSON(http.StatusOK, targetList)
} else if contentType == ContentTypeTextPlain {
shortLinks := ""
for _, shortlink := range targetList {
shortLinks += fmt.Sprintf("%s: %s\n", shortlink.Name, shortlink.Spec.Target)
}
c.Data(http.StatusOK, contentType, []byte(shortLinks))
ct.Data(http.StatusOK, contentType, []byte(shortLinks))
}
}
Loading

0 comments on commit 57594dc

Please sign in to comment.