From ea967a56086536dff49d5b1fbd2012c9efbdf311 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Mon, 2 Sep 2024 21:24:57 +0300 Subject: [PATCH] fix bug when no child tracer created --- deploy/grafana-ds.yaml | 30 ++++++++++++++++++++++++ docker-compose.yaml | 1 + src/app.go | 34 +++++++++++++++++----------- src/core/repos/user_repo.go | 21 ++++++++++++++--- src/server/middleware/request_log.go | 5 ---- src/server/middleware/tracing.go | 16 ++++++++++--- src/server/server.go | 3 +++ 7 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 deploy/grafana-ds.yaml diff --git a/deploy/grafana-ds.yaml b/deploy/grafana-ds.yaml new file mode 100644 index 0000000..1eebe9e --- /dev/null +++ b/deploy/grafana-ds.yaml @@ -0,0 +1,30 @@ +apiVersion: 1 + +datasources: +- name: Prometheus + type: prometheus + uid: prometheus + access: proxy + orgId: 1 + url: http://prometheus:9090 + basicAuth: false + isDefault: false + version: 1 + editable: false + jsonData: + httpMethod: GET +- name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index f4c28ac..478ddd3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -18,6 +18,7 @@ services: - "host.docker.internal:host-gateway" volumes: - grafana-volume:/var/lib/grafana + - ./deploy/grafana-ds.yaml:/etc/grafana/provisioning/datasources/datasources.yaml prometheus: image: prom/prometheus:v2.54.0 diff --git a/src/app.go b/src/app.go index 6bc66b6..8f4fd1e 100644 --- a/src/app.go +++ b/src/app.go @@ -24,7 +24,8 @@ import ( "time" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" - "go.opentelemetry.io/otel/sdk/trace" + traceSdk "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" ) type App struct{} @@ -105,6 +106,24 @@ func (a *App) Run(p RunParams) { } } + var tracer trace.Tracer + { + tracerExporter, err := otlptracehttp.New(context.Background(), otlptracehttp.WithEndpointURL("http://localhost:4318")) + if err != nil { + logger.Fatal().Err(err).Msg("failed initializing tracer") + } + + tracerProvider := traceSdk.NewTracerProvider( + traceSdk.WithSampler(traceSdk.AlwaysSample()), + traceSdk.WithBatcher( + tracerExporter, + traceSdk.WithMaxQueueSize(4096), + traceSdk.WithMaxExportBatchSize(1024), + ), + ) + tracer = tracerProvider.Tracer("backend") + } + // Build business-logic objects var ( userService services.UserService @@ -115,7 +134,7 @@ func (a *App) Run(p RunParams) { jwtUtil = utils.NewJwtUtil(key) passwordUtil = utils.NewPasswordUtil() - userRepo = repos.NewUserRepo(sqlDb) + userRepo = repos.NewUserRepo(sqlDb, tracer) emailRepo = repos.NewEmailRepo() actionTokenRepo = repos.NewActionTokenRepo(sqlDb) @@ -163,17 +182,6 @@ func (a *App) Run(p RunParams) { clientNotifier := client_notifier.NewBasicNotifier() - tracerExporter, err := otlptracehttp.New(context.Background(), otlptracehttp.WithEndpointURL("http://localhost:4318")) - if err != nil { - logger.Fatal().Err(err).Msg("failed initializing tracer") - } - tracerProvider := trace.NewTracerProvider( - trace.WithSampler(trace.AlwaysSample()), - trace.WithBatcher(tracerExporter), - ) - - tracer := tracerProvider.Tracer("backend") - // Start profiling if args.GetProfilePath() != "" { pprofFile, err := os.Create(args.GetProfilePath()) diff --git a/src/core/repos/user_repo.go b/src/core/repos/user_repo.go index e9b0c90..72c436a 100644 --- a/src/core/repos/user_repo.go +++ b/src/core/repos/user_repo.go @@ -6,6 +6,8 @@ import ( "context" "database/sql" "errors" + + "go.opentelemetry.io/otel/trace" ) // type userDAO struct { @@ -22,15 +24,19 @@ type UserRepo interface { GetUserByEmail(ctx context.Context, login string) (*models.UserDTO, error) } -func NewUserRepo(db integrations.SqlDB) UserRepo { - return &userRepo{db} +func NewUserRepo(db integrations.SqlDB, tracer trace.Tracer) UserRepo { + return &userRepo{db, tracer} } type userRepo struct { - db integrations.SqlDB + db integrations.SqlDB + tracer trace.Tracer } func (u *userRepo) CreateUser(ctx context.Context, dto models.UserDTO) (*models.UserDTO, error) { + _, span := u.tracer.Start(ctx, "postgres") + defer span.End() + query := `insert into users (email, secret, name) values ($1, $2, $3) returning id;` row := u.db.QueryRowContext(ctx, query, dto.Email, dto.Secret, dto.Name) @@ -48,6 +54,9 @@ func (u *userRepo) CreateUser(ctx context.Context, dto models.UserDTO) (*models. } func (u *userRepo) UpdateUser(ctx context.Context, userId string, dto models.UserUpdateDTO) error { + _, span := u.tracer.Start(ctx, "postgres") + defer span.End() + query := `update users set secret=$1, name=$2 where id = $3;` _, err := u.db.ExecContext(ctx, query, dto.Secret, dto.Name, userId) if err != nil { @@ -58,6 +67,9 @@ func (u *userRepo) UpdateUser(ctx context.Context, userId string, dto models.Use } func (u *userRepo) GetUserById(ctx context.Context, id string) (*models.UserDTO, error) { + _, span := u.tracer.Start(ctx, "postgres") + defer span.End() + query := `select id, email, secret, name from users where id = $1;` row := u.db.QueryRowContext(ctx, query, id) @@ -74,6 +86,9 @@ func (u *userRepo) GetUserById(ctx context.Context, id string) (*models.UserDTO, } func (u *userRepo) GetUserByEmail(ctx context.Context, login string) (*models.UserDTO, error) { + _, span := u.tracer.Start(ctx, "postgres") + defer span.End() + query := `select id, email, secret, name from users where email = $1;` row := u.db.QueryRowContext(ctx, query, login) diff --git a/src/server/middleware/request_log.go b/src/server/middleware/request_log.go index 40ed8ee..eb1b78f 100644 --- a/src/server/middleware/request_log.go +++ b/src/server/middleware/request_log.go @@ -7,7 +7,6 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" - "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -16,15 +15,11 @@ func NewRequestLogMiddleware(logger log.Logger, tracer trace.Tracer, prometheus prometheus.RequestInc() defer prometheus.RequestDec() - _, span := tracer.Start(c.Request.Context(), c.Request.URL.Path) - defer span.End() - requestId := c.GetHeader("X-Request-Id") if requestId == "" { requestId = uuid.New().String() } - span.SetAttributes(attribute.String("requestId", c.ClientIP())) log.SetCtxRequestId(c, requestId) path := c.Request.URL.Path diff --git a/src/server/middleware/tracing.go b/src/server/middleware/tracing.go index 22e66bc..9fac2c3 100644 --- a/src/server/middleware/tracing.go +++ b/src/server/middleware/tracing.go @@ -2,16 +2,26 @@ package middleware import ( "github.com/gin-gonic/gin" - "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func NewTracingMiddleware(tracer trace.Tracer) gin.HandlerFunc { + prop := otel.GetTextMapPropagator() + return func(c *gin.Context) { - _, span := tracer.Start(c.Request.Context(), c.Request.URL.Path) + savedCtx := c.Request.Context() + defer func() { + c.Request = c.Request.WithContext(savedCtx) + }() + + ctx := prop.Extract(savedCtx, propagation.HeaderCarrier(c.Request.Header)) + + ctx, span := tracer.Start(ctx, c.Request.URL.Path) defer span.End() - span.SetAttributes(attribute.String("requestId", c.ClientIP())) + c.Request = c.Request.WithContext(ctx) c.Next() } diff --git a/src/server/server.go b/src/server/server.go index 4704ed2..6d65309 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -35,6 +35,8 @@ func New(opts NewServerOpts) *Server { } r := gin.New() + r.ContextWithFallback = true // Use it to allow getting values from c.Request.Context() + r.Static("/webapp", "./webapp") r.GET("/health", handlers.NewDummyHandler()) @@ -43,6 +45,7 @@ func New(opts NewServerOpts) *Server { r.Use(middleware.NewRecoveryMiddleware(opts.Logger, prometheus, opts.DebugMode)) r.Use(middleware.NewRequestLogMiddleware(opts.Logger, opts.Tracer, prometheus)) + r.Use(middleware.NewTracingMiddleware(opts.Tracer)) r.GET("/pooling", handlers.NewLongPoolingHandler(opts.Logger, opts.Notifier))