Health Monitoring Custom Node.js Metrics for SAP BTP, Cloud Foundry environment

This guide demonstrates how to enable manual instrumentation for a Node.js microservice in SAP BTP, Cloud Foundry using the OpenTelemetry (OTEL) agent extension. While automatic instrumentation captures default metrics, custom instrumentation allows you to tailor metrics to your specific application needs.

Setting up Custom Instrumentation

The following declarations are essential for setting up custom instrumentation with the OTEL node.js agent extension:

 

Step 1 - Import OpenTelemetry Metrics Modules

const { MeterProvider } = require('@opentelemetry/sdk-metrics');
const { metrics } = require('@opentelemetry/api');

@opentelemetry/sdk-metrics: Provides the MeterProvider, which is responsible for managing metric collection.

@opentelemetry/api: Contains the core OpenTelemetry API, including the metrics module to interact with the global metrics API.

 

Step 2 - Initialize the MeterProvider

metrics.setGlobalMeterProvider(meterProvider)

MeterProvider is the entry point for setting up metric collection. It manages meters and exporters, sending the collected metrics to xotel-agent-ext-js.
 

Step 3 - Set the Global MeterProvider

metrics.setGlobalMeterProvider(meterProvider);

This step registers the MeterProvider as the global provider. This ensures that any Meter retrieved using the OpenTelemetry API is created by this MeterProvider.

 

Step 4 - Get the Meter Instance with scope “@sap-cloud-alm/instrumentation-metrics:manual“

const meter = metrics.getMeter('@sap-cloud-alm/instrumentation-metrics:manual');

 The getMeter method initializes the meter with scope@sap-cloud-alm/instrumentation-metrics:manual“. This meter is used to collect and report custom metrics specific to the application.

These declarations ensure that your Node.js microservice can use OpenTelemetry to capture and export custom metrics effectively.

 

Step 5- Define Custom Metrics

const successfulJobCounter = meter.createObservableGauge('custom.successful.jobs', {

  description: 'successful jobs'

});

const failedJobCounter = meter.createObservableGauge('custom.failed.jobs', {

  description:'failed jobs'

});

Create an ObservableGauge for successful and failed jobs.

let successJobs = 0;

let failedJobs = 0;

successfulJobCounter.addCallback(observableResult => {

  // Pass the value of successfulJobs to the observable gauge

  observableResult.observe(successJobs);

});

failedJobCounter.addCallback(observableResult => {

  // Pass the value of successfulJobs to the observable gauge

  observableResult.observe(failedJobs);

});

 Set up the observation logic.

cds.on("bootstrap", (cdsApp) => {  

    cdsApp.use((req, res, next) => {

      //Example: Increment counters based on request success or failure

      successJobs += 1; // Update based on real logic

      failedJobs += 1;

      next();

    });

    // Use the Express app as middleware for the CDS server

    cdsApp.use(app);

  });

successJobs and failedJobs are updated in middleware or event listeners, ensuring metrics reflect real system behavior.

app.get('/testCounters', (req, res) => {

    res.send(`Successful Jobs: ${successJobs}, Failed Jobs: ${ failedJobs }`);

});

Test endpoint to trigger requests to update counters.