Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/git/trace2hooks/log_exporter.go')
-rw-r--r--internal/git/trace2hooks/log_exporter.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/internal/git/trace2hooks/log_exporter.go b/internal/git/trace2hooks/log_exporter.go
new file mode 100644
index 000000000..a714d7fb3
--- /dev/null
+++ b/internal/git/trace2hooks/log_exporter.go
@@ -0,0 +1,68 @@
+package trace2hooks
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/trace2"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
+ "golang.org/x/time/rate"
+)
+
+// NewLogExporter initializes LogExporter, which is a hook that uses the parsed
+// trace2 events from the manager to export them to the Gitaly log. It's invocations are limited
+// by the rateLimiter. The limiter allows maxBurstToken number of events to happen at once and then
+// replenishes by maxEventPerSecond. It works on the token bucket algorithm where you have a number
+// of tokens in the bucket to start and you can consume them in each call whilst the bucket gets
+// refilled at the specified rate.
+func NewLogExporter(rl *rate.Limiter, logger log.Logger) *LogExporter {
+ return &LogExporter{
+ rateLimiter: rl,
+ logger: logger,
+ }
+}
+
+// LogExporter is a trace2 hook that adds trace2 api event logs to Gitaly's logs.
+type LogExporter struct {
+ logger log.Logger
+ rateLimiter *rate.Limiter
+}
+
+// Name returns the name of tracing exporter
+func (t *LogExporter) Name() string {
+ return "log_exporter"
+}
+
+// Handle will log the trace in a readable json format in Gitaly's logs. Metadata is also collected
+// and additional information is added to the log. It is also rate limited to protect it from overload
+// when there are a lot of trace2 events triggered from git operations.
+func (t *LogExporter) Handle(rootCtx context.Context, trace *trace2.Trace) error {
+ if !t.rateLimiter.Allow() {
+ // When the event is not allowed, return an error to the caller, this may cause traces to be skipped/dropped.
+ return fmt.Errorf("rate has exceeded current limit")
+ }
+
+ trace.Walk(rootCtx, func(ctx context.Context, t *trace2.Trace) context.Context {
+ t.SetMetadata("elapsed_ms", fmt.Sprintf("%d", t.FinishTime.Sub(t.StartTime).Milliseconds()))
+
+ return ctx
+ })
+
+ childrenJSON, err := json.Marshal(trace.Children)
+ if err != nil {
+ return fmt.Errorf("marshal json: %w", err)
+ }
+ escapedChildren := json.RawMessage(childrenJSON)
+
+ t.logger.WithFields(log.Fields{
+ "name": trace.Name,
+ "thread": trace.Thread,
+ "component": "trace2hooks." + t.Name(),
+ "start_time": trace.StartTime,
+ "finish_time": trace.FinishTime,
+ "metadata": trace.Metadata,
+ "children": escapedChildren,
+ }).Info("Git Trace2 API")
+ return nil
+}