Jump to content

Manual:Stats

From mediawiki.org

The Stats library (added in MW 1.41) attempts to better define the interface for generating metrics in MediaWiki.

API Docs on doc.wikimedia.org

Global Configuration

[edit]

The global configuration is in MainConfigSchema.php and can be overridden in LocalSettings.php .

  • $wgStatsFormat is the output format all metrics will be rendered to.
    • Default null which disables metrics rendering.
    • Supported options are statsd, dogstatsd, null
    • See Wikimedia\Stats\OutputFormats::SUPPORTED_FORMATS for an up-to-date list of options.
  • $wgStatsTarget is the URI the metrics will be forwarded to. E.g. udp://127.0.0.1:8125
    • Default null which disables sending metrics.
  • $wgStatsPrefix is the prefix which will be applied to all generated metrics. Required. Default MediaWiki.

Metric Types

[edit]

The supported metric types are:

  • CounterMetric
    • An only-ever-incrementing counter.
    • Great for tracking rates.
    • Implements increment() and incrementBy($number)
  • GaugeMetric
    • A settable value.
    • Implements set($number)
  • TimingMetric
    • Observes timing data.
    • When the backend is configured to do so, histograms of timing metrics are generated.
    • Implements observe($number), start(), and stop()
    • Can call start() many times; call to stop() can throw if start() not called first.

Requesting a Metric

[edit]

Use a getter to get a metric from the StatsFactory.

  • getCounter($name)
  • getGauge($name)
  • getTiming($name)

A Simple Example

[edit]

Let's create a counter for tracking each time a function is called:

// Get the StatsFactory from MediaWikiServices
$statsFactory = MediaWikiServices::getInstance()->getStatsFactory();

// Make a CounterMetric
$myCounter = $statsFactory->getCounter('function_calls')
    ->setLabel('function_name', 'my_function');

// increment the counter providing the namespace and the name of the function call
$myCounter->increment();  // StatsD output: "MediaWiki.function_calls.my_function 1"

StatsD Metric Namespace

[edit]

Generated StatsD metrics follow a predictable pattern:

$output = implode( '.', [ $wgStatsPrefix, $component, $name, $label_key_1, $label_key_2, ...etc ] );

For example:

// assuming $wgStatsFormat = 'statsd' and $wgStatsPrefix = 'mediawiki'

$namespace = 'Draft';

MediaWikiServices::getInstance()->getStatsFactory()
    ->getCounter( 'function_calls' )
    ->setLabel( 'name', 'my_function' )
    ->setLabel( 'namespace', $namespace )
    ->increment();

would create a metric namespace:

mediawiki.function_calls.my_function.Draft

Features

[edit]

StatsFactory->withComponent()

[edit]

Returns a new StatsFactory instance with a component field appended to the globally-configured prefix. Intended for components and extensions, this feature isolates metrics generated by the component to their own namespace. For example, a metric bar without a component would look like:

mediawiki.bar

Adding a component foo would make the same metric look like:

mediawiki.foo.bar

MetricInterface->copyToStatsdAt()

[edit]

When StatsFactory is configured with an IBufferingStatsdDataFactory instance, metrics will be copied to the legacy interface at the provided namespace. Intended to ease the transition to metrics generated by this library. For example:

// assuming:
// $wgStatsFormat = 'statsd'
// $wgStatsPrefix = 'mediawiki'
// $wgStatsTarget = 'udp://new_statsd_server:8125
// $wgStatsdServer = 'old_statsd_server:8125'
// $wgStatsdMetricPrefix = 'mediawiki'

MediaWikiServices::getInstance()->getStatsFactory()
    ->getCounter( 'function_calls' )
    ->setLabel( 'name', 'my_function' )
    ->setLabel( 'namespace', 'Drafts' )
    ->copyToStatsdAt( 'legacy_namespace.my_function.calls' )
    ->increment();

would send to the new_statsd_server:

mediawiki.function_calls.my_function.Drafts

and to the old_statsd_server

mediawiki.legacy_namespace.my_function.calls

MetricInterface->setSampleRate()

[edit]

Configures the metric to emit a subset of samples recorded. Takes a float: 0.0 (sends 0% of samples) to 1.0 (sends 100% of samples). Note: sample rate must be configured prior to recording any samples otherwise an IllegalOperationException will be thrown. This can be encountered inadvertently because metrics pulled from cache may have samples already recorded.

Notes

[edit]

Cardinality

[edit]

High cardinality metrics present challenges for service operators and consumers of timeseries data. It is recommended to avoid using unbound values in labels or names.

Examples of high-cardinality data include:

  • IDs and UUIDs
  • Usernames
  • IP Addresses
  • User agents

Recommendations

[edit]

Labels

[edit]

For StatsD output, declaration of label order matters. Take care to declare labels in the order you would like them to appear. Label setting order does not matter when the Metric instance is pulled from cache.

Metrics

[edit]

The Observability team recommends following the guidance published by the Prometheus project. TL;DR: A metric:

  • should not use string interpolation to set the metric name
  • should not have label keys repeated in the metric name
  • must measure a single unit (i.e. do not mix seconds with milliseconds, or seconds with bytes, etc.)
  • should use base units (e.g. seconds, bytes, meters, etc.)
  • should have a suffix describing the unit in plural form. (i.e. _seconds, _bytes, _total, etc.)
  • must always have consistent label keys across all measurements.
  • should represent the same logical thing being measured across all label dimensions - sum() or avg() across all label dimensions should be meaningful.

Patterns

[edit]

Recursion

[edit]

Use of TimingMetric->start()|stop() helpers is unsupported in cases of recursion. When this is unavoidable, track the time separately:

$startTime = microtime( true );

# <do work>

$statsFactory->getTiming('foo')
    ->observe( ( microtime( true ) - $startTime ) * 1000 );  # expects ms

See also: phabricator:T368073

Developers

[edit]

Local Testing in Docker

[edit]

Add statsd-exporter service to docker-compose.override.yml:

services:
  statsd-exporter:
    ports:
      - "9112:9112"
    image: docker.io/prom/statsd-exporter:v0.22.2
    command: "--web.listen-address=:9112"

Configure LocalSettings.php:

# statsd-exporter target config
$wgStatsFormat = 'dogstatsd';
$wgStatsTarget = 'udp://statsd-exporter:9125';

Scrape the metrics endpoint:

$ watch 'curl -s localhost:9112/metrics| grep mediawiki_'

Note that the production statsd-exporter configuration may differ from the default set and make the metrics render differently, especially timing metrics. Please refer to the production statsd-exporter configuration to get the most accurate Prometheus metrics representation.