Organizing Metrics
App Metrics provides a two ways to organize your metrics:
- Through the use of Tags when declaring your metrics or by configuring tags globally for all Metrics.
- 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.