Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

337 Commits

Repository files navigation

StackExchange.Metrics

Build status

A thread-safe C# .NET client for reporting metrics to various providers, including Bosun (Time Series Alerting Framework) and SignalFx. This library is more than a simple wrapper around relevant APIs. It is designed to encourage best-practices while making it easy to create counters and gauges, including multi-aggregate gauges. It automatically reports metrics on an interval and handles temporary API or network outages using a re-try queue.

VIEW CHANGES IN StackExchange.Metrics 2.0

Package Status

MyGet Pre-release feed: https://www.myget.org/gallery/stackoverflow

PackageNuGet StableNuGet Pre-releaseDownloadsMyGet
StackExchange.MetricsStackExchange.MetricsStackExchange.MetricsStackExchange.MetricsStackExchange.Metrics MyGet

Basic Usage

.NET Full Framework

First, create a MetricsCollector object. This is the top-level container which will hold all of your metrics and handle sending them to various metric endpoints. Therefore, you should only instantiate one, and make it a global singleton.

publicclassAppMetricSource:MetricSource{publicstaticreadonlyMetricSourceOptionsOptions=newMetricSourceOptions{DefaultTags={["host"]=Environment.MachineName}};publicAppMetricSource():base(Options){}}varcollector=newMetricsCollector(newMetricsCollectorOptions{ExceptionHandler= ex =>HandleException(ex),Endpoints=new[]{newMetricEndpoint("Bosun",newBosunMetricHandler(newUri("http://bosun.mydomain.com:8070"))),newMetricEndpoint("SignalFx",newSignalFxMetricHandler(newUri("https://mydomain.signalfx.com/api","API_KEY"))),},Sources=new[]{newGarbageCollectorMetricSource(AppMetricSource.DefaultOptions),newProcessMetricSource(AppMetricSource.DefaultOptions),newAppMetricSource()}});// start the collector; it'll start sending metricscollector.Start();// ...// and then, during application shutdown, stop the collectorcollector.Stop();

.NET Core

For .NET Core, you can configure a MetricsCollector in your Startup.cs.

Using the snippet below will register an IHostedService in the service collection that manages the lifetime of the MetricsCollector and configures it with the specified endpoints and metric sources.

publicclassAppMetricSource:MetricSource{publicAppMetricSource(MetricSourceOptionsoptions):base(options){}}publicclassStartup{publicvoidConfigureServices(IServiceCollectionservices){services.AddMetricsCollector()// configure things like default tags.ConfigureSources(
o =>{// NOTE: default tags include the host name by defaultp.DefaultTags.Add("tier","dev");})// add common metric sources// that includes ProcessMetricSource, AspNetMetricSource & RuntimeMetricSource.AddDefaultSources()// and then add our application-specific metric source.AddSource<AppMetricSource>()// add endpoints we care about. By default we add a `LocalMetricHandler` that // just maintains the latest metrics in memory (useful for debugging).AddBosunEndpoint(newUri("http://bosun.mydomain.com:8070")).AddSignalFxEndpoint(newUri("https://mydomain.signalfx.com/api","API_KEY")).UseExceptionHandler(ex =>HandleException(ex))// tweak other options in of `MetricsCollectionOptions`.Configure(
o =>{o.SnapshotInterval=TimeSpan.FromSeconds(5);})}}

All of the available options are documented in the MetricCollectorOptions class or the individual metric handlers:

Metrics are configured in a MetricSource. Using our AppMetricSource above:

Create a counter with only the default tags:

publicclassAppMetricSource:MetricSource{publicCounterMyCounter{get;}publicAppMetricSource(MetricSourceOptionsoptions):base(options){MyCounter=AddCounter("my_counter","units","description");}}

Increment the counter by 1:

appSource.MyCounter.Increment();

Using Tags

Tags are used to subdivide data in various metric platforms. In StackExchange.Metrics, tags are by specifying additional arguments when creating a metric. For example:

publicclassAppMetricSource:MetricSource{publicCounter<string>MyCounterWithTag{get;}publicAppMetricSource(MetricSourceOptionsoptions):base(options){MyCounterWithTag=AddCounter("my_counter","units","description",newMetricTag<string>("some_tag"));}}

Incrementing that counter works exactly the same as incrementing a counter without tags, but we need to specify the values:

appSource.MyCounter.Increment("tag_value");

For more details, see the Tags Documentation.

Metric Types

There are two high-level metric types: counters and gauges.

Counters are for counting things. The most common use case is to increment a counter each time an event occurs. Many metric platforms normalize this data and is able to show you a rate (events per second) in the graphing interface. StackExchange.Metrics has two built-in counter types.

NameDescription
CounterA general-purpose manually incremented long-integer counter.
SnapshotCounterCalls a user-provided Func<long?> to get the current counter value each time metrics are going to be posted to a metric handler.
CumulativeCounterA persistent counter (no resets) for very low-volume events.

Gauges describe a measurement at a point in time. A good example would be measuring how much RAM is being consumed by a process. StackExchange.Metrics provides several different built-in types of gauges in order to support different programmatic use cases.

NameDescription
SnapshotGaugeSimilar to a SnapshotCounter, it calls a user provided Func<double?> to get the current gauge value each time metrics are going to be posted to the metrics handlers.
EventGaugeEvery data point is sent to the metrics handlers. Good for low-volume events.
AggregateGaugeAggregates data points (min, max, avg, median, etc) before sending them to the metrics handlers. Good for recording high-volume events.
SamplingGaugeRecord as often as you want, but only the last value recorded before the reporting interval is sent to the metrics handlers (it samples the current value).

If none of the built-in metric types meet your specific needs, it's easy to create your own.

Metric Sources

Metric sets are pre-packaged sources of metrics that are useful across different applications. See Documentation for further details.

Implementation Notes

Periodically a MetricsCollector instance serializes all the metrics from the sources attached to it. When it does so it serially calls WriteReadings on each metric. WriteValue uses an IMetricBatch to assist in writing metrics into an endpoint-defined format using an implementation of IBufferWriter<byte> for buffering purposes.

For each type of payload that can be sent to an endpoint an IBufferWriter<byte> is created that manages an underlying buffer consisting of zero or more contiguous byte arrays.

At a specific interval the MetricsCollector flushes all metrics that have been serialized into the IBufferWriter<byte> to the underlying transport implemented by an endpoint (generally an HTTP JSON API or statsd UDP endpoint). Once flushed the associated buffer is released back to be used by the next batch of metrics being serialized. This keeps memory allocations low.

About

A .NET client to send metrics to a variety of metrics backends

Resources

Stars

135 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages