Skip to content

feat(observability/metrics): add Emitter, options, buckets, and label vocabulary#181

Open
xytan0056 wants to merge 5 commits into
pr0-docsfrom
pr1-emitter-core
Open

feat(observability/metrics): add Emitter, options, buckets, and label vocabulary#181
xytan0056 wants to merge 5 commits into
pr0-docsfrom
pr1-emitter-core

Conversation

@xytan0056

@xytan0056 xytan0056 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Adds the observability/metrics package: the Emitter interface with a tally-backed implementation, per-call options (WithTags, duration/value bucket overrides), the default histogram buckets, and the shared tag keys + Result values.

  • Operation and metric names are added in later PRs as their emitters land, so nothing here is unused.
  • single Option type across emitter. Per-method option types is overkill for 3 options. Unintended options are noop anyway.

Stacked on #158.

ResultFail Result = "fail"
ResultHit Result = "hit"
ResultMiss Result = "miss"
)

@xytan0056 xytan0056 Jul 11, 2026

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.

rest of consts will be added as used. Keeping the change incremental for easier review

@xytan0056 xytan0056 force-pushed the pr1-emitter-core branch 2 times, most recently from cd500a7 to 7e2b539 Compare July 11, 2026 03:08
@xytan0056 xytan0056 changed the title [WIP] feat(observability/metrics): add Emitter, options, buckets, and label vocabulary \\feat(observability/metrics): add Emitter, options, buckets, and label vocabulary Jul 11, 2026
@xytan0056 xytan0056 changed the title \\feat(observability/metrics): add Emitter, options, buckets, and label vocabulary feat(observability/metrics): add Emitter, options, buckets, and label vocabulary Jul 11, 2026
Comment thread observability/metrics/emitter.go Outdated

// Emitter is the interface for emitting metrics.
type Emitter interface {
Inc(op, name string, opts ...Option)

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.

these methods should all be documented

Comment thread observability/metrics/emitter_test.go Outdated
"github.com/uber-go/tally"
)

func counterValue(t *testing.T, s tally.TestScope, name string, tags map[string]string) int64 {

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.

style: helpers should be placed below the tests.

Comment thread observability/metrics/emitter.go Outdated
// limitations under the License.

// Package metrics is a thin wrapper over tally.Scope that pins the naming,
// bucket, and tag conventions defined in the Tango Metrics Inventory.

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.

what is this "Tango Metrics Inventory"? It's better to document these in the package doc directly rather than just referencing something.

Comment thread observability/metrics/emitter.go Outdated
)

// Emitter is the interface for emitting metrics.
type Emitter interface {

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.

now that we've written it out, I'm not sure if we want Emitter to be an interface or a struct since we only have a single implementation of it.

The only reason this might be useful is if people want to plug in metrics emitter that are not backed by Tally, but that seems unlikely -- Thoughts?

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.

  • with interface, downstream can just New(nil) without Tally.NewTestScope (which is not bad either). This also forces construction here, with exporting struct,people can do metrics.Emitter{}, which can panic with nil scope
  • uber internal (duplica server) can implement this interface for consistency, not necessarily required tho

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.

I think the whole purpose of Emitter interface is to have it potentially pluggable and not depend on Tally.
The alternative approach (this is done in sqv2) is to use Tally as is with a potentially customized backend, because Tally itself is an abstraction.

@xytan0056 xytan0056 force-pushed the pr1-emitter-core branch 2 times, most recently from 8ee7643 to 7e2b539 Compare July 12, 2026 22:16
Comment thread observability/metrics/emitter.go Outdated
)

// Emitter is the interface for emitting metrics.
type Emitter interface {

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.

I think the whole purpose of Emitter interface is to have it potentially pluggable and not depend on Tally.
The alternative approach (this is done in sqv2) is to use Tally as is with a potentially customized backend, because Tally itself is an abstraction.

Comment thread observability/metrics/emitter.go Outdated
// the default duration buckets unless overridden with WithDurationBuckets.
RecordDur(op, name string, d time.Duration, opts ...Option)
// RecordCount records v in the named histogram under the op subscope, using
// the default value buckets unless overridden with WithValueBuckets.

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.

where practically will it be used?
I think the only reason to record into histogram is a duration, otherwise it is simply a counter with tags.

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.

this is for recording targets count from changedtargets call. This way we have an idea of repo scale and sanity of response
counter (by Inc) is for recording traffic trends


// Result values for TagResult.
const (
ResultSuccess Result = "success"

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.

all exported times are to be commented

@xytan0056 xytan0056 Jul 13, 2026

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.

these are self-explanatory constants, I'm going to add more later for operations, adding a comment to each of them seems a bit redundant

Single implementation and a thin tally wrapper — drop the interface and
export the struct directly. New/Tagged return *Emitter. Callers fake metrics
with tally.NewTestScope, not an interface mock.
@xytan0056 xytan0056 force-pushed the pr0-docs branch 2 times, most recently from 4371e62 to f6e4228 Compare July 15, 2026 05:19
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.

3 participants