Page MenuHomePhabricator

StatsLib equivalent of PerDbNameStatsdDataFactory
Closed, ResolvedPublic


Some history:

Originally, addStaticLabel() was created to allow a replacement for perDbNameStatsdDataFactory. To use it as intended, there are several considerations:

  • StatsCache must be a singleton instance shared by all instances of StatsFactory
  • addStaticLabel() must not affect the global StatsFactory service
  • A StatsFactory with static labels must be created prior to any metrics appearing in the cache
  • Attempts to use it without a component or with metrics in the cache throw an unhandled IllegalOperationException

I question the wisdom of its current implementation for several reasons:

  1. It's unsafe to use outside of ServiceWiring
  2. It mutates the state of a StatsFactory instance
  3. It's not explicit about its behavior - to anyone looking later, usage looks identical to the "normal" StatsFactory instance when it really isn't

For impact measurement, PerDbNameStatsdDataFactory is only used in 17 places.

Pilot use case:

Event Timeline

Looking at the example in the addStaticLabel() method doc-block (which happens to be in line with what the code does):

$statsFactory->withComponent( 'demo' )
     ->addStaticLabel( 'first', 'foo' )
     ->addStaticLabel( 'second', 'bar' )
     ->getCounter( 'testMetric_total' )
     ->setLabel( 'third', 'baz' )

outputs statsd: ""
outputs prometheus: "mediawiki_demo_testMetric_total{first='foo',second='bar',third='baz'}

... the statsd output creates a somewhat suffix on the metric namespace instead of a prefix compared to PerDbNameStatsdDataFactory.

That creates a difference between what addStaticLabel() and PerDbNameStatsdDataFactory which will adds the wiki (DBname) as a prefix to the statsdD metric name which would make addStaticLabel() non backward-compatible as this will be a completely different metric name in StatsdD's perspective.

So if we do:

$statsFactory->withComponent( 'demo' )
     ->addStaticLabel( 'wiki', 'enwiki' )
     ->getCounter( 'testMetric_total' )
     ->setLabel( 'third', 'baz' )

... we end up with a statsd output as such: mediawiki.demo.testMetric_total.enwiki.baz instead of mediawiki.enwiki.demo.testMetric_total.baz.

Let me know if my reasoning is accurate here.

Let me know if my reasoning is accurate here.

You are correct. Labels are the "flexible" part of a Prometheus metric and names should be rigid. This concept had to be imposed on statslib's statsd implementation.

I think this use case is common enough to warrant a bit of guidance/documentation so that the callers can benefit from doing it the same way and not inventing slightly differenet wheels. However, it seems rare enough that creating a new top-level surfaces makes this hard to scale. There are other far more common labels we place on metrics that would otherwise justify their own services as well, and as soon as you have two, the problem is that you can't combine them, thus bringing us back to the same point: simply set the labels explicitly.

If we ignore the other common labels, I think even in the case where there is only one, there is loss of value if we encourage needless abstraction for metric generation. Having metrics created from a single chunk of code with everything right there is incredably valuable by itself. I'd instead suggest adding abstractions where needed in the area of 1) creating the values for those labels so that it is really just 1 line of code with a key and an injected value or simple function call and 2) re-using the resulting StatsFactory->getCounter(…)->setLabel() code via a utility method if multiple of the same metric are needed in a single code base.

In the case of a per-wiki metric, this appears to be satisfied as follows:

$stat->addLabel( 'wiki', WikiMap::getCurrentWikiId() );

In practice, for service classes that use DI to vary themselves by wiki, this is already injected as $wikiId from service wiring:

$stat->addLabel( 'wiki', $this->wiki );

Given the conversation we've had both here and on patches, I lean towards not reimplementing the per-db prefixed service. The alternative is to set the labels explicitly in the place where the metric is created.

If we decide on this, we get the opportunity to simplify StatsLib by removing all the static label supporting code.

Change #1017068 had a related patch set uploaded (by Cwhite; author: Cwhite):

[mediawiki/core@master] stats: remove static labels feature

Change #1017068 merged by jenkins-bot:

[mediawiki/core@master] stats: remove static labels feature

colewhite claimed this task.

Docs have been updated on The feature is gone.

Docs have been updated on The feature is gone.


I might be missing something @colewhite, remind me. Have we decided on what to move forward with?

Are we going to just prefix the statsd key in copyToStatsdAt() with the dbName to stay compatible and then in the new metric, add a label with the wiki? If this is the new way forward, does this patch: do it correctly? Or is there something else we need to change?

It seems is now obsolete since addStaticLabels() is gone? Cc @Lucas_Werkmeister_WMDE.

I might be missing something @colewhite, remind me. Have we decided on what to move forward with?

For metrics needing to stay compatible with the prefixing, I think we should follow @Krinkle 's advice and insert WikiMap::getCurrentWikiId() into the namespace at the appropriate point.