{"id":13430188,"url":"https://github.com/prometheus-net/prometheus-net","last_synced_at":"2025-05-13T17:14:31.867Z","repository":{"id":29346975,"uuid":"32881114","full_name":"prometheus-net/prometheus-net","owner":"prometheus-net","description":".NET library to instrument your code with Prometheus metrics","archived":false,"fork":false,"pushed_at":"2024-04-11T13:14:54.000Z","size":3367,"stargazers_count":2028,"open_issues_count":136,"forks_count":308,"subscribers_count":31,"default_branch":"master","last_synced_at":"2025-05-11T18:03:27.768Z","etag":null,"topics":["aspnetcore","grpc","grpc-request-metrics","healthchecks","httpclientfactory","metrics","monitoring","net-standard","performance-metrics","performance-monitor","prometheus"],"latest_commit_sha":null,"homepage":"https://prometheus.io","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prometheus-net.png","metadata":{"files":{"readme":"README.md","changelog":"History","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["sandersaares"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2015-03-25T17:48:51.000Z","updated_at":"2025-05-08T07:52:56.000Z","dependencies_parsed_at":"2023-01-16T22:30:37.831Z","dependency_job_id":"df5ee5ee-cb17-44bd-b0d1-6abbab324aac","html_url":"https://github.com/prometheus-net/prometheus-net","commit_stats":{"total_commits":686,"total_committers":66,"mean_commits":"10.393939393939394","dds":0.6516034985422741,"last_synced_commit":"a055f5bdfccd7bc298bc1f726c481f1f4c36b54c"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prometheus-net%2Fprometheus-net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prometheus-net%2Fprometheus-net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prometheus-net%2Fprometheus-net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prometheus-net%2Fprometheus-net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prometheus-net","download_url":"https://codeload.github.com/prometheus-net/prometheus-net/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253609633,"owners_count":21935560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","grpc","grpc-request-metrics","healthchecks","httpclientfactory","metrics","monitoring","net-standard","performance-metrics","performance-monitor","prometheus"],"created_at":"2024-07-31T02:00:50.907Z","updated_at":"2025-05-13T17:14:26.852Z","avatar_url":"https://github.com/prometheus-net.png","language":"C#","funding_links":["https://github.com/sponsors/sandersaares"],"categories":["Frameworks, Libraries and Tools","C# #","Libraries","C\\#","框架, 库和工具","Code Analysis and Metrics"],"sub_categories":["Code Analysis and Metrics","Profling, Tracing, and Metrics","代码分析和指标"],"readme":"# prometheus-net\n\nThis is a .NET library for instrumenting your applications and exporting metrics to [Prometheus](http://prometheus.io/).\n\n[![Build status](https://dev.azure.com/prometheus-net/prometheus-net/_apis/build/status/prometheus-net)](https://dev.azure.com/prometheus-net/prometheus-net/_build/latest?definitionId=1) [![Nuget](https://img.shields.io/nuget/v/prometheus-net.svg)](https://www.nuget.org/packages/prometheus-net/) ![Nuget](https://img.shields.io/nuget/dt/prometheus-net.svg)\n\n![](Screenshot.png)\n\nThe library targets the following runtimes (and newer):\n\n* .NET Framework 4.6.2\n* .NET 6.0\n\n# Table of contents\n\n* [Best practices and usage](#best-practices-and-usage)\n* [Quick start](#quick-start)\n* [Installation](#installation)\n* [Counters](#counters)\n* [Gauges](#gauges)\n* [Histogram](#histogram)\n* [Summary](#summary)\n* [Measuring operation duration](#measuring-operation-duration)\n* [Tracking in-progress operations](#tracking-in-progress-operations)\n* [Counting exceptions](#counting-exceptions)\n* [Labels](#labels)\n* [Static labels](#static-labels)\n* [Exemplars](#exemplars)\n* [Limiting exemplar volume](#limiting-exemplar-volume)\n* [When are metrics published?](#when-are-metrics-published)\n* [Deleting metrics](#deleting-metrics)\n* [ASP.NET Core exporter middleware](#aspnet-core-exporter-middleware)\n* [ASP.NET Core HTTP request metrics](#aspnet-core-http-request-metrics)\n* [ASP.NET Core gRPC request metrics](#aspnet-core-grpc-request-metrics)\n* [IHttpClientFactory metrics](#ihttpclientfactory-metrics)\n* [ASP.NET Core health check status metrics](#aspnet-core-health-check-status-metrics)\n* [Protecting the metrics endpoint from unauthorized access](#protecting-the-metrics-endpoint-from-unauthorized-access)\n* [ASP.NET Web API exporter](#aspnet-web-api-exporter)\n* [Kestrel stand-alone server](#kestrel-stand-alone-server)\n* [Publishing to Pushgateway](#publishing-to-pushgateway)\n* [Publishing to Pushgateway with basic authentication](#publishing-to-pushgateway-with-basic-authentication)\n* [Publishing via standalone HTTP handler](#publishing-via-standalone-http-handler)\n* [Publishing raw metrics document](#publishing-raw-metrics-document)\n* [Just-in-time updates](#just-in-time-updates)\n* [Suppressing default metrics](#suppressing-default-metrics)\n* [DiagnosticSource integration](#diagnosticsource-integration)\n* [EventCounter integration](#eventcounter-integration)\n* [.NET Meters integration](#net-meters-integration)\n* [Benchmarks](#benchmarks)\n* [Community projects](#community-projects)\n\n# Best practices and usage\n\nThis library allows you to instrument your code with custom metrics and provides some built-in metric collection integrations for ASP.NET Core.\n\nThe documentation here is only a minimal quick start. For detailed guidance on using Prometheus in your solutions, refer to the [prometheus-users discussion group](https://groups.google.com/forum/#!forum/prometheus-users). You are also expected to be familiar with the [Prometheus user guide](https://prometheus.io/docs/introduction/overview/). [/r/PrometheusMonitoring](https://www.reddit.com/r/PrometheusMonitoring/) on Reddit may also prove a helpful resource.\n\nFour types of metrics are available: Counter, Gauge, Summary and Histogram. See the documentation on [metric types](http://prometheus.io/docs/concepts/metric_types/) and [instrumentation best practices](http://prometheus.io/docs/practices/instrumentation/#counter-vs.-gauge-vs.-summary) to learn what each is good for.\n\n**The `Metrics` class is the main entry point to the API of this library.** The most common practice in C# code is to have a `static readonly` field for each metric that you wish to export from a given class.\n\nMore complex patterns may also be used (e.g. combining with dependency injection). The library is quite tolerant of different usage models - if the API allows it, it will generally work fine and provide satisfactory performance. The library is thread-safe.\n\n# Quick start\n\nAfter installing the library, you should:\n\n1. Collect some metrics, either by using built-in integrations or publishing your own custom metrics.\n1. Export the collected metrics over an HTTP endpoint (typically `/metrics`).\n1. Configure a Prometheus server to poll this endpoint for metrics on a regular interval.\n\nMinimal sample app (based on .NET 6 Console app template):\n\n```csharp\nusing var server = new Prometheus.KestrelMetricServer(port: 1234);\nserver.Start();\n\nConsole.WriteLine(\"Open http://localhost:1234/metrics in a web browser.\");\nConsole.WriteLine(\"Press enter to exit.\");\nConsole.ReadLine();\n```\n\nRefer to the sample projects for quick start instructions:\n\n| Name                                                                  | Description                                                                                                           |\n|-----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|\n| [Sample.Web](Sample.Web/Program.cs)                                   | ASP.NET Core application that produces custom metrics and uses multiple integrations to publish built-in metrics      |\n| [Sample.Console](Sample.Console/Program.cs)                           | .NET console application that exports custom metrics                                                                  |\n| [Sample.Console.DotNetMeters](Sample.Console.DotNetMeters/Program.cs) | Demonstrates how to [publish custom metrics via the .NET Meters API](#net-meters-integration)                         |\n| [Sample.Console.Exemplars](Sample.Console.Exemplars/Program.cs)       | .NET console application that attaches exemplars to some metrics                                                      |\n| [Sample.Console.NetFramework](Sample.Console.NetFramework/Program.cs) | Same as above but targeting .NET Framework                                                                            |\n| [Sample.Console.NoAspNetCore](Sample.Console.NoAspNetCore/Program.cs) | .NET console application that exports custom metrics without requiring the ASP.NET Core runtime to be installed       |\n| [Sample.Grpc](Sample.Grpc/Program.cs)                                 | ASP.NET Core application that publishes a gRPC service                                                                |\n| [Sample.Grpc.Client](Sample.Grpc.Client/Program.cs)                   | Client app for the above                                                                                              |\n| [Sample.NetStandard](Sample.NetStandard/ImportantProcess.cs)          | Demonstrates how to reference prometheus-net in a .NET Standard class library                                         |\n| [Sample.Web.DifferentPort](Sample.Web.DifferentPort/Program.cs)       | Demonstrates how to set up the metric exporter on a different port from the main web API (e.g. for security purposes) |\n| [Sample.Web.MetricExpiration](Sample.Web.MetricExpiration/Program.cs) | Demonstrates how to use [automatic metric deletion](#deleting-metrics)                                                |\n| [Sample.Web.NetFramework](Sample.Web.NetFramework/Global.asax.cs)     | .NET Framework web app that publishes custom metrics                                                                  |\n\nThe rest of this document describes how to use individual features of the library.\n\n# Installation\n\nNuget package for general use and metrics export via HttpListener or to Pushgateway: [prometheus-net](https://www.nuget.org/packages/prometheus-net)\n\n\u003eInstall-Package prometheus-net\n\nNuget package for ASP.NET Core middleware and stand-alone Kestrel metrics server: [prometheus-net.AspNetCore](https://www.nuget.org/packages/prometheus-net.AspNetCore)\n\n\u003eInstall-Package prometheus-net.AspNetCore\n\nNuget package for ASP.NET Core Health Check integration: [prometheus-net.AspNetCore.HealthChecks](https://www.nuget.org/packages/prometheus-net.AspNetCore.HealthChecks)\n\n\u003eInstall-Package prometheus-net.AspNetCore.HealthChecks\n\nNuget package for ASP.NET Core gRPC integration: [prometheus-net.AspNetCore.Grpc](https://www.nuget.org/packages/prometheus-net.AspNetCore.Grpc)\n\n\u003eInstall-Package prometheus-net.AspNetCore.Grpc\n\nNuget package for ASP.NET Web API middleware on .NET Framework: [prometheus-net.NetFramework.AspNet](https://www.nuget.org/packages/prometheus-net.NetFramework.AspNet)\n\n\u003eInstall-Package prometheus-net.NetFramework.AspNet\n\n# Counters\n\nCounters only increase in value and reset to zero when the process restarts.\n\n```csharp\nprivate static readonly Counter ProcessedJobCount = Metrics\n    .CreateCounter(\"myapp_jobs_processed_total\", \"Number of processed jobs.\");\n\n...\n\nProcessJob();\nProcessedJobCount.Inc();\n```\n\n# Gauges\n\nGauges can have any numeric value and change arbitrarily.\n\n```csharp\nprivate static readonly Gauge JobsInQueue = Metrics\n    .CreateGauge(\"myapp_jobs_queued\", \"Number of jobs waiting for processing in the queue.\");\n\n...\n\njobQueue.Enqueue(job);\nJobsInQueue.Inc();\n\n...\n\nvar job = jobQueue.Dequeue();\nJobsInQueue.Dec();\n```\n\n# Histogram\n\nHistograms track the size and number of events in buckets. This allows for aggregatable calculation of quantiles.\n\n```csharp\nprivate static readonly Histogram OrderValueHistogram = Metrics\n    .CreateHistogram(\"myapp_order_value_usd\", \"Histogram of received order values (in USD).\",\n        new HistogramConfiguration\n        {\n            // We divide measurements in 10 buckets of $100 each, up to $1000.\n            Buckets = Histogram.LinearBuckets(start: 100, width: 100, count: 10)\n        });\n\n...\n\nOrderValueHistogram.Observe(order.TotalValueUsd);\n```\n\n# Summary\n\nSummaries track the trends in events over time (10 minutes by default).\n\n```csharp\nprivate static readonly Summary RequestSizeSummary = Metrics\n    .CreateSummary(\"myapp_request_size_bytes\", \"Summary of request sizes (in bytes) over last 10 minutes.\");\n\n...\n\nRequestSizeSummary.Observe(request.Length);\n```\n\nBy default, only the sum and total count are reported. You may also specify quantiles to measure:\n\n```csharp\nprivate static readonly Summary RequestSizeSummary = Metrics\n    .CreateSummary(\"myapp_request_size_bytes\", \"Summary of request sizes (in bytes) over last 10 minutes.\",\n        new SummaryConfiguration\n        {\n            Objectives = new[]\n            {\n                new QuantileEpsilonPair(0.5, 0.05),\n                new QuantileEpsilonPair(0.9, 0.05),\n                new QuantileEpsilonPair(0.95, 0.01),\n                new QuantileEpsilonPair(0.99, 0.005),\n            }\n        });\n```\n\nThe epsilon indicates the absolute error allowed in measurements. For more information, refer to the [Prometheus documentation on summaries and histograms](https://prometheus.io/docs/practices/histograms/).\n\n# Measuring operation duration\n\nTimers 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.\n\n```csharp\nprivate static readonly Histogram LoginDuration = Metrics\n    .CreateHistogram(\"myapp_login_duration_seconds\", \"Histogram of login call processing durations.\");\n\n...\n\nusing (LoginDuration.NewTimer())\n{\n    IdentityManager.AuthenticateUser(Request.Credentials);\n}\n```\n\n# Tracking in-progress operations\n\nYou can use `Gauge.TrackInProgress()` to track how many concurrent operations are taking place. Wrap the operation you want to track in a using block.\n\n```csharp\nprivate static readonly Gauge DocumentImportsInProgress = Metrics\n    .CreateGauge(\"myapp_document_imports_in_progress\", \"Number of import operations ongoing.\");\n\n...\n\nusing (DocumentImportsInProgress.TrackInProgress())\n{\n    DocumentRepository.ImportDocument(path);\n}\n```\n\n# Counting exceptions\n\nYou can use `Counter.CountExceptions()` to count the number of exceptions that occur while executing some code.\n\n\n```csharp\nprivate static readonly Counter FailedDocumentImports = Metrics\n    .CreateCounter(\"myapp_document_imports_failed_total\", \"Number of import operations that failed.\");\n\n...\n\nFailedDocumentImports.CountExceptions(() =\u003e DocumentRepository.ImportDocument(path));\n```\n\nYou can also filter the exception types to observe:\n\n```csharp\nFailedDocumentImports.CountExceptions(() =\u003e DocumentRepository.ImportDocument(path), IsImportRelatedException);\n\nbool IsImportRelatedException(Exception ex)\n{\n    // Do not count \"access denied\" exceptions - those are user error for pointing us to a forbidden file.\n    if (ex is UnauthorizedAccessException)\n        return false;\n\n    return true;\n}\n```\n\n# Labels\n\nAll metrics can have labels, allowing grouping of related time series.\n\nSee the best practices on [naming](http://prometheus.io/docs/practices/naming/)\nand [labels](http://prometheus.io/docs/practices/instrumentation/#use-labels).\n\nTaking a counter as an example:\n\n```csharp\nprivate static readonly Counter RequestCountByMethod = Metrics\n    .CreateCounter(\"myapp_requests_total\", \"Number of requests received, by HTTP method.\", labelNames: new[] { \"method\" });\n\n...\n\n// You can specify the values for the labels later, once you know the right values (e.g in your request handler code).\nRequestCountByMethod.WithLabels(\"GET\").Inc();\n```\n\nNB! Best practices of metric design is to **minimize the number of different label values**. For example:\n\n* HTTP request method is a good choice for labeling - there are not many values.\n* URL is a bad choice for labeling - it has many possible values and would lead to significant data processing inefficiency.\n\n# Static labels\n\nYou can add static labels that always have fixed values. This is possible on two levels:\n\n* on the metrics registry (e.g. `Metrics.DefaultRegistry`)\n* on a metric factory (e.g. `Metrics.WithLabels()`)\n\nAll levels of labeling can be combined and instance-specific metric labels can also be applied on top, as usual.\n\nExample with static labels on two levels and one instance-specific label:\n\n```csharp\nMetrics.DefaultRegistry.SetStaticLabels(new Dictionary\u003cstring, string\u003e\n{\n  // Labels applied to all metrics in the registry.\n  { \"environment\", \"testing\" }\n});\n\nvar backgroundServicesMetricFactory = Metrics.WithLabels(new Dictionary\u003cstring, string\u003e\n{\n  // Labels applied to all metrics created via this factory.\n  { \"category\", \"background-services\" }\n});\n\nvar requestsHandled = backgroundServicesMetricFactory\n  .CreateCounter(\"myapp_requests_handled_total\", \"Count of requests handled, labelled by response code.\", labelNames: new[] { \"response_code\" });\n\n// Labels applied to individual instances of the metric.\nrequestsHandled.WithLabels(\"404\").Inc();\nrequestsHandled.WithLabels(\"200\").Inc();\n```\n\n# Exemplars\n\nExemplars facilitate [distributed tracing](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-concepts), by attaching related trace IDs to metrics. This enables a metrics visualization app to cross-reference [traces](https://opentelemetry.io/docs/concepts/signals/traces/) that explain how the metric got the value it has.\n\n![](Exemplars.png)\n\nSee also, [Grafana fundamentals - introduction to exemplars](https://grafana.com/docs/grafana/latest/fundamentals/exemplars/).\n\nBy default, prometheus-net will create an exemplar with the `trace_id` and `span_id` labels based on the current distributed tracing context (`Activity.Current`). If using OpenTelemetry tracing with ASP.NET Core, the `traceparent` HTTP request header will be used to automatically assign `Activity.Current`.\n\n```csharp\nprivate static readonly Counter TotalSleepTime = Metrics\n    .CreateCounter(\"sample_sleep_seconds_total\", \"Total amount of time spent sleeping.\");\n...\n\n// You only need to create the Activity if one is not automatically assigned (e.g. by ASP.NET Core).\nusing (var activity = new Activity(\"Pausing before record processing\").Start())\n{\n    var sleepStopwatch = Stopwatch.StartNew();\n    await Task.Delay(TimeSpan.FromSeconds(1));\n\n    // The trace_id and span_id from the current Activity are exposed as the exemplar.\n    TotalSleepTime.Inc(sleepStopwatch.Elapsed.TotalSeconds);\n}\n```\n\nThis will be published as the following metric point:\n\n```\nsample_sleep_seconds_total 251.03833569999986 # {trace_id=\"08ad1c8cec52bf5284538abae7e6d26a\",span_id=\"4761a4918922879b\"} 1.0010688 1672634812.125\n```\n\nYou can override any default exemplar logic by providing your own exemplar when updating the value of the metric:\n\n```csharp\nprivate static readonly Counter RecordsProcessed = Metrics\n    .CreateCounter(\"sample_records_processed_total\", \"Total number of records processed.\");\n\n// The key from an exemplar key-value pair should be created once and reused to minimize memory allocations.\nprivate static readonly Exemplar.LabelKey RecordIdKey = Exemplar.Key(\"record_id\");\n...\n\nforeach (var record in recordsToProcess)\n{\n    var exemplar = Exemplar.From(RecordIdKey.WithValue(record.Id.ToString()));\n    RecordsProcessed.Inc(exemplar);\n}\n```\n\n\u003e **Warning**\n\u003e Exemplars are limited to 128 ASCII characters (counting both keys and values) - they are meant to contain IDs for cross-referencing with trace databases, not as a replacement for trace databases.\n\nExemplars are only published if the metrics are being scraped by an OpenMetrics-capable client. For development purposes, you can force the library to use the OpenMetrics exposition format by adding `?accept=application/openmetrics-text` to the `/metrics` URL.\n\n\u003e **Note**\n\u003e The Prometheus database automatically negotiates OpenMetrics support when scraping metrics - you do not need to apply any special scraping configuration in production scenarios. You may need to [enable exemplar storage](https://prometheus.io/docs/prometheus/latest/feature_flags/#exemplars-storage), though.\n\nSee also, [Sample.Console.Exemplars](Sample.Console.Exemplars/Program.cs).\n\n# Limiting exemplar volume\n\nExemplars can be expensive to store in the metrics database. For this reason, it can be useful to only record exemplars for \"interesting\" metric values.\n\nYou can use `ExemplarBehavior.NewExemplarMinInterval` to define a minimum interval between exemplars - a new exemplar will only be recorded if this much time has passed. This can be useful to limit the rate of publishing unique exemplars.\n\nYou can customize the default exemplar provider via `IMetricFactory.ExemplarBehavior` or `CounterConfiguration.ExemplarBehavior` and `HistogramConfiguration.ExemplarBehavior`, which allows you to provide your own method to generate exemplars and to filter which values/metrics exemplars are recorded for:\n\nExample of a custom exemplar provider used together with exemplar rate limiting:\n\n```csharp\n// For the next histogram we only want to record exemplars for values larger than 0.1 (i.e. when record processing goes slowly).\nstatic Exemplar RecordExemplarForSlowRecordProcessingDuration(Collector metric, double value)\n{\n    if (value \u003c 0.1)\n        return Exemplar.None;\n\n    return Exemplar.FromTraceContext();\n}\n\nvar recordProcessingDuration = Metrics\n    .CreateHistogram(\"sample_record_processing_duration_seconds\", \"How long it took to process a record, in seconds.\",\n    new HistogramConfiguration\n    {\n        Buckets = Histogram.PowersOfTenDividedBuckets(-4, 1, 5),\n        ExemplarBehavior = new()\n        {\n            DefaultExemplarProvider = RecordExemplarForSlowRecordProcessingDuration,\n            // Even if we have interesting data more often, do not record it to conserve exemplar storage.\n            NewExemplarMinInterval = TimeSpan.FromMinutes(5)\n        }\n    });\n```\n\nFor the ASP.NET Core HTTP server metrics, you can further fine-tune exemplar recording by inspecting the HTTP request and response:\n\n```csharp\napp.UseHttpMetrics(options =\u003e\n{\n    options.ConfigureMeasurements(measurementOptions =\u003e\n    {\n        // Only measure exemplar if the HTTP response status code is not \"OK\".\n        measurementOptions.ExemplarPredicate = context =\u003e context.Response.StatusCode != HttpStatusCode.Ok;\n    });\n});\n```\n\n# When are metrics published?\n\nMetrics without labels are published immediately after the `Metrics.CreateX()` call. Metrics that use labels are published when you provide the label values for the first time.\n\nSometimes you want to delay publishing a metric until you have loaded some data and have a meaningful value to supply for it. The API allows you to suppress publishing of the initial value until you decide the time is right.\n\n```csharp\nprivate static readonly Gauge UsersLoggedIn = Metrics\n    .CreateGauge(\"myapp_users_logged_in\", \"Number of active user sessions\",\n        new GaugeConfiguration\n        {\n            SuppressInitialValue = true\n        });\n\n...\n\n// After setting the value for the first time, the metric becomes published.\nUsersLoggedIn.Set(LoadSessions().Count);\n```\n\nYou can also use `.Publish()` on a metric to mark it as ready to be published without modifying the initial value (e.g. to publish a zero). Conversely, you can use `.Unpublish()` to hide a metric temporarily. Note that the metric remains in memory and retains its value.\n\n# Deleting metrics\n\nYou can use `.Dispose()` or `.RemoveLabelled()` methods on the metric classes to manually delete metrics at any time.\n\nIn some situations, it can be hard to determine when a metric with a specific set of labels becomes irrelevant and needs to be removed. The library provides some assistance here by enabling automatic expiration of metrics when they are no longer used.\n\nTo enable automatic expiration, create the metrics via the metric factory returned by `Metrics.WithManagedLifetime()`. All such metrics will have a fixed expiration time, with the expiration restarting based on certain conditions that indicate the metric is in use.\n\nOption 1: metric lifetime can be controlled by leases - the metric expiration timer starts when the last lease is released (and will be reset when a new lease is taken again).\n\n```csharp\nvar factory = Metrics.WithManagedLifetime(expiresAfter: TimeSpan.FromMinutes(5));\n\n// With expiring metrics, we get back handles to the metric, not the metric directly.\nvar inProgressHandle = expiringMetricFactory\n  .CreateGauge(\"documents_in_progress\", \"Number of documents currently being processed.\",\n    // Automatic metric deletion only makes sense if we have a high/unknown cardinality label set,\n    // so here is a sample label for each \"document provider\", whoever that may be.\n    labelNames: new[] { \"document_provider\" });\n\n...\n\npublic void ProcessDocument(string documentProvider)\n{\n  // Automatic metric deletion will not occur while this lease is held.\n  // This will also reset any existing expiration timer for this document provider.\n  inProgressHandle.WithLease(metric =\u003e\n  {\n    using (metric.TrackInProgress())\n      DoDocumentProcessingWork();\n  }, documentProvider);\n  // Lease is released here.\n  // If this was the last lease for this document provider, the expiration timer will now start.\n}\n```\n\nScenario 2: sometimes managing the leases is not required because you simply want the metric lifetime to be extended whenever the value is updated.\n\n```csharp\nvar factory = Metrics.WithManagedLifetime(expiresAfter: TimeSpan.FromMinutes(5));\n\n// With expiring metrics, we get back handles to the metric, not the metric directly.\nvar processingStartedHandle = expiringMetricFactory\n  .CreateGauge(\"documents_started_processing_total\", \"Number of documents for which processing has started.\",\n    // Automatic metric deletion only makes sense if we have a high/unknown cardinality label set,\n    // so here is a sample label for each \"document provider\", whoever that may be.\n    labelNames: new[] { \"document_provider\" });\n\n// This returns a metric instance that will reset the expiration timer whenever the metric value is updated.\nvar processingStarted = processingStartedHandle.WithExtendLifetimeOnUse();\n\n...\n\npublic void ProcessDocument(string documentProvider)\n{\n  // This will reset the expiration timer for this document provider.\n  processingStarted.WithLabels(documentProvider).Inc();\n\n  DoDocumentProcessingWork();\n}\n```\n\nThe expiration logic is scoped to the factory. Multiple handles for the same metric from the same factory will share their expiration logic. However, handles for the same metric from different factories will have independent expiration logic.\n\nSee also, [Sample.Web.MetricExpiration](Sample.Web.MetricExpiration/Program.cs).\n\n# ASP.NET Core exporter middleware\n\nFor projects built with ASP.NET Core, a middleware plugin is provided.\n\nIf you use the default Visual Studio project templates, modify the `UseEndpoints` call as follows:\n\n* Add `endpoints.MapMetrics()` anywhere in the delegate body.\n\n```csharp\npublic void Configure(IApplicationBuilder app, ...)\n{\n    // ...\n\n    app.UseEndpoints(endpoints =\u003e\n    {\n        // ...\n\n        endpoints.MapMetrics();\n    });\n}\n```\n\nThe default configuration will publish metrics on the `/metrics` URL.\n\nThe ASP.NET Core functionality is delivered in the `prometheus-net.AspNetCore` NuGet package.\n\nSee also, [Sample.Web](Sample.Web/Program.cs).\n\n# ASP.NET Core HTTP request metrics\n\nThe library exposes some metrics from ASP.NET Core applications:\n\n* Number of HTTP requests in progress.\n* Total number of received HTTP requests.\n* Duration of HTTP requests.\n\nThe ASP.NET Core functionality is delivered in the `prometheus-net.AspNetCore` NuGet package.\n\nYou can expose HTTP metrics by modifying your `Startup.Configure()` method:\n\n* After `app.UseRouting()` add `app.UseHttpMetrics()`.\n\nExample `Startup.cs`:\n\n```csharp\npublic void Configure(IApplicationBuilder app, ...)\n{\n    // ...\n\n    app.UseRouting();\n    app.UseHttpMetrics();\n\n    // ...\n}\n```\n\nBy default, metrics are collected separately for each response status code (200, 201, 202, 203, ...). You can considerably reduce the size of the data set by only preserving information about the first digit of the status code:\n\n```csharp\napp.UseHttpMetrics(options =\u003e\n{\n    // This will preserve only the first digit of the status code.\n    // For example: 200, 201, 203 -\u003e 2xx\n    options.ReduceStatusCodeCardinality();\n});\n```\n\nNB! Exception handler middleware that changes HTTP response codes must be registered **after** `UseHttpMetrics()` in order to ensure that prometheus-net reports the correct HTTP response status code.\n\nThe `action`, `controller` and `endpoint` route parameters are always captured by default. If Razor Pages is in use, the `page` label will be captured to show the path to the page.\n\nYou can include additional route parameters as follows:\n\n```csharp\napp.UseHttpMetrics(options =\u003e\n{\n    // Assume there exists a custom route parameter with this name.\n    options.AddRouteParameter(\"api-version\");\n});\n```\n\nYou can also extract arbitrary data from the HttpContext into label values as follows:\n\n```csharp\napp.UseHttpMetrics(options =\u003e\n{\n    options.AddCustomLabel(\"host\", context =\u003e context.Request.Host.Host);\n});\n```\n\nSee also, [Sample.Web](Sample.Web/Program.cs).\n\n# ASP.NET Core gRPC request metrics\n\nThe library allows you to expose some metrics from ASP.NET Core gRPC services. These metrics include labels for service and method name.\n\nYou can expose gRPC metrics by modifying your `Startup.Configure()` method:\n* After `app.UseRouting()` add `app.UseGrpcMetrics()`.\n\nExample `Startup.cs`:\n\n```csharp\npublic void Configure(IApplicationBuilder app, ...)\n{\n    // ...\n\n    app.UseRouting();\n    app.UseGrpcMetrics();\n\n    // ...\n}\n```\n\nThe gRPC functionality is delivered in the `prometheus-net.AspNetCore.Grpc` NuGet package.\n\nSee also, [Sample.Grpc](Sample.Grpc/Program.cs).\n\n# IHttpClientFactory metrics\n\nThis library allows you to expose metrics about HttpClient instances created using [IHttpClientFactory](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests).\n\nThe exposed metrics include:\n\n* Number of HTTP requests in progress.\n* Total number of started HTTP requests.\n* Duration of HTTP client requests (from start of request to end of reading response headers).\n* Duration of HTTP client responses (from start of request to end of reading response body).\n\nExample `Startup.cs` modification to enable these metrics for all HttpClients registered in the service collection:\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.UseHttpClientMetrics();\n\n    // ...\n}\n```\n\n\u003e **Note**\n\u003e You can also register HTTP client metrics only for a specific HttpClient by calling `services.AddHttpClient(...).UseHttpClientMetrics()`.\n\nSee also, [Sample.Web](Sample.Web/Program.cs).\n\n# ASP.NET Core health check status metrics\n\nYou can expose the current status of [ASP.NET Core health checks](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks) as Prometheus metrics by extending your `IHealthChecksBuilder` in the `Startup.ConfigureServices()` method:\n\n```csharp\npublic void ConfigureServices(IServiceCollection services, ...)\n{\n    // ...\n\n    services.AddHealthChecks()\n        // ...\n        \u003cYour Health Checks\u003e\n        // ...\n        .ForwardToPrometheus();\n\n    // ...\n}\n```\n\nThe status of each health check will be published in the `aspnetcore_healthcheck_status` metric.\n\nThe ASP.NET Core health check integration is delivered in the `prometheus-net.AspNetCore.HealthChecks` NuGet package.\n\nSee also, [Sample.Web](Sample.Web/Program.cs).\n\n# Protecting the metrics endpoint from unauthorized access\n\nYou may wish to restrict access to the metrics export URL. Documentation on how to apply ASP.NET Core security mechanisms is beyond the scope of this readme file but a good starting point may be to [require an authorization policy to be satisfied for accessing the endpoint](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0#apply-policies-to-endpoints)\n\n```csharp\napp.UseEndpoints(endpoints =\u003e\n{\n    // ...\n\n    // Assumes that you have previously configured the \"ReadMetrics\" policy (not shown).\n    endpoints.MapMetrics().RequireAuthorization(\"ReadMetrics\");\n});\n```\n\nAnother commonly used option is to expose a separate web server endpoint (e.g. a new `KestrelMetricServer` instance) on a different port, with firewall rules limiting access to only certain IP addresses. Refer to the sample project [Sample.Web.DifferentPort](Sample.Web.DifferentPort/Program.cs).\n\n# ASP.NET Web API exporter\n\nThe easiest way to export metrics from an ASP.NET Web API app on the full .NET Framework is to use `AspNetMetricServer` in your `Global.asax.cs` file. Insert the following line to the top of the `Application_Start` method:\n\n```csharp\nprotected void Application_Start(object sender, EventArgs e)\n{\n    AspNetMetricServer.RegisterRoutes(GlobalConfiguration.Configuration);\n\n    // Other code follows.\n}\n```\n\nThe above snippet exposes metrics on the `/metrics` URL.\n\nThe `AspNetMetricServer` class is provided by the `prometheus-net.NetFramework.AspNet` NuGet package.\n\n# Kestrel stand-alone server\n\nIn some situation, you may wish to start a stand-alone metric server using Kestrel (e.g. if your app has no other HTTP-accessible functionality).\n\n```csharp\nvar metricServer = new KestrelMetricServer(port: 1234);\nmetricServer.Start();\n```\n\nThe default configuration will publish metrics on the `/metrics` URL.\n\nIf your app is an ASP.NET Core web app, you can use a pipeline-integrated mechanism:\n\n```csharp\nservices.AddMetricServer(options =\u003e\n{\n    options.Port = 1234;\n});\n```\n\n# Publishing to Pushgateway\n\nMetrics can be posted to a [Pushgateway](https://prometheus.io/docs/practices/pushing/) server.\n\n```csharp\nvar pusher = new MetricPusher(new MetricPusherOptions\n{\n    Endpoint = \"https://pushgateway.example.org:9091/metrics\",\n    Job = \"some_job\"\n});\n\npusher.Start();\n```\n\nNote that the default behavior of the metric pusher is to append metrics. You can use `MetricPusherOptions.ReplaceOnPush` to make it replace existing metrics in the same group, removing any that are no longer pushed.\n\n# Publishing to Pushgateway with basic authentication\n\nYou can use a custom HttpClient to supply credentials for the Pushgateway.\n\n```csharp\n// Placeholder username and password here - replace with your own data.\nvar headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(\"username:password\"));\nvar httpClient = new HttpClient();\nhttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Basic\", headerValue);\n\nvar pusher = new MetricPusher(new MetricPusherOptions\n{\n    Endpoint =  \"https://pushgateway.example.org:9091/metrics\",\n    Job = \"some_job\",\n    HttpClientProvider = () =\u003e httpClient\n});\n\npusher.Start();\n```\n\n# Publishing via standalone HTTP handler\n\nAs a fallback option for scenarios where Kestrel or ASP.NET Core hosting is unsuitable, an `HttpListener` based metrics server implementation is also available.\n\n```csharp\nvar metricServer = new MetricServer(port: 1234);\nmetricServer.Start();\n```\n\nThe default configuration will publish metrics on the `/metrics` URL.\n\n`MetricServer.Start()` may throw an access denied exception on Windows if your user does not have the right to open a web server on the specified port. You can use the *netsh* command to grant yourself the required permissions:\n\n\u003e netsh http add urlacl url=http://+:1234/metrics user=DOMAIN\\user\n\n# Publishing raw metrics document\n\nIn scenarios where you handle publishing via a custom endpoint, you can export the entire metrics data set as a Prometheus text document.\n\n```csharp\nawait Metrics.DefaultRegistry.CollectAndExportAsTextAsync(outputStream);\n```\n\n# Just-in-time updates\n\nIn some scenarios you may want to only collect data when it is requested by Prometheus. To easily implement this scenario prometheus-net enables you to register a callback before every collection occurs. Register your callback using `Metrics.DefaultRegistry.AddBeforeCollectCallback()`.\n\nEvery callback will be executed before each collection, which will not finish until every callback has finished executing. Prometheus will expect each scrape to complete within a certain amount of seconds. To avoid timeouts, ensure that any registered callbacks execute quickly.\n\n* A synchronous callback (of type `Action`) should not take more than a few milliseconds. Do not read data from remote systems in these callbacks.\n* An asynchronous callback (of type `Func\u003cCancellationToken, Task\u003e`) is more suitable for long-running data collection work (lasting a few seconds). You can use asynchronous callbacks for reading data from remote systems.\n\n```csharp\nMetrics.DefaultRegistry.AddBeforeCollectCallback(async (cancel) =\u003e\n{\n    // Probe a remote system.\n    var response = await httpClient.GetAsync(\"https://google.com\", cancel);\n\n    // Increase a counter by however many bytes we loaded.\n    googlePageBytes.Inc(response.Content.Headers.ContentLength ?? 0);\n});\n```\n\n# Suppressing default metrics\n\nThe library enables various default metrics and integrations by default. If these default metrics are not desirable you may remove them by calling `Metrics.SuppressDefaultMetrics()` before registering any of your own metrics.\n\n# DiagnosticSource integration\n\n[.NET Core provides the DiagnosticSource mechanism for reporting diagnostic events](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Diagnostics.DiagnosticSource/src/DiagnosticSourceUsersGuide.md), used widely by .NET and ASP.NET Core classes. To expose basic data on these events via Prometheus, you can use the `DiagnosticSourceAdapter` class:\n\n```csharp\n// An optional \"options\" parameter is available to customize adapter behavior.\nvar registration = DiagnosticSourceAdapter.StartListening();\n\n...\n\n// Stops listening for DiagnosticSource events.\nregistration.Dispose();\n```\n\nAny events that occur are exported as Prometheus metrics, indicating the name of the event source and the name of the event:\n\n```\ndiagnostic_events_total{source=\"Microsoft.AspNetCore\",event=\"Microsoft.AspNetCore.Mvc.AfterAction\"} 4\ndiagnostic_events_total{source=\"HttpHandlerDiagnosticListener\",event=\"System.Net.Http.Request\"} 8\n```\n\nThe level of detail obtained from this is rather low - only the total count for each event is exported. For more fine-grained analytics, you need to listen to DiagnosticSource events on your own and create custom metrics that can understand the meaning of each particular type of event that is of interest to you.\n\n# EventCounter integration\n\n\u003e **Note**\n\u003e The output produced by this integration has changed significantly between prometheus-net 6.0 and prometheus-net 7.0. The old output format is no longer supported.\n\n[.NET Core provides the EventCounter mechanism for reporting diagnostic events](https://docs.microsoft.com/en-us/dotnet/core/diagnostics/event-counters), used used widely by .NET and ASP.NET Core classes. This library publishes all .NET EventCounter data by default. To suppress this, see [Suppressing default metrics](#suppressing-default-metrics).\n\nYou can configure the integration using `Metrics.ConfigureEventCounterAdapter()`.\n\nBy default, prometheus-net will only publish [the well-known .NET EventCounters](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/available-counters) to minimize resource consumption in the default configuration. A custom event source filter must be provided in the configuration to enable publishing of additional event counters.\n\nSee also, [Sample.Console](Sample.Console/Program.cs).\n\n# .NET Meters integration\n\n\u003e **Note**\n\u003e The output produced by this integration has changed significantly between prometheus-net 6.0 and prometheus-net 7.0. The old output format is no longer supported.\n\n[.NET provides the Meters mechanism for reporting diagnostic metrics](https://docs.microsoft.com/en-us/dotnet/core/diagnostics/metrics). This library publishes all .NET Meters API data by default. To suppress this, see [Suppressing default metrics](#suppressing-default-metrics).\n\nYou can configure the integration using `Metrics.ConfigureMeterAdapter()`.\n\nSee also, [Sample.Console.DotNetMeters](Sample.Console.DotNetMeters/Program.cs).\n\n# Benchmarks\n\nA suite of benchmarks is included if you wish to explore the performance characteristics of the library. Simply build and run the `Benchmarks.NetCore` project in Release mode.\n\nAs an example of the performance of measuring data using prometheus-net, we have the results of the MeasurementBenchmarks here, converted into measurements per second:\n\n| Metric type             | Measurements per second |\n|-------------------------|------------------------:|\n| Counter                 |             261 million |\n| Gauge                   |             591 million |\n| Histogram (16 buckets)  |             105 million |\n| Histogram (128 buckets) |              65 million |\n\nAnother popular .NET SDK with Prometheus support is the OpenTelemetry SDK. To help you choose, we have [SdkComparisonBenchmarks.cs](Benchmark.NetCore/SdkComparisonBenchmarks.cs) to compare the two SDKs and give some idea of how they differer in the performance tradeoffs made. Both SDKs are evaluated in single-threaded mode under a comparable workload and enabled feature set. A representative result is here:\n\n| SDK            | Benchmark scenario                    | CPU time | Memory |\n|----------------|---------------------------------------|---------:|-------:|\n| prometheus-net | Counter (existing timeseries) x100K   |   230 µs |   None |\n| OpenTelemetry  | Counter (existing timeseries) x100K   | 10998 µs |   None |\n| prometheus-net | Histogram (existing timeseries) x100K |   957 µs |   None |\n| OpenTelemetry  | Histogram (existing timeseries) x100K | 12110 µs |   None |\n| prometheus-net | Histogram (new timeseries) x1K        |   716 µs | 664 KB |\n| OpenTelemetry  | Histogram (new timeseries) x1K        |   350 µs |  96 KB |\n\n# Community projects\n\nSome useful related projects are:\n\n* [prometheus-net.DotNetRuntime](https://github.com/djluck/prometheus-net.DotNetRuntime) instruments .NET Core apps to export metrics on .NET Core performance.\n* [prometheus-net.AspNet](https://github.com/rocklan/prometheus-net.AspNet) instruments ASP.NET full framework apps to export metrics on performance.\n* [prometheus-net.SystemMetrics](https://github.com/Daniel15/prometheus-net.SystemMetrics) exports various system metrics such as CPU usage, disk usage, etc.\n* [prometheus-net Grafana dashboards](https://github.com/prometheus-net/grafana-dashboards) provides example dashboards for visualizing prometheus-net metrics in [Grafana](https://grafana.com/).\n* [PromQL.Parser](https://github.com/djluck/PromQL.Parser) enables you to parse and create Prometheus queries in C#.\n\nNote: to avoid confusion between \"official\" prometheus-net and community maintained packages, the `prometheus-net` namespace is protected on nuget.org. However, the `prometheus-net.Contrib.*` namespace allows package publishing by all authors.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprometheus-net%2Fprometheus-net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprometheus-net%2Fprometheus-net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprometheus-net%2Fprometheus-net/lists"}