mirror of https://github.com/go-gitea/gitea.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.6 KiB
96 lines
2.6 KiB
// Copyright 2025 The Gitea Authors. All rights reserved. |
|
// SPDX-License-Identifier: MIT |
|
|
|
package gtprof |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"strings" |
|
"sync/atomic" |
|
"time" |
|
|
|
"code.gitea.io/gitea/modules/tailmsg" |
|
) |
|
|
|
type traceBuiltinStarter struct{} |
|
|
|
type traceBuiltinSpan struct { |
|
ts *TraceSpan |
|
|
|
internalSpanIdx int |
|
} |
|
|
|
func (t *traceBuiltinSpan) addEvent(name string, cfg *EventConfig) { |
|
// No-op because builtin tracer doesn't need it. |
|
// In the future we might use it to mark the time point between backend logic and network response. |
|
} |
|
|
|
func (t *traceBuiltinSpan) recordError(err error, cfg *EventConfig) { |
|
// No-op because builtin tracer doesn't need it. |
|
// Actually Gitea doesn't handle err this way in most cases |
|
} |
|
|
|
func (t *traceBuiltinSpan) toString(out *strings.Builder, indent int) { |
|
t.ts.mu.RLock() |
|
defer t.ts.mu.RUnlock() |
|
|
|
out.WriteString(strings.Repeat(" ", indent)) |
|
out.WriteString(t.ts.name) |
|
if t.ts.endTime.IsZero() { |
|
out.WriteString(" duration: (not ended)") |
|
} else { |
|
fmt.Fprintf(out, " start=%s duration=%.4fs", t.ts.startTime.Format("2006-01-02 15:04:05"), t.ts.endTime.Sub(t.ts.startTime).Seconds()) |
|
} |
|
for _, a := range t.ts.attributes { |
|
out.WriteString(" ") |
|
out.WriteString(a.Key) |
|
out.WriteString("=") |
|
value := a.Value.AsString() |
|
if strings.ContainsAny(value, " \t\r\n") { |
|
quoted := false |
|
for _, c := range "\"'`" { |
|
if quoted = !strings.Contains(value, string(c)); quoted { |
|
value = string(c) + value + string(c) |
|
break |
|
} |
|
} |
|
if !quoted { |
|
value = fmt.Sprintf("%q", value) |
|
} |
|
} |
|
out.WriteString(value) |
|
} |
|
out.WriteString("\n") |
|
for _, c := range t.ts.children { |
|
span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan) |
|
span.toString(out, indent+2) |
|
} |
|
} |
|
|
|
func (t *traceBuiltinSpan) end() { |
|
if t.ts.parent == nil { |
|
// TODO: debug purpose only |
|
// TODO: it should distinguish between http response network lag and actual processing time |
|
threshold := time.Duration(traceBuiltinThreshold.Load()) |
|
if threshold != 0 && t.ts.endTime.Sub(t.ts.startTime) > threshold { |
|
sb := &strings.Builder{} |
|
t.toString(sb, 0) |
|
tailmsg.GetManager().GetTraceRecorder().Record(sb.String()) |
|
} |
|
} |
|
} |
|
|
|
func (t *traceBuiltinStarter) start(ctx context.Context, traceSpan *TraceSpan, internalSpanIdx int) (context.Context, traceSpanInternal) { |
|
return ctx, &traceBuiltinSpan{ts: traceSpan, internalSpanIdx: internalSpanIdx} |
|
} |
|
|
|
func init() { |
|
globalTraceStarters = append(globalTraceStarters, &traceBuiltinStarter{}) |
|
} |
|
|
|
var traceBuiltinThreshold atomic.Int64 |
|
|
|
func EnableBuiltinTracer(threshold time.Duration) { |
|
traceBuiltinThreshold.Store(int64(threshold)) |
|
}
|
|
|