Skip to content

docs(observability/metrics): document the metrics package#158

Open
xytan0056 wants to merge 17 commits into
mainfrom
pr0-docs
Open

docs(observability/metrics): document the metrics package#158
xytan0056 wants to merge 17 commits into
mainfrom
pr0-docs

Conversation

@xytan0056

@xytan0056 xytan0056 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

add Tango Metrics Inventory RFC into the repo. Covers the Emitter contract and its usage in callsites

@xytan0056 xytan0056 force-pushed the pr0-docs branch 5 times, most recently from ea9e0ef to d01c936 Compare July 7, 2026 23:37
@xytan0056 xytan0056 marked this pull request as ready for review July 7, 2026 23:39
@xytan0056 xytan0056 requested review from a team as code owners July 7, 2026 23:39
Comment thread docs/observability/metrics.md Outdated
@xytan0056 xytan0056 force-pushed the pr0-docs branch 4 times, most recently from a1249f6 to cf7326b Compare July 7, 2026 23:58
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
@xytan0056 xytan0056 force-pushed the pr0-docs branch 6 times, most recently from 4f4387b to 54a049f Compare July 8, 2026 21:47

@sbalabanov sbalabanov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing pieces:

  • error classification integration
  • working with histograms for both status and duration and an example on custom buckets

Comment thread docs/observability/metrics.md Outdated

Tango is a library. Consumers wire it into their own `fx` graph with their own `tally.Scope`, and often deploy multiple flavors (long-running server, batch job, one-shot CLI) side-by-side. Without a shared convention every deployment invents its own metric names and tag layout, and dashboards devolve into per-name merges.

This package owns:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this file be README.md under observability/metrics then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
xytan0056 and others added 4 commits July 14, 2026 18:07
…local metrics

Rework metrics.md around the revised proposal: a concrete Tally-backed
Emitter that binds and returns instruments, explicit dependency injection
instead of context propagation, domain-local operation/metric names and
bucket policies, controller-boundary request classification, per-series
in-flight counters, and explicit no-op construction.
…ing-method errors

Refine the revised metrics design: remove the gauge/in-flight tracking,
drop the central shared-conventions vocabulary, and return instruments
directly from the binding methods (only New surfaces a nil-scope wiring
error). Add a Request-specific tags example.
@xytan0056

Copy link
Copy Markdown
Contributor Author

updated based on discussion offline.

…Params

Show per-component buckets as a default owned by the package, overridable
through the component's Params (zero value falls back), and add the
requestMetrics constructor with the same default-and-override handling.
…ord call

Collapse the Begin/Complete/requestAttempt two-phase into one deferred
Record(start, err); fold the duplicated GetChangedTargets handler into a
single example; align the request counter name on 'called'.
… Begin/Complete

Begin increments called and returns the start time; Complete records
duration and outcome. Keeps the entry-vs-exit ordering without the
requestAttempt handle or sync.Once.
… Record

called was redundant with succeeded + failed once Complete is deferred, so
drop it and the two-phase Begin/Complete in favor of a single deferred
Record(start, err).
…uest binding

Build requestMetrics per request from a repo-tagged emitter so
succeeded/failed/duration break down by repo; rely on tally name+tags
caching to bind each (op, repo) series once. Trim request-specific tags
to the cardinality rules.
…nd-once claims

Make newQueryMetrics take positional emitter+buckets (drop exported
MetricParams) to match newRequestMetrics, and soften the two bound-once
statements so they don't over-generalize past the per-request request
metrics.
Comment thread docs/observability/metrics.md Outdated
e := c.emitter.Tagged(map[string]string{
tagRepo: common.ToShortRemote(req.GetFirstRevision().GetRemote()),
})
m := newRequestMetrics(e, opGetChangedTargets, c.requestDurationBuckets)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requestmetrics need to be per-repo, so this is initialized per request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really needed to create a metrics structure per each metric type emitted?
SubmitQueue uses simpler structure with standalone helper functions and a general scope object:
https://github.com/uber/submitqueue/blob/main/submitqueue/orchestrator/controller/start/start.go#L76-L77
https://github.com/uber/submitqueue/blob/main/submitqueue/orchestrator/controller/validate/validate.go#L92-L93

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a concern of scopes being tagged everywhere which is expensive.
I updated with a memoization approach in each domain, what do you think?

Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
// New creates an emitter for scope. A nil scope is a configuration error.
func New(scope tally.Scope) (*Emitter, error)

// Nop creates an explicitly disabled emitter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would it do so if Emitter is not an interface? With noop tally scope?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

func Nop() *Emitter { return &Emitter{scope: tally.NoopScope} }

Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
Comment thread docs/observability/metrics.md Outdated
e := c.emitter.Tagged(map[string]string{
tagRepo: common.ToShortRemote(req.GetFirstRevision().GetRemote()),
})
m := newRequestMetrics(e, opGetChangedTargets, c.requestDurationBuckets)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really needed to create a metrics structure per each metric type emitted?
SubmitQueue uses simpler structure with standalone helper functions and a general scope object:
https://github.com/uber/submitqueue/blob/main/submitqueue/orchestrator/controller/start/start.go#L76-L77
https://github.com/uber/submitqueue/blob/main/submitqueue/orchestrator/controller/validate/validate.go#L92-L93

…ency

Address review feedback on the metrics design:

- Record outcomes as one result-tagged latency histogram instead of
  separate success/failure counters; counts derive from the histogram.
- Add a begin/complete request pattern (started counter at Begin, result-
  tagged latency histogram at Complete).
- Restore shared vocabulary constants (operation names, tag keys, result
  values) in names.go so outcomes tag consistently across operations.
- Fill in concise Emitter method bodies and note Nop wraps NoopScope.
…ain memoization

- Move Begin/Complete out of the metrics package into each domain struct
  (graphRunnerMetrics, requestMetrics) — memoization is domain-local.
- Metrics package exports Emitter + constants + Outcome() only.
- Standardize start/finish naming convention across all operations.
- Domain structs pre-build result-tagged emitters at construction;
  controller memoizes per (repo, result) pair.
- Buckets declared at each callsite, not as package defaults.
- Add ResultCancelled for context.Canceled/DeadlineExceeded.
- Add M3QL query examples for start rate, outcome counts, P95 latency.
…egin/Complete

- Switch domain-local example from graphrunner to orchestrator
- Emitter.Tagged is stateless; memoization is per-domain struct
- Each domain owns Begin/Complete, op struct, and tagged emitter cache
- Metrics package exports only Emitter + constants + Outcome()
- Orchestrator example shows repo-memoized Begin/Complete pattern
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants