DEV Community

Cover image for Optimizing Performance Using Prometheus with Node JS for Monitoring
oluwatobi2001
oluwatobi2001

Posted on

Optimizing Performance Using Prometheus with Node JS for Monitoring

Application performance monitoring is an essential hack you as a developer should get acquainted with to detect any error and provide a seamless experience to the end user of the service.
However, to achieve this, it’s quite needed to possess adequate knowledge of some Application monitoring tools.

In this article, we will be talking about The Prometheus tool, its use cases, and its relevance to backend development. Furthermore, we will be looking into integrating it into our Backend application, via the use of several packages and we will also test its functionality.
Additionally, we would chip in on how to generate meaningful insights from our scraped metrics with Prometheus using a tool called Grafana. Having laid out our objectives, let’s get started.
Before moving on to this tutorial, here are some prerequisites
needed to understand this tutorial efficiently.

  • Firstly, you need to have at least basic to intermediate knowledge of Node JS
  • Understand and ability to use NPM

What is Prometheus?

Prometheus is an open-source system monitoring and observability tool invented in the year 2012. It provides monitoring, observability and alerting features for both cloud services and backend applications.  It also works on the principle of querying various endpoints and generating various data matrices which are then stored and can be analyzed to monitor for application and cloud performance.
It provides client libraries across several programming languages providing ease of Application integration.  It also provides an Admin dashboard where various data are queried and scraped from an application and cloud operations are collected. Its Alert features also notify the application developer in case of an occurrence of any anomaly in the application metrics.
Additionally; it possesses an advanced feature known as the PROMQL (Prometheus query language) which allows the developer to use advanced queries to generate data commands for appropriate analysis and the generation of measurable information insights. Right now, we will be integrating Prometheus into our sample backend application which is a Node JS application powered by the Express framework. It is important to have the software already set up before proceeding to the subsequent sections. Here is a link to the Prometheus tool

After completing your installation, initialize a default Node JS application and then install the necessary server dependencies.

Prometheus Client packages for Node JS

Prometheus as mentioned earlier provides various client packages across various languages and Node JS isn’t left out. Currently, here are some of the most popular Prometheus client packages available for Node JS.

However, for this tutorial, the Prom-client package will be used as it has user-friendly documentation, a large user base and strong community support. Here is a link to its documentation and npm page.

Node JS integration with Prometheus

To integrate the Prometheus metrics tracking feature into our Node JS application, we would have to install the prom-client package
npm i prom-client
On successful completion of this step, we will then be initializing the prom client in our code base.
Navigating to the index.js page, and prom client can be initialized by

const client =require(“prom-client”)
Enter fullscreen mode Exit fullscreen mode

With this, we have successfully initialized Prometheus into our Node JS project. Subsequently, we would be setting it up to collect relevant metrics and also learn about some of its specific metric features.

Tracking metrics using Prometheus             

Prometheus provides the user with the flexibility to collect routine Backend application service metrics via the use of its CollectDefaultMetrics feature. It also empowers the user to design unique customized metric collection functions which helps the user assess the application performance more reliably.
To collect routine application metrics, the code below can be used.

const register = new client.Registry();
const collectDefaultMetrics = client.collectDefaultMetrics;

collectDefaultMetrics({
    register
});

Enter fullscreen mode Exit fullscreen mode

The above code initializes the Prometheus registry which serves as a state/container that holds all metrics to be collected from the application.

With this properly configured, we have successfully implemented the default metrics collection feature. To access the metrics collected, an endpoint would have to be created which when accessed, would provide all metrics scraped per time. This can easily be created below.

app.get("/metrics", async (req, res) => {
    res.setHeader("Content-Type", client.register.contentType);
    let metrics = await register.metrics();
    res.send(metrics);
});

Enter fullscreen mode Exit fullscreen mode

 
Accessing this endpoint "/metrics", will reveal all the scraped metrics collected. We would then go on to create customizable specific application metrics to be scraped by the Prometheus library.
Here is the code below. on how to create custom metrics.

