App Metrics 1.0 Fork me on GitHub
Show / Hide Table of Contents

Organizing Metrics

App Metrics provides a two ways to organize your metrics:

  1. Through the use of Tags when declaring your metrics or by configuring tags globally for all Metrics.
  2. By specifing a Context label when declaring your metrics. By default any all custom Metrics will belong the the "Application" Context.

Metric Tagging

Metrics can be tagged when they are declared, these tags can then be shipped with your metric values to your database of choice which is useful for commonly-queried metadata.

An example use case for tagging is recording an APIs response time per endpoint where a timer is recorded per endpoint but then reported as the same metric name tagged with by the endpoint. This allows us to more easily have a dynamic list of endpoints and their response times when visualizing with Grafana for example.

Tagging at runtime

var tags = new MetricTags(new[] { "client_id", "route" }, new[] { clientId, routeTemplate });
metrics.Measure.Meter.Mark(OAuthRequestMetricsRegistry.Meters.RequestRate, tags);

Tagging globally

Tags can also be defined for all Metrics globally which is useful for tagging by things like machine name, environment, ip address, application name etc.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options => options.AddMetricsResourceFilter());
        
        services.AddMetrics(options => {
                options.DefaultContextLabel = "MyContext",                
                options.GlobalTags.Add("env", "stage");
                options.MetricsEnabled = true;
                options.ReportingEnabled = true;     	
            })
            .AddDefaultReservoir(() => new Lazy<IReservoir>(() => new DefaultSlidingWindowReservoir()))
            .AddJsonSerialization()
            .AddHealthChecks()
            .AddMetricsMiddleware();
    }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {	        
        app.UseMetrics();
    }
}

Default tags

App Metrics adds a few default global tags which are commonly used. These are as follows:

Tag Description
app The name of the application, which is set to the entry assembly name of the application i.e. Assembly.GetEntryAssembly().GetName().Name.
server The name of the machine the application is currently running on i.e. Environment.MachineName.
env The environment the application is running in. When running in debug mode will be set to debug otherwise release. This can be adjusted to be staging, production etc via app settings, via the tagging helpers or disabled setting the AppMetricsOptions.AddDefaultGlobalTags to false.

Tagging helpers

App Metrics provides an extension method on the AppMetricsOptions delegate passing some environment information that can be used to set global tags such as the machine name, assembly version etc.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMetrics(options => {
                options.DefaultContextLabel = "MyContext";
                options.WithGlobalTags((globalTags, envInfo) =>
                {                    
                    globalTags.Add("server", envInfo.MachineName);
                    globalTags.Add("app", envInfo.EntryAssemblyName);
                    // Assumes _env is the IHostingEnvironment
                    globalTags.Add("env", _env.IsStaging() ? "stage" : _env.IsProduction() ? "prod" : "dev");
                });  	
            })
            .AddJsonSerialization()
            .AddHealthChecks()
            .AddMetricsMiddleware();
    }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {	        
        app.UseMetrics();
    }
}

Tagging statically

public static class AppMetricsRegistery
{
    public static class ProcessMetrics
    {
        private static readonly MetricTags CustomTags = new MetricTags("tag-key", "tag-value");
        private static readonly string ContextName = "Process";

        public static GaugeOptions SystemNonPagedMemoryGauge = new GaugeOptions
        {
            Context = ContextName,
            Name = "System Non-Paged Memory",
            MeasurementUnit = Unit.Bytes,
            Tags = CustomTags
        };            

        public static GaugeOptions ProcessVirtualMemorySizeGauge = new GaugeOptions
        {
            Context = ContextName,
            Name = "Process Virtual Memory Size",
            MeasurementUnit = Unit.Bytes,
            Tags = CustomTags
        };
    }

    public static class DatabaseMetrics
    {
        private static readonly string ContextName = "Database";

        public static TimerOptions SearchUsersSqlTimer = new TimerOptions
        {
            Context = ContextName,
            Name = "Search Users",
            MeasurementUnit = Unit.Calls
        };
    }
}

Metric Contexts

Organizing your Metrics into separate meaningful contexts is helpful for visualization and reporting. Only one level of Context categorization is supported.

The default global context can be modified using the DefaultContextLabel in the configuration options when configuring your application to use App Metrics.

Defining a Context on a Metric

To add Metrics to a particular context, the context can be specified when declaring your metrics. For example:

public static class AppMetricsRegistery
{
    public static class ProcessMetrics
    {
        private static readonly MetricTags CustomTags = new MetricTags("tag-key", "tag-value");
        private static readonly string ContextName = "Process";

        public static GaugeOptions SystemNonPagedMemoryGauge = new GaugeOptions
        {
            Context = ContextName,
            Name = "System Non-Paged Memory",
            MeasurementUnit = Unit.Bytes,
            Tags = CustomTags
        };            

        public static GaugeOptions ProcessVirtualMemorySizeGauge = new GaugeOptions
        {
            Context = ContextName,
            Name = "Process Virtual Memory Size",
            MeasurementUnit = Unit.Bytes,
            Tags = CustomTags
        };
    }

    public static class DatabaseMetrics
    {
        private static readonly string ContextName = "Database";

        public static TimerOptions SearchUsersSqlTimer = new TimerOptions
        {
            Context = ContextName,
            Name = "Search Users",
            MeasurementUnit = Unit.Calls
        };
    }
}

Filtering in process by Context

The DefaultMetricsFilter can be used to filter Metrics by a Context. This would be useful if we only wanted to report on a particular Metrics Context.

Note

See Metrics Filtering for more details on filtering Metrics.

Viewing from a Web Host

Below is a snippet from a /metrics response generated by a web host using the App.Metrics.Extensions.Middleware nuget package (Note: Metric values have been omitted for brevity).

{
  "contexts": [
    {
      "context": "Application",
      "counters": [],
      "meters": [],
      "timers": []
    },
    {
      "context": "Application.HttpRequests",
      "counters": [],
      "gauges": [],
      "histograms": [],
      "meters": [],
      "timers": []
    },
    {
      "context": "Application.OAuth2Client.HttpRequests",
      "counters": [],
      "gauges": [],
      "histograms": [],
      "meters": [],
      "timers": []
    },
    {
      "context": "Database",
      "counters": [],
      "meters": [],
      "timers": []
    }
  ],
  "environment": { },
  "timestamp": "",
  "version": "1"
}
Note

You'll need to install the App.Metrics.Formatters.Json nuget package and AddJsonSerialization() in your Startup.cs for formatting /metrics results as json.

Filtering in process by Tag Keys

The DefaultMetricsFilter can be used to filter Metrics by a Tag Keys. This would be useful if we only wanted to report on a particular Metrics Tags.

Note

See Metrics Filtering for more details on filtering Metrics.

  • Edit this Doc
Back to top Copyright © 2017 Allan Hardy
Generated by DocFX