package utils import ( "context" "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing" "github.com/valyala/fasthttp" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) type httpCarrier struct { r *fasthttp.RequestCtx } func (c *httpCarrier) Get(key string) string { bytes := c.r.Request.Header.Peek(key) if len(bytes) == 0 { return "" } return string(bytes) } func (c *httpCarrier) Set(key string, value string) { c.r.Response.Header.Set(key, value) } func (c *httpCarrier) Keys() []string { dict := make(map[string]interface{}) c.r.Request.Header.VisitAll( func(key, _ []byte) { dict[string(key)] = true }, ) c.r.Response.Header.VisitAll( func(key, _ []byte) { dict[string(key)] = true }, ) result := make([]string, 0, len(dict)) for key := range dict { result = append(result, key) } return result } func extractHTTPTraceInfo(ctx context.Context, req *fasthttp.RequestCtx) context.Context { if req == nil { return ctx } carrier := &httpCarrier{r: req} return tracing.Propagator.Extract(ctx, carrier) } // SetHTTPTraceInfo saves trace headers to response. func SetHTTPTraceInfo(ctx context.Context, span trace.Span, req *fasthttp.RequestCtx) { if req == nil { return } if err := req.Err(); err != nil { span.SetStatus(codes.Error, err.Error()) } span.SetAttributes( semconv.HTTPStatusCode(req.Response.StatusCode()), ) carrier := &httpCarrier{r: req} tracing.Propagator.Inject(ctx, carrier) } // StartHTTPServerSpan starts root HTTP server span. func StartHTTPServerSpan(ctx context.Context, req *fasthttp.RequestCtx, operationName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { ctx = extractHTTPTraceInfo(ctx, req) opts = append(opts, trace.WithAttributes( attribute.String("http.client_address", req.RemoteAddr().String()), attribute.String("http.path", string(req.Path())), semconv.HTTPMethod(string(req.Method())), semconv.RPCService("frostfs-http-gw"), attribute.String("http.query", req.QueryArgs().String()), ), trace.WithSpanKind(trace.SpanKindServer)) return tracing.StartSpanFromContext(ctx, operationName, opts...) }