diff --git a/api/tracing/tracing.go b/api/tracing/tracing.go index d2cc40bf..ef2bbefa 100644 --- a/api/tracing/tracing.go +++ b/api/tracing/tracing.go @@ -1,58 +1,58 @@ package tracing -import ( - "context" - "fmt" - - texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" - gcppropagator "github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator" - "go.opentelemetry.io/contrib/detectors/gcp" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/propagation" - "go.opentelemetry.io/otel/sdk/resource" - sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.21.0" -) - -type Configuration struct { - Enabled bool - ApplicationName string - ProjectID string -} - -func Init(configuration Configuration) error { - if !configuration.Enabled { - return nil - } - - exporter, err := texporter.New(texporter.WithProjectID(configuration.ProjectID)) - if err != nil { - return fmt.Errorf("texporter.New error: %v", err) - } - - res, err := resource.New(context.Background(), - resource.WithDetectors(gcp.NewDetector()), - resource.WithTelemetrySDK(), - resource.WithAttributes( - semconv.ServiceNameKey.String(configuration.ApplicationName), - ), - ) - if err != nil { - return fmt.Errorf("resource.New error: %w", err) - } - - tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exporter), - sdktrace.WithResource(res), - ) - - otel.SetTextMapPropagator( - propagation.NewCompositeTextMapPropagator( - gcppropagator.CloudTraceFormatPropagator{}, - propagation.TraceContext{}, - propagation.Baggage{}, - ), - ) - otel.SetTracerProvider(tp) - return nil -} +// import ( +// "context" +// "fmt" + +// texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" +// gcppropagator "github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator" +// "go.opentelemetry.io/contrib/detectors/gcp" +// "go.opentelemetry.io/otel" +// "go.opentelemetry.io/otel/propagation" +// "go.opentelemetry.io/otel/sdk/resource" +// sdktrace "go.opentelemetry.io/otel/sdk/trace" +// semconv "go.opentelemetry.io/otel/semconv/v1.21.0" +// ) + +// type Configuration struct { +// Enabled bool +// ApplicationName string +// ProjectID string +// } + +// func Init(configuration Configuration) error { +// if !configuration.Enabled { +// return nil +// } + +// exporter, err := texporter.New(texporter.WithProjectID(configuration.ProjectID)) +// if err != nil { +// return fmt.Errorf("texporter.New error: %v", err) +// } + +// res, err := resource.New(context.Background(), +// resource.WithDetectors(gcp.NewDetector()), +// resource.WithTelemetrySDK(), +// resource.WithAttributes( +// semconv.ServiceNameKey.String(configuration.ApplicationName), +// ), +// ) +// if err != nil { +// return fmt.Errorf("resource.New error: %w", err) +// } + +// tp := sdktrace.NewTracerProvider( +// sdktrace.WithBatcher(exporter), +// sdktrace.WithResource(res), +// ) + +// otel.SetTextMapPropagator( +// propagation.NewCompositeTextMapPropagator( +// gcppropagator.CloudTraceFormatPropagator{}, +// propagation.TraceContext{}, +// propagation.Baggage{}, +// ), +// ) +// otel.SetTracerProvider(tp) +// return nil +// } diff --git a/go.mod b/go.mod index c2f720e1..a5c8446b 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/getsentry/sentry-go v0.25.0 github.com/gin-contrib/cors v1.4.0 github.com/gin-contrib/size v0.0.0-20231211133737-500859255df8 + github.com/gin-contrib/timeout v0.0.6 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/validator/v10 v10.15.3 github.com/gofrs/uuid v4.4.0+incompatible @@ -36,6 +37,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 go.opentelemetry.io/otel v1.21.0 go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/trace v1.21.0 golang.org/x/net v0.18.0 google.golang.org/api v0.138.0 ) @@ -84,7 +86,6 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-contrib/timeout v0.0.6 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -133,7 +134,6 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect golang.org/x/arch v0.5.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/mod v0.12.0 // indirect diff --git a/go.sum b/go.sum index c7d5dcdd..8b9e2988 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,6 @@ github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= @@ -97,7 +95,6 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= @@ -175,8 +172,6 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo= github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= @@ -245,8 +240,6 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/pgx/v5 v5.5.1 h1:5I9etrGkLrN+2XPCsi6XLlV5DITbSL/xBZdmAxFcXPI= github.com/jackc/pgx/v5 v5.5.1/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= @@ -262,8 +255,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= @@ -308,8 +299,6 @@ github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -349,7 +338,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= @@ -392,8 +380,6 @@ go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8 go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -455,7 +441,6 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go index 0da766b0..7e44290e 100644 --- a/main.go +++ b/main.go @@ -15,15 +15,16 @@ import ( "time" "github.com/segmentio/analytics-go/v3" + "go.opentelemetry.io/otel/trace" "github.com/checkmarble/marble-backend/api" - "github.com/checkmarble/marble-backend/api/tracing" "github.com/checkmarble/marble-backend/infra" "github.com/checkmarble/marble-backend/jobs" "github.com/checkmarble/marble-backend/models" "github.com/checkmarble/marble-backend/repositories" "github.com/checkmarble/marble-backend/repositories/firebase" "github.com/checkmarble/marble-backend/repositories/postgres" + "github.com/checkmarble/marble-backend/tracing" "github.com/checkmarble/marble-backend/usecases" "github.com/checkmarble/marble-backend/usecases/datamodel" "github.com/checkmarble/marble-backend/usecases/token" @@ -31,14 +32,15 @@ import ( ) type dependencies struct { - Authentication *api.Authentication - TokenHandler *api.TokenHandler - DataModelHandler *api.DataModelHandler - SegmentClient analytics.Client + Authentication *api.Authentication + TokenHandler *api.TokenHandler + DataModelHandler *api.DataModelHandler + SegmentClient analytics.Client + OpenTelemetryTracer trace.Tracer } func initDependencies(conf AppConfiguration, signingKey *rsa.PrivateKey) (dependencies, error) { - err := tracing.Init(tracing.Configuration{ + tracer, err := tracing.Init(tracing.Configuration{ Enabled: conf.env != "development", ApplicationName: "marble-backend", ProjectID: conf.gcpProject, @@ -66,10 +68,11 @@ func initDependencies(conf AppConfiguration, signingKey *rsa.PrivateKey) (depend segmentClient := analytics.New(conf.config.SegmentWriteKey) return dependencies{ - Authentication: api.NewAuthentication(tokenValidator), - TokenHandler: api.NewTokenHandler(tokenGenerator), - DataModelHandler: api.NewDataModelHandler(dataModelUseCase), - SegmentClient: segmentClient, + Authentication: api.NewAuthentication(tokenValidator), + TokenHandler: api.NewTokenHandler(tokenGenerator), + DataModelHandler: api.NewDataModelHandler(dataModelUseCase), + SegmentClient: segmentClient, + OpenTelemetryTracer: tracer, }, nil } diff --git a/router.go b/router.go index 7e40e9db..b1735110 100644 --- a/router.go +++ b/router.go @@ -78,6 +78,7 @@ func initRouter(ctx context.Context, conf AppConfiguration, deps dependencies) * r.Use(otelgin.Middleware("marble-backend")) r.Use(utils.StoreLoggerInContextMiddleware(logger)) r.Use(utils.StoreSegmentClientInContextMiddleware(deps.SegmentClient)) + r.Use(utils.StoreOpenTelemetryTracerInContextMiddleware(deps.OpenTelemetryTracer)) r.GET("/liveness", api.HandleLivenessProbe) r.POST("/crash", api.HandleCrash) diff --git a/tracing/tracing.go b/tracing/tracing.go index d2cc40bf..06c1c18b 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -6,12 +6,15 @@ import ( texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" gcppropagator "github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator" + "go.opentelemetry.io/contrib/detectors/gcp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) type Configuration struct { @@ -20,14 +23,14 @@ type Configuration struct { ProjectID string } -func Init(configuration Configuration) error { +func Init(configuration Configuration) (trace.Tracer, error) { if !configuration.Enabled { - return nil + return &noop.Tracer{}, nil } exporter, err := texporter.New(texporter.WithProjectID(configuration.ProjectID)) if err != nil { - return fmt.Errorf("texporter.New error: %v", err) + return nil, fmt.Errorf("texporter.New error: %v", err) } res, err := resource.New(context.Background(), @@ -38,7 +41,7 @@ func Init(configuration Configuration) error { ), ) if err != nil { - return fmt.Errorf("resource.New error: %w", err) + return nil, fmt.Errorf("resource.New error: %w", err) } tp := sdktrace.NewTracerProvider( @@ -54,5 +57,8 @@ func Init(configuration Configuration) error { ), ) otel.SetTracerProvider(tp) - return nil + + tracer := tp.Tracer(configuration.ApplicationName) + return tracer, nil + } diff --git a/usecases/decision_usecase.go b/usecases/decision_usecase.go index e86fb593..94ebe009 100644 --- a/usecases/decision_usecase.go +++ b/usecases/decision_usecase.go @@ -148,6 +148,10 @@ func (usecase *DecisionUsecase) validateTriggerObjects(ctx context.Context, filt func (usecase *DecisionUsecase) CreateDecision(ctx context.Context, input models.CreateDecisionInput, logger *slog.Logger) (models.Decision, error) { + tracer := utils.OpenTelemetryTracerFromContext(ctx) + ctx, span := tracer.Start(ctx, "DecisionUsecase.CreateDecision") + defer span.End() + if err := usecase.enforceSecurity.CreateDecision(input.OrganizationId); err != nil { return models.Decision{}, err } diff --git a/usecases/evaluate_scenario/evaluate_scenario.go b/usecases/evaluate_scenario/evaluate_scenario.go index 4cb20363..387622e1 100644 --- a/usecases/evaluate_scenario/evaluate_scenario.go +++ b/usecases/evaluate_scenario/evaluate_scenario.go @@ -8,11 +8,15 @@ import ( "time" "github.com/cockroachdb/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/checkmarble/marble-backend/models" + "github.com/checkmarble/marble-backend/models/ast" "github.com/checkmarble/marble-backend/repositories" "github.com/checkmarble/marble-backend/usecases/ast_eval" "github.com/checkmarble/marble-backend/usecases/transaction" + "github.com/checkmarble/marble-backend/utils" ) type ScenarioEvaluationParameters struct { @@ -50,6 +54,10 @@ func EvalScenario(ctx context.Context, params ScenarioEvaluationParameters, repo logger.InfoContext(ctx, "Evaluating scenario", "scenarioId", params.Scenario.Id) + tracer := utils.OpenTelemetryTracerFromContext(ctx) + ctx, span := tracer.Start(ctx, "evaluate_scenario.EvalScenario") + defer span.End() + // If the scenario has no live version, don't try to Eval() it, return early if params.Scenario.LiveVersionID == nil { return models.ScenarioExecution{}, errors.Wrap(models.ScenarioHasNoLiveVersionError, "scenario has no live version in EvalScenario") @@ -79,8 +87,9 @@ func EvalScenario(ctx context.Context, params ScenarioEvaluationParameters, repo } // Evaluate the trigger - triggerPassed, err := repositories.EvaluateRuleAstExpression.EvaluateRuleAstExpression( + triggerPassed, err := evalScenarioTrigger( ctx, + repositories, publishedVersion.Body.TriggerConditionAstExpression, dataAccessor.organizationId, dataAccessor.Payload, @@ -142,6 +151,10 @@ func EvalScenario(ctx context.Context, params ScenarioEvaluationParameters, repo func evalScenarioRule(ctx context.Context, repositories ScenarioEvaluationRepositories, rule models.Rule, dataAccessor DataAccessor, dataModel models.DataModel, logger *slog.Logger) (int, models.RuleExecution, error) { // Evaluate single rule + tracer := utils.OpenTelemetryTracerFromContext(ctx) + ctx, span := tracer.Start(ctx, "evaluate_scenario.evalScenarioRule", trace.WithAttributes(attribute.String("rule_id", rule.Id))) + defer span.End() + ruleReturnValue, err := repositories.EvaluateRuleAstExpression.EvaluateRuleAstExpression( ctx, *rule.FormulaAstExpression, @@ -185,3 +198,18 @@ func evalScenarioRule(ctx context.Context, repositories ScenarioEvaluationReposi } return score, ruleExecution, nil } + +func evalScenarioTrigger(ctx context.Context, repositories ScenarioEvaluationRepositories, ruleAstExpression ast.Node, organizationId string, payload models.PayloadReader, dataModel models.DataModel) (bool, error) { + + tracer := utils.OpenTelemetryTracerFromContext(ctx) + ctx, span := tracer.Start(ctx, "evaluate_scenario.evalScenarioTrigger") + defer span.End() + + return repositories.EvaluateRuleAstExpression.EvaluateRuleAstExpression( + ctx, + ruleAstExpression, + organizationId, + payload, + dataModel, + ) +} diff --git a/utils/context.go b/utils/context_credentials.go similarity index 59% rename from utils/context.go rename to utils/context_credentials.go index 88103016..1579a225 100644 --- a/utils/context.go +++ b/utils/context_credentials.go @@ -5,21 +5,9 @@ import ( "fmt" "net/http" - "github.com/gin-gonic/gin" - "github.com/gofrs/uuid" - "github.com/segmentio/analytics-go/v3" - "github.com/checkmarble/marble-backend/models" ) -type ContextKey int - -const ( - ContextKeyCredentials ContextKey = iota - ContextKeyLogger - ContextKeySegmentClient -) - func CredentialsFromCtx(ctx context.Context) (models.Credentials, bool) { creds, ok := ctx.Value(ContextKeyCredentials).(models.Credentials) return creds, ok @@ -64,28 +52,3 @@ func OrganizationIdFromRequest(request *http.Request) (organizationId string, er func OrgIDFromCtx(ctx context.Context, request *http.Request) (organizationId string, err error) { return OrganizationIdFromRequest(request) } - -func ValidateUuid(uuidParam string) error { - _, err := uuid.FromString(uuidParam) - if err != nil { - err = fmt.Errorf("'%s' is not a valid UUID: %w", uuidParam, models.BadParameterError) - } - return err -} - -func SegmentClientFromContext(ctx context.Context) (analytics.Client, bool) { - client, found := ctx.Value(ContextKeySegmentClient).(analytics.Client) - return client, found -} - -func StoreSegmentClientInContext(ctx context.Context, client analytics.Client) context.Context { - return context.WithValue(ctx, ContextKeySegmentClient, client) -} - -func StoreSegmentClientInContextMiddleware(client analytics.Client) gin.HandlerFunc { - return func(c *gin.Context) { - ctxWithSegment := StoreSegmentClientInContext(c.Request.Context(), client) - c.Request = c.Request.WithContext(ctxWithSegment) - c.Next() - } -} diff --git a/utils/context_keys.go b/utils/context_keys.go new file mode 100644 index 00000000..b3102459 --- /dev/null +++ b/utils/context_keys.go @@ -0,0 +1,10 @@ +package utils + +type ContextKey int + +const ( + ContextKeyCredentials ContextKey = iota + ContextKeyLogger + ContextKeySegmentClient + ContextKeyOpenTelemetryTracer +) diff --git a/utils/context_segment.go b/utils/context_segment.go new file mode 100644 index 00000000..31f2d2f4 --- /dev/null +++ b/utils/context_segment.go @@ -0,0 +1,25 @@ +package utils + +import ( + "context" + + "github.com/gin-gonic/gin" + "github.com/segmentio/analytics-go/v3" +) + +func SegmentClientFromContext(ctx context.Context) (analytics.Client, bool) { + client, found := ctx.Value(ContextKeySegmentClient).(analytics.Client) + return client, found +} + +func StoreSegmentClientInContext(ctx context.Context, client analytics.Client) context.Context { + return context.WithValue(ctx, ContextKeySegmentClient, client) +} + +func StoreSegmentClientInContextMiddleware(client analytics.Client) gin.HandlerFunc { + return func(c *gin.Context) { + ctxWithSegment := StoreSegmentClientInContext(c.Request.Context(), client) + c.Request = c.Request.WithContext(ctxWithSegment) + c.Next() + } +} diff --git a/utils/context_tracing.go b/utils/context_tracing.go new file mode 100644 index 00000000..52af196d --- /dev/null +++ b/utils/context_tracing.go @@ -0,0 +1,32 @@ +package utils + +import ( + "context" + + "github.com/gin-gonic/gin" + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" +) + +func OpenTelemetryTracerFromContext(ctx context.Context) trace.Tracer { + tracer, found := ctx.Value(ContextKeyOpenTelemetryTracer).(trace.Tracer) + + if !found { + LoggerFromContext(ctx).DebugContext(ctx, "OpenTelemetryTracer not found in context, using NoopTracer: traces will be dismissed") + return &noop.Tracer{} + } + + return tracer +} + +func StoreOpenTelemetryTracerInContext(ctx context.Context, tracer trace.Tracer) context.Context { + return context.WithValue(ctx, ContextKeyOpenTelemetryTracer, tracer) +} + +func StoreOpenTelemetryTracerInContextMiddleware(tracer trace.Tracer) gin.HandlerFunc { + return func(c *gin.Context) { + ctxWithTracer := StoreOpenTelemetryTracerInContext(c.Request.Context(), tracer) + c.Request = c.Request.WithContext(ctxWithTracer) + c.Next() + } +} diff --git a/utils/uuid.go b/utils/uuid.go new file mode 100644 index 00000000..fe40b596 --- /dev/null +++ b/utils/uuid.go @@ -0,0 +1,16 @@ +package utils + +import ( + "fmt" + + "github.com/checkmarble/marble-backend/models" + "github.com/gofrs/uuid" +) + +func ValidateUuid(uuidParam string) error { + _, err := uuid.FromString(uuidParam) + if err != nil { + err = fmt.Errorf("'%s' is not a valid UUID: %w", uuidParam, models.BadParameterError) + } + return err +}