Exposing Node.js process metrics using PM2 and PMX.

Introduction rant

Over the course of the last few months I have been in charge of developing a sustainable and observable project structure for Node micro services. While I have done many things like this before, each environment and ecosystem that you develop in provides different challenges. Using PM2 for your node projects is not anything revolutionary if you live in the world of Node development; however using PM2 to its fullest can be a bit mystifying depending on your development requirements. 

One requirement I came across with my latest endeavors is when your employer doesn't want to invest into Kyemetrics as a service, there is a limiting technical factor that doesn't allow direct reporting to the Keymetrics platform, or you simply get dismissed by the higher ups but there is still the requirement for the existing technology ( such as an orchestration system ) to be able to pull metrics from your service/app.

It is the last situation above, that lead me into the deeper parts of the PM2 ecosystem tools and how to expose things not only that came stock with the metric reporter, but very specific things that I wanted to expose for one reason or another.

At this point if you don't have a understanding of what PM2 is or what it does for you, I suggest you read this before moving forward.

What is PMX?

PMX is a module for the PM2 runner that implements an API that allows exposure of metrics tied to the process sandboxes and layer 4 of the OSI model. This allows for the monitoring of various metrics associated with each application process being run.

That is really just a lot of talk to say that it can let you know when your Node instances are on fire. Also it can reveal useful patterns that can show you data that can lead to change on how you scale your instance or utilize certain resources.

Starting a small example

Download Sample Code

Let us get to the good stuff and actually show how it is used and the code implemented. It is actually a pretty painless process assuming you are already using PM2 to manage your project. If you don't want to bother going through the steps of creating your own project you can download the sample code above.

Installation and setup

For this particular article we will assume our project structure looks like this, you can also just download the code example for this article.

  • myProject
    • metricsDefinitions
      • count.js
    • middleware
      • countMetric.js
    • node_modules
    • package.json
    • bootstrap.js

and it will be using the following libraries for our example build out : pm2, pmx, and express. You can install these by running

 npm install pm2 pmx express --save 

After your dependencies have been installed modify your package.json scripts section to mimic the following

This adds the ability for your npm start command to also start the metrics API if your app start up was successful. Really we are just wrapping the PM2 startup commands here but leveraging the npm scripts section to ensure that PM2 exits successfully for starting your app is just good practice in my book. You can just do the whole thing in the start script command as well with pm2 start bootstrap.js; pm2 web which will always bring up the metrics API regardless of your app state which can be useful if you are going to use it to check the status of you Node instance(s).

Finally writing some code

Now we can get to actually adding code to files. We will be creating a small server that keeps track of how many requests have come Into it over the course of its life span. We will then use a custom metric probe, and the PMX API to expose that information.

Create, if you haven't already, a bootstrap.js file and add the following to it :

Bootstrap.js walk through

In our bootstrap.js we setup a few things for our app. First we do the normal requires just to get the express app up and running. On line 3 however we import the pmx library and configure it. There are a few options that are boolean flags

  • http - HTTP routes logging (default: false)Enable pm2 to perform http watching for http related metrics
  • errors - Exceptions logging
  • custom_probes - Auto expose JS Loop Latency and HTTP req/s as custom metrics
  • network - Network monitoring at the application levelEnable calculation of lower level network statistics
  • ports - Shows which ports your app is listening on

There are a lot more options that the pmx interface can be configured with which can be found here , for now however these are the ones we need to ensure are setup for this example. The following is the rest of the steps taken in our bootstrap.js file

  • Then we pull in our metric middleware which we will go over in just a bit. 
  • Then we insert that middleware into the Express app request life cycle so it can intercept all requests that come into our app. 
  • Then we add a health check route so we can check to see if our app is running, but also it's a simple route that we can hit to trigger our metric. 
  • Then we start our server and output a success message for us to see in the console.

countMetric.js

In our bootstrap.js we pulled in a countMetric.js , if you haven't created that file, do so now. Then add the following to it :

While this file is long or complex it does act as a glue layer between your probe definitions from PMX to the your actual applications use of the metrics. This will allow you to change out metric calculation, implementation, or even library in the future without breaking your entire Express request life cycle. In this file we do the following :

  • Pull in a countProbe - Will be covered next.
  • Create a module export function that is pretty standard
  • We tell our metric that we want to increment it's count by 1.
  • Then we tell the life cycle it can continue with next()

count.js

count.js is a wrapper for the actual PMX probe creation that then gets exported. Again it's not complex or long, but breaking your modules out like this will prevent a lot of pain down the line when these metrics inevitably change. If you haven't already create this file, do so and add the following to it :

This will do the following for us :

  • Pull in the PMX module
  • Instantiate a new probe definition within PMX for us
  • Export a defined probe type

PMX provides various metric types, not just counts. In this example we are only using count because it's simple and doesn't require high volumes of requests to show it working. PMX supports the following metric types all of which expose different methods once their type is defined by calling that metric type method on a new probe instance.

  • Simple metrics: Values that can be read instantly
    • eg. Monitor variable value
  • Counter: Things that increment or decrement
    • eg. Downloads being processed, user connected
  • Meter: Things that are measured as events / interval
    • eg. Request per minute for a http server
  • Histogram: Keeps a resevoir of statistically relevant values biased towards the last 5 minutes to explore their distribution
    • eg. Monitor the mean of execution of a query into database

In our instance we are creating a counter type metric probe that we are simple adding to which expose the inc() and dec() methods that increments and decrements the count of the metric probe respectively. The agg_type param is optionnal, it can be summaxminavg (default) or none. It will impact the way the probe data is aggregated within the Keymetrics/PMX report backend. Use none if this is irrelevant (eg: constant or string value).

Starting Our Project

Right, it's been a bit of a long winded explanation but we are finally there. Lets run our project, issue a npm start in your project directory. You should see something similar to this in your terminal :

Confirming it all works

If nothing errored out, then your little application is now running! You can now check your custom metric status by hitting the PMX metric report API by going to : localhost:9615 

I highly suggest you have a JSON parsing extension setup for your browser because it will give you way more information then you thought you ever needed for you instances. The pieces of this massive metrics dump that we are interested however are under the following JSON path : processes[].pm2_env.axm_monitor

Under that path you will find in the axm_monitor object there is a field name "Request Count" which is the name that was gave our counter probe in count.js , that is our custom metric value. Now to test it out you can go to localhost:3000/health , let that load. Now reload your metrics url, go back the same path and take note that the "value" property has been increased by 1. 

Conclusion

There is a lot of things you can get PM2 and PMX to do for you in the world of reporting, metrics and monitoring. This article hasn't even scratched the surface of what all can be done but hopefully it has peaked your interest enough to have you learn more about what you can do with PM2 to make managing your applications and services easier in everyday dev life.

If you want to poke around more feel free to download the sample code and mess around with all that PM2 and PMX has to offer. In addition I will link to all the resources that I used to create my first metrics and everything that was pulled into this article.

Links

https://expressjs.com/en/starter/hello-world.html

https://github.com/keymetrics/pmx

https://github.com/Unitech/pm2