diff --git a/graphrunner/BUILD.bazel b/graphrunner/BUILD.bazel index ed50781d..99f8b0a7 100644 --- a/graphrunner/BUILD.bazel +++ b/graphrunner/BUILD.bazel @@ -4,6 +4,7 @@ go_library( name = "graphrunner", srcs = [ "graph_runner.go", + "metrics.go", "native.go", "shell.go", ], @@ -15,6 +16,7 @@ go_library( "//core/git", "//core/targethasher", "//core/workspace", + "//observability/metrics", "@com_github_uber_go_tally//:tally", ], ) diff --git a/graphrunner/metrics.go b/graphrunner/metrics.go new file mode 100644 index 00000000..5714687d --- /dev/null +++ b/graphrunner/metrics.go @@ -0,0 +1,35 @@ +// Copyright (c) 2026 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package graphrunner + +import ( + "time" + + "github.com/uber-go/tally" +) + +// opCompute is snake_cased after the GraphRunner.Compute method. +const opCompute = "compute" + +var ( + // phaseDurationBuckets covers the compute phases (bazel query, git file + // hashes, target hashing). A bazel query on a large repo can run for hours, + // so the range extends to ~4.9h: exponential 100ms..~4.9h. + phaseDurationBuckets = tally.MustMakeExponentialDurationBuckets(100*time.Millisecond, 3, 12) + + // targetCountBuckets covers the computed graph size. Graphs already reach + // ~4M targets: exponential 1..~100M. + targetCountBuckets = tally.MustMakeExponentialValueBuckets(1, 10, 9) +) diff --git a/graphrunner/native.go b/graphrunner/native.go index cf5582d4..75d7d470 100644 --- a/graphrunner/native.go +++ b/graphrunner/native.go @@ -24,6 +24,7 @@ import ( "github.com/uber/tango/core/git" "github.com/uber/tango/core/targethasher" "github.com/uber/tango/core/workspace" + "github.com/uber/tango/observability/metrics" ) type nativeGraphRunner struct { @@ -31,7 +32,7 @@ type nativeGraphRunner struct { git git.Interface config config.RepositoryConfig extraExcludedFiles []string - scope tally.Scope + emitter *metrics.Emitter } type NativeGraphRunnerParams struct { @@ -48,12 +49,13 @@ func NewNativeGraphRunner(p NativeGraphRunnerParams) GraphRunner { if scope == nil { scope = tally.NoopScope } + emitter, _ := metrics.New(scope.SubScope("graph_runner")) return &nativeGraphRunner{ bazel: p.BazelClient, git: p.GitClient, config: p.Config, extraExcludedFiles: p.ExtraExcludedFiles, - scope: scope.SubScope("graph_runner"), + emitter: emitter, } } @@ -78,14 +80,14 @@ func (g *nativeGraphRunner) Compute(ctx context.Context, ws workspace.Workspace) AdditionalArgs: additionalArgs, }) - g.scope.Timer("bazel_query_duration").Record(time.Since(bazelStart)) + g.emitter.DurationHistogram(opCompute, "bazel_query_duration", phaseDurationBuckets).RecordDuration(time.Since(bazelStart)) if err != nil { return targethasher.EmptyResult(), err } gitStart := time.Now() knownSourceHashes, err := g.git.FileHashes(ctx, "HEAD") - g.scope.Timer("git_file_hashes_duration").Record(time.Since(gitStart)) + g.emitter.DurationHistogram(opCompute, "git_file_hashes_duration", phaseDurationBuckets).RecordDuration(time.Since(gitStart)) if err != nil { return targethasher.EmptyResult(), err } @@ -99,11 +101,11 @@ func (g *nativeGraphRunner) Compute(ctx context.Context, ws workspace.Workspace) hashStart := time.Now() res, err := targethasher.FromProto(ctx, queryResult.Result, ws.Path(), hashConfig) - g.scope.Timer("target_hash_duration").Record(time.Since(hashStart)) + g.emitter.DurationHistogram(opCompute, "target_hash_duration", phaseDurationBuckets).RecordDuration(time.Since(hashStart)) if err != nil { return targethasher.EmptyResult(), err } - g.scope.Gauge("target_count").Update(float64(len(res.Targets))) + g.emitter.ValueHistogram(opCompute, "target_count", targetCountBuckets).RecordValue(float64(len(res.Targets))) return res, nil }