Integrating SAP CALM Into Your CAP NodeJS Typescript Service

Simon Laursen
4 min readApr 9, 2024

Finally the time has come for the SAP sphere to fully embrace the OpenTelemetry world, and help us as developers ensure long living and stable services!

But how does one go about integrating the auto-instrumentation needed for a CAP application to communicate with CALM?
And how can we test this locally with TypeScript?

Disclaimer

The goal of this article is not to document the initial setup of SAP CALM, but instead to help developers make sure their applications are ready to integrate with CALM.

For the sake of this article, we’ll be focusing primarily on the Cloud Foundry environment on BTP, but the setup can easily be translated to Kyma if needed.

The First Step: Preparing Your Credentials

Before we can get all nitty gritty into the code, we’ll first have to fetch the needed credentials to access the NPM registry containing the instrumentation package.

To do this, we’ll first navigate to the User Authentication Management section of SAP’s Repository-Based Shipment Channel. Under the User Management section here, we’ll then click the “Add User” option, and then create our technical access user.

SAP’s Repository-Based Shipment Channel — User Management

From here we’ll then want to copy over the NPM Base64 Credentials. We’ll need these for our new fancy `.npmrc`.

The `.npmrc` file we’ll need to create is fairly straight forward. It is just a base pointer for npm to remember to authenticate when fetching this particular package, called `@sap/xotel-agent-ext-js`.

//73555000100200018064.npmsrv.cdn.repositories.cloud.sap/:_auth=<your-base64-token>

Remember, this file should NOT be included in your version control and should be kept safe at all costs. If you need to have the dependency installed during a CI/CD pipeline, then have the token be inserted from a safe storage at install time.

With this, we’re now ready to start integrating the package into our project!

Adding the Auto-Instrumentation

Now that we’re authenticated for the resources, it’s time for us to include the OTEL dependencies in our package.json file.

{
...
"dependencies": {
...
"@opentelemetry/instrumentation": "^0.50.0",
"@opentelemetry/sdk-trace-base": "^1.23.0",
"@sap/xotel-agent-ext-js": "https://73555000100200018064.npmsrv.cdn.repositories.cloud.sap/@sap/xotel-agent-ext-js/-/xotel-agent-ext-js-1.5.9.tgz",
...
},
...
}

NOTE: Seeing as the link SAP has provided is a direct link to the package, it might be subject to change so make sure to keep up to date with their official documentation regarding the package!

Once you’ve added the dependency to the file, we just need to ensure that it is installed in the CAP project. Simply run `npm install` and we should be good to go!

We’re Not Ready Just Yet

Now that we’ve prepared the base of our project for the new dependency, we still need to make sure that it will actually run.

First step to make sure that happens, is of course to include the requirement in the bootstrap of our service:

export default async (srv: Service) => {
// SAP CALM Instrumentation - Can be disabled in environment using SAP_CALM_INSTRUMENTATION_ENABLED = false
require("@sap/xotel-agent-ext-js/dist/common/tracerCallback")(async () => {
// SERVICE INIT LOGIC GOES HERE!
});
};

We’re using the tracerCallback instead of the standard tracer, to make sure that our entire bootstrap is included in the setup. If you don’t have any custom boostrapping you could just replace this with a require to the tracer class instead.

And now we just need to setup our .env file to configure the runtime for our instrumentation, and to allow for us to turn it off when it is not necessary.

SAP_CALM_SERVICE_NAME=<your-service-name>
SAP_CALM_SERVICE_TYPE=SAP_CP_CF
SAP_CALM_DCI_AGG_THRESHOLD=100 # This is the default value
SAP_CALM_DCI_AGG_USER=true # This is the default value
OTEL_RESOURCE_ATTRIBUTES=sap.tenancy.tenant_id=<your-subaccount-id>
SAP_CALM_DCI_LOG_LEVEL=debug
OTEL_LOG_LEVEL=info

NOTE: You could also set this up in the default-env.json file if you want.

Now, of course CALM is running on the cloud, and not on your local machine, so we will need for our service to first be deployed to Cloud Foundry before we can connect to it (even locally). My advice here would be to first deploy your application without the CALM setup. That way we can test locally if the connection is working before we deploy the actual connection.

From our deployed application we’ll need both the environment configuration for VCAP_SERVICES and the VCAP_APPLICATION values. Be sure to not include any database connection you might have in the services section. Only include what is absolutely necessary, such as XSUAA and Destination service.

And with this, we should now be ready to run a local test! Simply use your standard local start-up command (e.g. cds-ts run).

If you get an initialization error, stating that the CALM instrumentation is not able to connect to the system, then it is likely due to the CALM destination not being available in your subaccount yet.

Preparing For Deployment

Okay, so now that we have our service ready for CALM let’s actually put it up there in the clouds to interact with it!

Luckily this is the easist step, as we only need to include a couple of runtime environment variables to our project’s already existing MTA descriptor.

...
# These are the properties of the service you configured instrumentation for
properties:
SAP_CALM_SERVICE_NAME: <your-service-name>
SAP_CALM_SERVICE_TYPE: SAP_CP_CF
SAP_CALM_DCI_AGG_THRESHOLD: 100
SAP_CALM_DCI_AGG_USER: true
OTEL_RESOURCE_ATTRIBUTES: sap.tenancy.tenant_id=${tenantId}
SAP_CALM_DCI_LOG_LEVEL: debug
OTEL_LOG_LEVEL: info
SAP_CALM_INSTRUMENTATION_ENABLED: true
...

And now all we have to do is build our project and send your .mtar file to our subaccount!

For more information on how you can configure your runtime, I highly encourage you go check out the official documentation made by SAP.

Thanks for reading!

--

--