pulse-prometheus is a .NET library that implements the pulse interface and abstracts the C# prometheus-net library.
Abstracted metrics libraries are helpful in the event the underlying monitoring system changes. Whether the underlying monitoring library experiences breaking changes or you decide to do a complete swap of the underlying monitoring library, rest assured that you will only have to update the abstracted library and not your service code.
- Requirements
- Download
- Best Practices and Usage
- Quick Start
- Middleware Extensions
- Depedency Injection
- Metric Factory
- Counter
- Gauge
- Histogram
- Summary
- Tracking Operation Duration
- Counting In-Progress Operations
- Counting Exceptions
- Mutable Labels
- Immutable Labels
- Switching to a Different Metrics Library?
- Contributing
- Security
- Support
- License
pulse-prometheus is distributed via the NuGet gallery.
This library allows you to instrument your code with custom metrics. You are expected to be familiar with:
- Configure the endpoint. See Middleware Extensions.
- Register the IMetricFactory. See Dependency Injection. Optionally, create an IMetricFactory instead of injecting it.
- Use your IMetricFactory to create counters, gauges, histograms, and summaries.
- Use your metrics to do other cool things like track operation duration, count in-progress operations, and count exceptions. Also check out how to use mutable labels and immutable labels
Use metric middleware extensions to output metrics to an endpoint.
The default is /metrics
.
public class Startup
{
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
...
endpoints.MapMetrics();
});
}
...
}
Use IServiceCollection extensions to make it easy for consumers to register implementations for the included IMetricFactory.
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMetricFactory();
}
...
}
In subsequent code, request an implementation for the IMetricFactory by including it in the constructor of the classes which require it.
public class Example
{
private readonly pulseMetricFactory;
public Example(IMetricFactory metricFactory)
{
pulseMetricFactory = metricFactory;
}
public void TrackSomething()
{
var counter = pulseMetricFactory.CreateCounter("counter", "this is a counter metric");
using (counter.NewTimer())
{
Thread.Sleep(1000);
}
}
}
Create a metric factory as an entry point into the library, or use dependency injection.
private static readonly IMetricFactory MyAppMetricFactory = new PulseMetricFactory(new PrometheusMetricFactory());
Counters only increase in value and reset to zero when the process restarts.
private static readonly ICounter LogCounter =
MyAppMetricFactory.CreateCounter("myapp_number_of_logs_emitted", "Number of logs emitted.");
...
Log();
LogCounter.Increment();
Gauges can have any numeric value and change arbitrarily.
private static readonly IGauge JobQueueGauge =
MyAppMetricFactory.CreateGauge("myapp_jobs_queued", "Number of jobs queued.");
...
jobs.Enqueue(job);
JobQueueGauge.Increment();
...
jobs.Dequeue(job);
JobQueueGauge.Decrement();
Histograms track the size and number of events in buckets. This allows for aggregatable calculation over a set of buckets.
double[] buckets = new double[] { 100.0, 200.0, 300.0, 400.0, 500.0 }
private static readonly IHistogram OrderValueHistogram =
MyAppMetricFactory.CreateHistogram(
"myapp_order_value_usd",
"Histogram of received order values (in USD).",
new HistogramConfiguration()
{
Buckets = buckets
});
...
OrderValueHistogram.Observe(order.TotalValueUsd);
Summaries track events over time, with a default of 10 minutes.
private static readonly ISummary UploadSizeSummary =
MyAppMetricFactory.CreateSummary(
"myapp_upload_size_bytes",
"Summary of upload sizes (in bytes) over last 10 minutes.");
...
UploadSizeSummary.Observe(file.Length);
Timers can be used to report the duration of an operation (in seconds) to a Summary, Histogram, Gauge or Counter. Wrap the operation you want to measure in a using block.
double[] buckets = new double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
private static readonly IHistogram UploadDuration =
MyAppMetricFactory.CreateHistogram(
"myapp_upload_duration_seconds",
"Histogram of file upload durations.",
new HistogramConfiguration()
{
Buckets = buckets
});
...
using (UploadDuration.NewTimer())
{
Scheduler.Upload(file);
}
You can use Gauge.TrackInProgress()
to track how many concurrent operations are taking place. Wrap the operation you want to track in a using block.
private static readonly IGauge UploadsInProgress =
MyAppMetricFactory.CreateGauge(
"myapp_uploads_in_progress",
"Number of upload operations occuring.");
...
using (UploadsInProgress.TrackInProgress())
{
Scheduler.Upload(file);
}
You can use Counter.CountExceptions()
to count the number of exceptions that occur while executing some code.
private static readonly ICounter FailedExtractions =
MyAppMetricFactory.CreateCounter(
"myapp_extractions_failed_total",
"Number of extraction operations that failed.");
...
FailedExtractions.CountExceptions(() => Extractor.Extract(file));
You can also filter the exception types to observe:
FailedExtractions.CountExceptions(() => Extractor.Extract(file), IsExtractionRelatedException);
bool IsExtractionRelatedException(Exception ex)
{
return ex is ExtractionException; // Only count ExtractionExceptions.
}
All metrics can have mutable labels, allowing grouping of related time series.
See the best practices on naming and labels.
- Labels should contain a limited set of label values.
- URLs would be a bad choice. There are infinite options.
- HTTP response codes would be a good choice. There is a finite set of options.
Taking a counter as an example:
private static readonly ICounter HttpResponseCounter =
MyAppMetricFactory.CreateCounter(
"myapp_http_responses_total",
"Number of responses received by http method and response code.",
new CounterConfiguration()
{
MutableLabelNames = new string[] { "http_method", "http_response_code" }
});
...
// Specify the value(s) for the label(s) when you want to call a metric operation.
HttpResponseCounter.WithLabels("GET", "200").Inc();
You can add immutable labels that always have fixed values.
Taking a counter as an example with immutable labels and mutable labels:
Dictionary<string, string> immutableLabels = new Dictionary<string, string>() { { "service_name", "scheduler" } };
...
private static readonly ICounter HttpResponseCounter =
MyAppMetricFactory.CreateCounterWithStaticLabels(
"myapp_http_responses_received",
"Count of responses received, labelled by response code.",
new CounterConfiguration()
{
ImmutableLabels = immutableLabels
MutableLabelNames = new string[] { "http_response_code" }
});
...
// Labels applied to individual instances of the metric.
HttpResponseCounter.WithLabels("404").Inc();
HttpResponseCounter.WithLabels("200").Inc();
- All pulse-projects implement the pulse interface, meaning all pulse-projects are interchangable.
- If you need to change monitoring systems in the future, you can do so without having to change your projects code!
- If a pulse-project does not exist for the metric monitoring system you need to use, you can easily create one by implementing the pulse common interface.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines.
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.