const http_request_counter = new client.Counter({
    name: 'myapp_http_request_count',
    help: 'Count of HTTP requests',
    labelNames: ['method', 'route', 'statusCode']
});

register.registerMetric(http_request_counter);

app.use("/*", function(req, res, next) {
    http_request_counter.labels({
        method: req.method,
        route: req.originalUrl,
        statusCode: res.statusCode
    }).inc();
    console.log(register.metrics());
    next();
});

 
Enter fullscreen mode Exit fullscreen mode

in the code above, we created a request counter metric. This counter will automatically increase by 1 whenever we access any endpoint in our backend application. Also included is the name assigned to the custom metrics and the parameters to be collected such as the route, the request method and the status code of the request.

Here is the final code for the project.

// Import required modules
const express = require("express");
const client = require("prom-client");
const bodyParser = require("body-parser");
const cors = require("cors");
const connectDB = require("./Config/db");

// Create an Express application
const app = express();

// Initialize Prometheus registry
const register = new client.Registry();

// Configure default Prometheus labels
register.setDefaultLabels({
    app: "blue",
});

// Define Prometheus metrics
const http_request_counter = new client.Counter({
    name: 'myapp_http_request_count',
    help: 'Count of HTTP requests',
    labelNames: ['method', 'route', 'statusCode']
});
const userCounter = new client.Counter({
    name: "user_counter",
    help: "User counter for my application"
});

// Register Prometheus metrics with the registry
register.registerMetric(http_request_counter);
register.registerMetric(userCounter);

// Middleware to collect and expose Prometheus metrics
app.get("/metrics", async (req, res) => {
    res.setHeader("Content-Type", client.register.contentType);
    let metrics = await register.metrics();
    res.send(metrics);
});

// Middleware to increment user counter for all routes
app.get("/*", (req, res) => {
    userCounter.inc();
    console.log(register.metrics());
    res.send("test");
});

// Middleware to count HTTP requests and log metrics
app.use("/*", function(req, res, next) {
    http_request_counter.labels({
        method: req.method,
        route: req.originalUrl,
        statusCode: res.statusCode
    }).inc();
    console.log(register.metrics());
    next();
});

// Collect default Prometheus metrics (e.g., CPU, memory)
client.collectDefaultMetrics({
    register
});

// Define a Prometheus histogram for response time
const restResponseTimeHistogram = new client.Histogram({
    name: 'rest_response_time_duration_seconds',
    help: 'REST API response time in seconds',
    labelNames: ['method', 'route', 'status_code']
});

// Enable CORS for all routes
app.use(cors({
    origin: '*',
}));

// Parse JSON requests
app.use(express.json());
app.use(bodyParser.json());

// Connect to the database
connectDB();

// Start the server
app.listen(process.env.PORT || 5000, () => {
    console.log("Server is running...");
});

Enter fullscreen mode Exit fullscreen mode

Here is the endpoint showing the application metrics scraped by Prom-client.
Prometheus scraping

With this, we have completed the basics of Prometheus integration with Node JS. Other advanced concepts in Prometheus would further help the developer to create complex relevant metrics registers using the prom client tool.

Additional info (Exploring Grafana)

Grafana dashboard
Obtaining your metrics from your backend service application shouldn’t be all that there is to be. As beautiful as Prometheus is, it is also limited in quite several features of which data visualization is among. Here comes Grafana to the rescue.
The Grafana tool is a data visualization tool that generates meaningful readable insights from the queried metric raw data obtained from Prometheus. You can check out their documentation here and download the tool here for your respective Operating systems. You can also check out tutorials on how to integrate both Prometheus and Grafana.

Conclusion

With this, we have come to the end of the tutorial. We hope you’ve learned essentially about Prometheus, its uses and how to integrate into a backend application for efficient monitoring of application performance.
Feel free to drop comments and questions in the box below, and also check out my other articles here. Till next time, keep on coding!

Top comments (0)