gitea源码

trace_builtin.go 2.6KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2025 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package gtprof
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "sync/atomic"
  9. "time"
  10. "code.gitea.io/gitea/modules/tailmsg"
  11. )
  12. type traceBuiltinStarter struct{}
  13. type traceBuiltinSpan struct {
  14. ts *TraceSpan
  15. internalSpanIdx int
  16. }
  17. func (t *traceBuiltinSpan) addEvent(name string, cfg *EventConfig) {
  18. // No-op because builtin tracer doesn't need it.
  19. // In the future we might use it to mark the time point between backend logic and network response.
  20. }
  21. func (t *traceBuiltinSpan) recordError(err error, cfg *EventConfig) {
  22. // No-op because builtin tracer doesn't need it.
  23. // Actually Gitea doesn't handle err this way in most cases
  24. }
  25. func (t *traceBuiltinSpan) toString(out *strings.Builder, indent int) {
  26. t.ts.mu.RLock()
  27. defer t.ts.mu.RUnlock()
  28. out.WriteString(strings.Repeat(" ", indent))
  29. out.WriteString(t.ts.name)
  30. if t.ts.endTime.IsZero() {
  31. out.WriteString(" duration: (not ended)")
  32. } else {
  33. 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())
  34. }
  35. for _, a := range t.ts.attributes {
  36. out.WriteString(" ")
  37. out.WriteString(a.Key)
  38. out.WriteString("=")
  39. value := a.Value.AsString()
  40. if strings.ContainsAny(value, " \t\r\n") {
  41. quoted := false
  42. for _, c := range "\"'`" {
  43. if quoted = !strings.Contains(value, string(c)); quoted {
  44. value = string(c) + value + string(c)
  45. break
  46. }
  47. }
  48. if !quoted {
  49. value = fmt.Sprintf("%q", value)
  50. }
  51. }
  52. out.WriteString(value)
  53. }
  54. out.WriteString("\n")
  55. for _, c := range t.ts.children {
  56. span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan)
  57. span.toString(out, indent+2)
  58. }
  59. }
  60. func (t *traceBuiltinSpan) end() {
  61. if t.ts.parent == nil {
  62. // TODO: debug purpose only
  63. // TODO: it should distinguish between http response network lag and actual processing time
  64. threshold := time.Duration(traceBuiltinThreshold.Load())
  65. if threshold != 0 && t.ts.endTime.Sub(t.ts.startTime) > threshold {
  66. sb := &strings.Builder{}
  67. t.toString(sb, 0)
  68. tailmsg.GetManager().GetTraceRecorder().Record(sb.String())
  69. }
  70. }
  71. }
  72. func (t *traceBuiltinStarter) start(ctx context.Context, traceSpan *TraceSpan, internalSpanIdx int) (context.Context, traceSpanInternal) {
  73. return ctx, &traceBuiltinSpan{ts: traceSpan, internalSpanIdx: internalSpanIdx}
  74. }
  75. func init() {
  76. globalTraceStarters = append(globalTraceStarters, &traceBuiltinStarter{})
  77. }
  78. var traceBuiltinThreshold atomic.Int64
  79. func EnableBuiltinTracer(threshold time.Duration) {
  80. traceBuiltinThreshold.Store(int64(threshold))
  81. }