What is Prometheus and How to Add Prometheus To Your .NET Projects?
Requirements: Latest versions of Docker and Visual Studio

Hello all,
Monitoring is very essential in todays fast pacing development environments. We can divide monitoring into different aspects such as tracing, collecting metrics and visualizing metrics. For tracing, we have covered OpenTelemetry and Zipkin here. Today we will talk about collecting any metrics within our application.
There will be no new installation for your machine unless you have Docker installed. Else I strongly advise you to have Docker.
Prometheus is basically a metric collector for your applications. It doesn’t have to be a .NET application. It doesn’t even need to be an application. Prometheus also have some exporters for exporting OS metrics such as CPU, Mem, etc..
If we have already Docker Desktop up and running, let’s pull the Prometheus image.
docker pull prom/prometheus
After the pull is completed:
docker run --name prometheus -d -p 9090:9090 prom/prometheus
If you are not familiar with Docker, let’s talk about what does that command do.
“docker run prom/prometheus” is the command for starting a container from official prometheus image.
“ — — name prometheus” argument is for giving a name to our little container.
“-d” is for detached mode. It means the container will run in the background and it won’t stop when you quit your terminal.
“-p 9090:9090” first 9090 is your machine’s port and the second one is container’s port. It means you are exposing container’s 9090 port to your machine’s 9090 port, so you can reach Prometheus interface from your web browser as “localhost:9090”
Enough with the Docker command. Let’s continue with Prometheus. From your Docker interface (or as an output to “docker ps” command) you should see Prometheus container is up and running. Let’s hit your favorite web browser to investigate Prometheus further. Go to “localhost:9090” from you web browser.

An empty screen welcomes us. In this screen we can write some queries and get some results. Again, to write any query, we should have some metrics. Actually the very container you have run have some metrics already even though we won’t care about those metrics. You can hit “localhost:9090/metrics” to see which metrics are exposed by the Prometheus server (your container itself)

The metrics are related to Prometheus Server itself. It’s like a self healthcheck. But how exactly does Prometheus work?
I encourage you to discover “Targets” page located in Prometheus UI.


Prometheus already harvests its own metrics. Because you can see the endpoint’s state is UP. And if you hit the “Configuration” page, you will see the configuration for Prometheus.


So now we know that, which endpoints are listened to, comes from the configuration in Prometheus Server.
Prometheus basically operates like this. There is a Prometheus server which has all the metrics listened to.
Prometheus exporters are remote endpoints on different hosts which are all basically a bunch of texts served from the memory. Each client should be targeted by configuration in Prometheus Server. If that exporter is not in targets list, there is no one listening to that target.
An exporter could be a Windows exe, or it could be another service within our .NET application which run on different port. Whatever that exporter is, I have to enter the remote address in that configuration file. After we prepare our .NET application, we will return to here.
We create a new project for our little experiment to see how we configure Prometheus. Open Visual Studio and create a new API project. But feel free to do the same for ASP projects.


Let’s add the NuGet packages for Prometheus. The package we will be using is prometheus-net and prometheus-net.AspNetCore from sandersaares.

In your Program.cs file, add this code below to prepare a Prometheus client up and running. The snippet should be before builder.Build() is executed.
.....
builder.Services.AddMetricServer(
options => {
options.Port = 1234;
});
....
....
var app = builder.Build();
Let’s run our project to see if Prometheus is awakened. It does not matter if you run your project with Kestrel or IIS Express at this point. This is your development environment. We specified port 1234 to run our Prometheus endpoint at. You may change this port. I’ll assume you have used 1234 as your Prometheus port.
After our project is initialized, let’s go to localhost:1234/metrics to check Prometheus endpoint.

If you can see this screen, it means you have succeeded running Prometheus in your project. Well done.
As soon as I refresh the page, it has some default metrics counted already. They are actually because I am refreshing a page in my .NET project while refreshing the Prometheus metrics page. They are counted as default by prometheus-net.AspNetCore.

We can also make our own special metrics using Prometheus-net documentations. I will cover it on another article.
Let’s summarize what we have done until here. We have run a Prometheus Server as a Docker container. We have created a sample project which is counting my requests by default. But our Prometheus server is not informed about that new Prometheus endpoint. So how do we do that? We should get back to Prometheus server configuration.
We did see localhost:9090 (that localhost is not your machine, it is the container which Prometheus server runs) in targets, is configured by default on our Prometheus server for self observing purposes. We should also add our application as target to Prometheus Server. Open a cmd window and write this:
docker exec -it prometheus sh
This command will be activate a shell in Prometheus container which we will be able to edit configuration file. After it, cmd (or PowerShell) window should look like this:
PS C:\Users\idylmz> docker exec -it prometheus sh
/prometheus $
If we see /prometheus, we are in the container. Now go and edit /etc/prometheus/prometheus.yml.
vi /etc/prometheus/prometheus.yml
For those who are not familiar to vim, I will walk you through.
With vim, we are basically using our terminal window as a text editor. So there is no mouse pointer to help us, we must use our keyboard’s arrows.
By using our keyboard arrows, we will go to the end of the last line which is:
- targets: ["localhost: 9090"]
If we press “i” in vim, it means we will be inserting some new characters. We’ll be continuing this line as follows:
- targets: ["localhost:9090", "host.docker.internal:1234"]
host.docker.internal is our Docker host which we are running Docker from. Since we are running our sample app on our host machine, we should be call our host as this. 1234 port is the port that our app is using for exposing prometheus metrics. To save our file and quit vim, first we press ESC to quit from insert mode. Then press “:wq!” and enter to save and quit from vim without any “Are you sure” prompt.

After editing our Prometheus config, we should restart the container to make changes to take effect.

First we exit the shell in our container.
exit
Then we restart the container once we returned to our host machine.
docker restart prometheus
Let’s see our targets if it did changed at all.
If everything did go well and the project is running, this is the screen we should be seeing.

You can see our host is recognized by Prometheus Server and the metrics are started to collect.
With these steps, you’re now equipped to start monitoring your .NET applications with Prometheus. From here, you can dive deeper into custom metrics, querying, and visualizing your data to make the most of your monitoring setup. Stay tuned for more articles where I’ll cover these topics in detail — happy coding, and may your metrics be ever insightful!
