diff --git a/go.mod b/go.mod index 55f4117f8..78874c04e 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/ory/herodot v0.9.13 github.com/ory/jsonschema/v3 v3.0.7 github.com/ory/keto/proto v0.10.0-alpha.0 - github.com/ory/x v0.0.550 + github.com/ory/x v0.0.552 github.com/pelletier/go-toml v1.9.5 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index efb68d87a..1c089a47a 100644 --- a/go.sum +++ b/go.sum @@ -643,8 +643,8 @@ github.com/ory/herodot v0.9.13/go.mod h1:IWDs9kSvFQqw/cQ8zi5ksyYvITiUU4dI7glUrhZ github.com/ory/jsonschema/v3 v3.0.7 h1:GQ9qfZDiJqs4l2d3p56dozCChvejQFZyLKGHYzDzOSo= github.com/ory/jsonschema/v3 v3.0.7/go.mod h1:g8c8YOtN4TrR2wYeMdT02GDmzJDI0fEW2nI26BECafY= github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= -github.com/ory/x v0.0.550 h1:bcaOdUW/jHByoT8U6cfraBpRCtNtUB8lNBD97LTrB+Y= -github.com/ory/x v0.0.550/go.mod h1:oRVemI3SQQOLvOCJWIRinHQKlgmay/NbwSyRUIsS/Yk= +github.com/ory/x v0.0.552 h1:vgDw7FFQ7Ama3iyDLbjElY2Um1/ub82iIubK0pUj81M= +github.com/ory/x v0.0.552/go.mod h1:oRVemI3SQQOLvOCJWIRinHQKlgmay/NbwSyRUIsS/Yk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= diff --git a/internal/check/engine.go b/internal/check/engine.go index f07fdfa19..0cd213723 100644 --- a/internal/check/engine.go +++ b/internal/check/engine.go @@ -9,6 +9,9 @@ import ( "github.com/ory/herodot" "github.com/ory/x/otelx" "github.com/pkg/errors" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/keto/x/events" "github.com/ory/keto/internal/check/checkgroup" "github.com/ory/keto/internal/driver/config" @@ -17,7 +20,6 @@ import ( "github.com/ory/keto/internal/persistence" "github.com/ory/keto/internal/relationtuple" "github.com/ory/keto/internal/x" - "github.com/ory/keto/internal/x/events" "github.com/ory/keto/internal/x/graph" "github.com/ory/keto/ketoapi" ) @@ -74,8 +76,6 @@ func (e *Engine) CheckRelationTuple(ctx context.Context, r *relationTuple, restD ctx, span := e.d.Tracer(ctx).Tracer().Start(ctx, "Engine.CheckRelationTuple") defer otelx.End(span, &res.Err) - events.Add(ctx, e.d, events.PermissionsChecked) - // global max-depth takes precedence when it is the lesser or if the request // max-depth is less than or equal to 0 if globalMaxDepth := e.d.Config(ctx).MaxReadDepth(); restDepth <= 0 || globalMaxDepth < restDepth { @@ -86,6 +86,7 @@ func (e *Engine) CheckRelationTuple(ctx context.Context, r *relationTuple, restD go e.checkIsAllowed(ctx, r, restDepth, false)(ctx, resultCh) select { case result := <-resultCh: + trace.SpanFromContext(ctx).AddEvent(events.NewPermissionsChecked(ctx)) return result case <-ctx.Done(): return checkgroup.Result{Err: errors.WithStack(ctx.Err())} diff --git a/internal/driver/daemon.go b/internal/driver/daemon.go index 9a3fa58e0..ac14384b7 100644 --- a/internal/driver/daemon.go +++ b/internal/driver/daemon.go @@ -14,6 +14,8 @@ import ( "syscall" "time" + "github.com/ory/x/otelx/semconv" + grpcRecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -328,6 +330,7 @@ func (r *RegistryDefault) ReadRouter(ctx context.Context) http.Handler { for _, f := range r.defaultHttpMiddlewares { n.UseFunc(f) } + n.UseFunc(semconv.Middleware) n.Use(reqlog.NewMiddlewareFromLogger(r.l, "read#Ory Keto").ExcludePaths(healthx.AliveCheckPath, healthx.ReadyCheckPath)) br := &x.ReadRouter{Router: httprouter.New()} @@ -364,6 +367,7 @@ func (r *RegistryDefault) WriteRouter(ctx context.Context) http.Handler { for _, f := range r.defaultHttpMiddlewares { n.UseFunc(f) } + n.UseFunc(semconv.Middleware) n.Use(reqlog.NewMiddlewareFromLogger(r.l, "write#Ory Keto").ExcludePaths(healthx.AliveCheckPath, healthx.ReadyCheckPath)) pr := &x.WriteRouter{Router: httprouter.New()} @@ -400,6 +404,7 @@ func (r *RegistryDefault) OPLSyntaxRouter(ctx context.Context) http.Handler { for _, f := range r.defaultHttpMiddlewares { n.UseFunc(f) } + n.UseFunc(semconv.Middleware) n.Use(reqlog.NewMiddlewareFromLogger(r.l, "syntax#Ory Keto").ExcludePaths(healthx.AliveCheckPath, healthx.ReadyCheckPath)) pr := &x.OPLSyntaxRouter{Router: httprouter.New()} diff --git a/internal/expand/engine.go b/internal/expand/engine.go index 3fe3d323c..b38e0eba3 100644 --- a/internal/expand/engine.go +++ b/internal/expand/engine.go @@ -7,11 +7,13 @@ import ( "context" "github.com/ory/x/otelx" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/keto/x/events" "github.com/ory/keto/internal/driver/config" "github.com/ory/keto/internal/relationtuple" "github.com/ory/keto/internal/x" - "github.com/ory/keto/internal/x/events" "github.com/ory/keto/internal/x/graph" "github.com/ory/keto/ketoapi" ) @@ -41,9 +43,11 @@ func NewEngine(d EngineDependencies) *Engine { func (e *Engine) BuildTree(ctx context.Context, subject relationtuple.Subject, restDepth int) (t *relationtuple.Tree, err error) { ctx, span := e.d.Tracer(ctx).Tracer().Start(ctx, "Engine.BuildTree") defer otelx.End(span, &err) - events.Add(ctx, e.d, events.PermissionsExpanded) t, err = e.buildTreeRecursive(ctx, subject, restDepth) + if err != nil { + trace.SpanFromContext(ctx).AddEvent(events.NewPermissionsExpanded(ctx)) + } return } diff --git a/internal/relationtuple/transact_server.go b/internal/relationtuple/transact_server.go index 9369b81bd..e467fdd4d 100644 --- a/internal/relationtuple/transact_server.go +++ b/internal/relationtuple/transact_server.go @@ -8,11 +8,14 @@ import ( "encoding/json" "net/http" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/keto/x/events" + "github.com/julienschmidt/httprouter" "github.com/ory/herodot" "github.com/pkg/errors" - "github.com/ory/keto/internal/x/events" "github.com/ory/keto/internal/x/validate" "github.com/ory/keto/ketoapi" rts "github.com/ory/keto/proto/ory/keto/relation_tuples/v1alpha2" @@ -34,8 +37,6 @@ func protoTuplesWithAction(deltas []*rts.RelationTupleDelta, action rts.Relation } func (h *handler) TransactRelationTuples(ctx context.Context, req *rts.TransactRelationTuplesRequest) (*rts.TransactRelationTuplesResponse, error) { - events.Add(ctx, h.d, events.RelationtuplesChanged) - insertTuples, err := protoTuplesWithAction(req.RelationTupleDeltas, rts.RelationTupleDelta_ACTION_INSERT) if err != nil { return nil, err @@ -56,6 +57,8 @@ func (h *handler) TransactRelationTuples(ctx context.Context, req *rts.TransactR return nil, err } + trace.SpanFromContext(ctx).AddEvent(events.NewRelationtuplesChanged(ctx)) + snaptokens := make([]string, len(insertTuples)) for i := range insertTuples { snaptokens[i] = "not yet implemented" @@ -66,8 +69,6 @@ func (h *handler) TransactRelationTuples(ctx context.Context, req *rts.TransactR } func (h *handler) DeleteRelationTuples(ctx context.Context, req *rts.DeleteRelationTuplesRequest) (*rts.DeleteRelationTuplesResponse, error) { - events.Add(ctx, h.d, events.RelationtuplesDeleted) - var q ketoapi.RelationQuery switch { @@ -87,6 +88,8 @@ func (h *handler) DeleteRelationTuples(ctx context.Context, req *rts.DeleteRelat return nil, errors.WithStack(herodot.ErrInternalServerError.WithError(err.Error())) } + trace.SpanFromContext(ctx).AddEvent(events.NewRelationtuplesDeleted(ctx)) + return &rts.DeleteRelationTuplesResponse{}, nil } @@ -128,8 +131,6 @@ type createRelationshipBody struct { func (h *handler) createRelation(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { ctx := r.Context() - events.Add(ctx, h.d, events.RelationtuplesCreated) - var rt ketoapi.RelationTuple if err := json.NewDecoder(r.Body).Decode(&rt); err != nil { h.d.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithError(err.Error()))) @@ -155,6 +156,8 @@ func (h *handler) createRelation(w http.ResponseWriter, r *http.Request, _ httpr return } + trace.SpanFromContext(ctx).AddEvent(events.NewRelationtuplesCreated(ctx)) + h.d.Writer().WriteCreated(w, r, ReadRouteBase+"?"+rt.ToURLQuery().Encode(), &rt, @@ -182,8 +185,6 @@ func (h *handler) createRelation(w http.ResponseWriter, r *http.Request, _ httpr func (h *handler) deleteRelations(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { ctx := r.Context() - events.Add(ctx, h.d, events.RelationtuplesDeleted) - if err := validate.All(r, validate.NoExtraQueryParams(ketoapi.RelationQueryKeys...), validate.QueryParamsContainsOneOf(ketoapi.NamespaceKey), @@ -218,6 +219,8 @@ func (h *handler) deleteRelations(w http.ResponseWriter, r *http.Request, _ http return } + trace.SpanFromContext(ctx).AddEvent(events.NewRelationtuplesDeleted(ctx)) + w.WriteHeader(http.StatusNoContent) } @@ -252,8 +255,6 @@ func internalTuplesWithAction(deltas []*ketoapi.PatchDelta, action ketoapi.Patch func (h *handler) patchRelationTuples(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { ctx := r.Context() - events.Add(ctx, h.d, events.RelationtuplesChanged) - var deltas []*ketoapi.PatchDelta if err := json.NewDecoder(r.Body).Decode(&deltas); err != nil { h.d.Writer().WriteError(w, r, herodot.ErrBadRequest.WithError(err.Error())) @@ -296,5 +297,7 @@ func (h *handler) patchRelationTuples(w http.ResponseWriter, r *http.Request, _ return } + trace.SpanFromContext(ctx).AddEvent(events.NewRelationtuplesChanged(ctx)) + w.WriteHeader(http.StatusNoContent) } diff --git a/internal/x/events/events.go b/internal/x/events/events.go deleted file mode 100644 index a063d78c4..000000000 --- a/internal/x/events/events.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package events - -import ( - "context" - - "github.com/ory/x/otelx/semconv" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - - "github.com/ory/keto/internal/x" -) - -type Event string - -const ( - RelationtuplesCreated Event = "RelationtuplesCreated" - RelationtuplesDeleted Event = "RelationtuplesDeleted" - RelationtuplesChanged Event = "RelationtuplesChanged" - - PermissionsExpanded Event = "PermissionsExpanded" - PermissionsChecked Event = "PermissionsChecked" -) - -// Add adds an event to the current span in the context. -func Add(ctx context.Context, p x.NetworkIDProvider, event Event) { - trace.SpanFromContext(ctx).AddEvent( - string(event), - trace.WithAttributes( - attribute.String(semconv.AttrNID, p.NetworkID(ctx).String()), - ), - ) -} diff --git a/x/events/events.go b/x/events/events.go new file mode 100644 index 000000000..7c532b2c5 --- /dev/null +++ b/x/events/events.go @@ -0,0 +1,55 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package events + +import ( + "context" + + "github.com/ory/x/otelx/semconv" + "go.opentelemetry.io/otel/trace" +) + +const ( + RelationtuplesCreated semconv.Event = "RelationtuplesCreated" + RelationtuplesDeleted semconv.Event = "RelationtuplesDeleted" + RelationtuplesChanged semconv.Event = "RelationtuplesChanged" + + PermissionsExpanded semconv.Event = "PermissionsExpanded" + PermissionsChecked semconv.Event = "PermissionsChecked" +) + +func NewRelationtuplesCreated(ctx context.Context) (string, trace.EventOption) { + return RelationtuplesCreated.String(), + trace.WithAttributes( + semconv.AttributesFromContext(ctx)..., + ) +} + +func NewRelationtuplesDeleted(ctx context.Context) (string, trace.EventOption) { + return RelationtuplesDeleted.String(), + trace.WithAttributes( + semconv.AttributesFromContext(ctx)..., + ) +} + +func NewRelationtuplesChanged(ctx context.Context) (string, trace.EventOption) { + return RelationtuplesChanged.String(), + trace.WithAttributes( + semconv.AttributesFromContext(ctx)..., + ) +} + +func NewPermissionsExpanded(ctx context.Context) (string, trace.EventOption) { + return PermissionsExpanded.String(), + trace.WithAttributes( + semconv.AttributesFromContext(ctx)..., + ) +} + +func NewPermissionsChecked(ctx context.Context) (string, trace.EventOption) { + return PermissionsChecked.String(), + trace.WithAttributes( + semconv.AttributesFromContext(ctx)..., + ) +}