@@ -16,7 +16,7 @@ type contextKey struct {
1616 name string
1717}
1818
19- var ContextKeySpan = & contextKey {"span" }
19+ var contextKeySpan = & contextKey {"span" }
2020
2121type traceStarter interface {
2222 start (ctx context.Context , traceSpan * TraceSpan , internalSpanIdx int ) (context.Context , traceSpanInternal )
@@ -132,10 +132,29 @@ func (t *Tracer) Start(ctx context.Context, spanName string) (context.Context, *
132132 ts .internalContexts = append (ts .internalContexts , ctx )
133133 ts .internalSpans = append (ts .internalSpans , internalSpan )
134134 }
135- ctx = context .WithValue (ctx , ContextKeySpan , ts )
135+ ctx = context .WithValue (ctx , contextKeySpan , ts )
136136 return ctx , ts
137137}
138138
139+ type mutableContext interface {
140+ context.Context
141+ SetContextValue (key , value any )
142+ GetContextValue (key any ) any
143+ }
144+
145+ // StartInContext starts a trace span in Gitea's mutable context (usually the web request context).
146+ // Due to the design limitation of Gitea's web framework, it can't use `context.WithValue` to bind a new span into a new context.
147+ // So here we use our "reqctx" framework to achieve the same result: web request context could always see the latest "span".
148+ func (t * Tracer ) StartInContext (ctx mutableContext , spanName string ) (* TraceSpan , func ()) {
149+ curTraceSpan := GetContextSpan (ctx )
150+ _ , newTraceSpan := GetTracer ().Start (ctx , spanName )
151+ ctx .SetContextValue (contextKeySpan , newTraceSpan )
152+ return newTraceSpan , func () {
153+ newTraceSpan .End ()
154+ ctx .SetContextValue (contextKeySpan , curTraceSpan )
155+ }
156+ }
157+
139158func (s * TraceSpan ) End () {
140159 s .mu .Lock ()
141160 s .endTime = time .Now ()
@@ -151,6 +170,6 @@ func GetTracer() *Tracer {
151170}
152171
153172func GetContextSpan (ctx context.Context ) * TraceSpan {
154- ts , _ := ctx .Value (ContextKeySpan ).(* TraceSpan )
173+ ts , _ := ctx .Value (contextKeySpan ).(* TraceSpan )
155174 return ts
156175}
0 commit comments