From b7ebf40e081ccf027a6dc7666f275795afb1a8e5 Mon Sep 17 00:00:00 2001 From: ryanfkeepers Date: Mon, 20 Mar 2023 12:23:34 -0600 Subject: [PATCH] Metrics POC: github.com/NdoleStudio/go-otelroundtripper Proof of concept implementation for collecting metrics with go-otelroundtripper. Pros: - hooks into http clients for centralized tracing. - otel compliance for easy consumption - in-memory - Could be stored in streamstore snapshot. Cons: - not human consumable, requries post-processing. - without storage, consumption/usage is difficult. --- src/cli/cli.go | 29 +++++++++++++++++++++++++ src/go.mod | 9 ++++++-- src/go.sum | 18 +++++++++++---- src/internal/connector/graph/service.go | 12 ++++++++++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/cli/cli.go b/src/cli/cli.go index 8b8cf3b57..34eb876f4 100644 --- a/src/cli/cli.go +++ b/src/cli/cli.go @@ -2,12 +2,17 @@ package cli import ( "context" + "encoding/json" + "fmt" "os" "regexp" "strings" "time" "github.com/spf13/cobra" + "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" + "go.opentelemetry.io/otel/metric/global" + "go.opentelemetry.io/otel/sdk/metric" "golang.org/x/exp/slices" "github.com/alcionai/corso/src/cli/backup" @@ -152,6 +157,29 @@ func Handle() { ctx, cancel := context.WithDeadline(context.Background(), tenDays) defer cancel() + // ---------------------------------------------------------- + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + + exporter, err := stdoutmetric.New(stdoutmetric.WithEncoder(enc)) + if err != nil { + fmt.Printf("creating stdoutmetric exporter: %v\n", err) + } else { + // Register the exporter with an SDK via a periodic reader. + sdk := metric.NewMeterProvider(metric.WithReader(metric.NewPeriodicReader(exporter))) + + global.SetMeterProvider(sdk) + + defer func() { + if err := sdk.Shutdown(ctx); err != nil { + fmt.Printf("stopping sdk: %v\n", err) + } + }() + } + + // ---------------------------------------------------------- + ctx = config.Seed(ctx) ctx = print.SetRootCmd(ctx, corsoCmd) observe.SeedWriter(ctx, print.StderrWriter(ctx), observe.PreloadFlags()) @@ -159,6 +187,7 @@ func Handle() { BuildCommandTree(corsoCmd) loglevel, logfile := logger.PreloadLoggingFlags() + ctx, log := logger.Seed(ctx, loglevel, logfile) defer func() { diff --git a/src/go.mod b/src/go.mod index de9ef11d9..1c7cae81a 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 + github.com/NdoleStudio/go-otelroundtripper v0.0.6 github.com/alcionai/clues v0.0.0-20230314154528-c469e1adafb6 github.com/aws/aws-sdk-go v1.44.220 github.com/aws/aws-xray-sdk-go v1.8.1 @@ -28,6 +29,9 @@ require ( github.com/tidwall/pretty v1.2.1 github.com/tomlazar/table v0.1.2 github.com/vbauerster/mpb/v8 v8.1.6 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.34.0 + go.opentelemetry.io/otel/metric v0.34.0 + go.opentelemetry.io/otel/sdk/metric v0.34.0 go.uber.org/zap v1.24.0 golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/tools v0.7.0 @@ -50,6 +54,7 @@ require ( github.com/subosito/gotenv v1.4.2 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.11.2 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) @@ -107,8 +112,8 @@ require ( github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/zeebo/blake3 v0.2.3 // indirect - go.opentelemetry.io/otel v1.11.2 // indirect - go.opentelemetry.io/otel/trace v1.11.2 // indirect + go.opentelemetry.io/otel v1.14.0 + go.opentelemetry.io/otel/trace v1.14.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.5.0 // indirect diff --git a/src/go.sum b/src/go.sum index 276367cd7..334c2007b 100644 --- a/src/go.sum +++ b/src/go.sum @@ -48,6 +48,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw= +github.com/NdoleStudio/go-otelroundtripper v0.0.6 h1:y9nUERqMQI34tfLE59sH/dEAEcEgjKu35fr9Wnbp3uY= +github.com/NdoleStudio/go-otelroundtripper v0.0.6/go.mod h1:gOnZQu6fktDW7PNvWX184+Gbgi0IRDZXVYdLkBwT7Zw= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= @@ -431,10 +433,18 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= -go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= -go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= -go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.34.0 h1:O1E9/qhspQSz3O6/dSGLNBND2TO9mUaSvlhcKJMv278= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.34.0/go.mod h1:Id0oYi2ARij/um3gFV+t5rH1MTFdJpfTimsFsqKS7pE= +go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= +go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= +go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= +go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= +go.opentelemetry.io/otel/sdk/metric v0.34.0 h1:7ElxfQpXCFZlRTvVRTkcUvK8Gt5DC8QzmzsLsO2gdzo= +go.opentelemetry.io/otel/sdk/metric v0.34.0/go.mod h1:l4r16BIqiqPy5rd14kkxllPy/fOI4tWo1jkpD9Z3ffQ= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= diff --git a/src/internal/connector/graph/service.go b/src/internal/connector/graph/service.go index 69403fb19..712daa63f 100644 --- a/src/internal/connector/graph/service.go +++ b/src/internal/connector/graph/service.go @@ -10,6 +10,7 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + otelrt "github.com/NdoleStudio/go-otelroundtripper" backoff "github.com/cenkalti/backoff/v4" "github.com/microsoft/kiota-abstractions-go/serialization" ka "github.com/microsoft/kiota-authentication-azure-go" @@ -17,6 +18,8 @@ import ( msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" "github.com/pkg/errors" + "go.opentelemetry.io/otel/metric/global" + semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "github.com/alcionai/clues" "github.com/alcionai/corso/src/pkg/account" @@ -202,6 +205,15 @@ func HTTPClient(opts ...option) *http.Client { httpClient := msgraphgocore.GetDefaultClient(&clientOptions, middlewares...) httpClient.Timeout = defaultHTTPClientTimeout + parentTripper := httpClient.Transport + meter := global.MeterProvider().Meter("corso") + + httpClient.Transport = otelrt.New( + otelrt.WithParent(parentTripper), + otelrt.WithMeter(meter), + otelrt.WithAttributes(semconv.ServiceNameKey.String("corso")), + ) + clientconfig.apply(httpClient) return httpClient