---
title: Instrumenting a Node.js Container App with Sidecar
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: >-
  Docs > Serverless > Azure Container Apps > Sidecar Instrumentation >
  Instrumenting a Node.js Container App with Sidecar
---

# Instrumenting a Node.js Container App with Sidecar

## Setup{% #setup %}

1. **Install the Datadog Node.js tracer**.

   1. In your main application, install the `dd-trace` package.

      ```shell
      npm install dd-trace
```

   1. Initialize the Node.js tracer with the `NODE_OPTIONS` environment variable:

      ```dockerfile
      ENV NODE_OPTIONS="--require dd-trace/init"
```

For more information, see [Tracing Node.js applications](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/nodejs/).

1. **Install serverless-init as a sidecar**.

Datadog publishes new releases of the `serverless-init` container image to Google's gcr.io, AWS's ECR, and on Docker Hub:

| hub.docker.com          | gcr.io                           | public.ecr.aws                         |
| ----------------------- | -------------------------------- | -------------------------------------- |
| datadog/serverless-init | gcr.io/datadoghq/serverless-init | public.ecr.aws/datadog/serverless-init |

Images are tagged based on semantic versioning, with each new version receiving three relevant tags:

   - `1`, `1-alpine`: use these to track the latest minor releases, without breaking changes
   - `1.x.x`, `1.x.x-alpine`: use these to pin to a precise version of the library
   - `latest`, `latest-alpine`: use these to follow the latest version release, which may include breaking changes

   {% tab title="Datadog CLI" %}
   Locally: 
Install the Datadog CLI

   ```shell
   npm install -g @datadog/datadog-ci @datadog/datadog-ci-plugin-container-app
   ```

Install the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) and authenticate with `az login`.

To set up the Datadog sidecar for your applications, configure the [Datadog site](https://docs.datadoghq.com/getting_started/site/) and Datadog API key, and run the `instrument` command *after* your normal deployment:

   ```shell
   export DD_SITE="<DATADOG_SITE>"
   export DD_API_KEY="<DATADOG_API_KEY>"
   datadog-ci container-app instrument -s <AZURE-SUBSCRIPTION-ID> -g <AZURE-RESOURCE-GROUP-NAME> -n <CONTAINER-APP-NAME>
   ```

You can also instrument multiple applications using the full resource IDs:

   ```shell
   datadog-ci container-app instrument \
     --resource-id "/subscriptions/<subscription-id>/resourceGroups/<resource-group-name-1>/providers/Microsoft.App/containerApps/<container-app-name-1>" \
     --resource-id "/subscriptions/<subscription-id>/resourceGroups/<resource-group-name-2>/providers/Microsoft.App/containerApps/<container-app-name-2>"
   ```
Azure Cloud Shell: 
To use the Datadog CLI in [Azure Cloud Shell](https://portal.azure.com/#cloudshell/), open a cloud shell, set your API key and site in the `DD_API_KEY` and `DD_SITE` environment variables, and use `npx` to run the CLI directly.

   ```shell
   export DD_API_KEY=<DATADOG_API_KEY>
   export DD_SITE=<DATADOG_SITE>
   npx @datadog/datadog-ci container-app instrument -s <AZURE-SUBSCRIPTION-ID> -g <AZURE-RESOURCE-GROUP-NAME> -n <CONTAINER-APP-NAME>
   ```

Additional parameters can be found in the [CLI documentation](https://github.com/DataDog/datadog-ci/tree/master/packages/plugin-container-app#arguments).
   {% /tab %}

   {% tab title="Terraform" %}
The [Datadog Terraform module for Container Apps](https://registry.terraform.io/modules/DataDog/container-app-datadog/azurerm/latest) wraps the [`azurerm_container_app`](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app) resource and automatically configures your Azure Container App for Datadog Serverless Monitoring by adding required environment variables and the serverless-init sidecar.

If you don't already have Terraform set up, [install Terraform](https://developer.hashicorp.com/terraform/install), create a new directory, and make a file called `main.tf`.

Then, add the following to your Terraform configuration, updating it as necessary based on your needs:

   ```tf
   variable "datadog_api_key" {
     description = "Your Datadog API key"
     type        = string
     sensitive   = true
   }
   
   provider "azurerm" {
     features {}
     subscription_id = "00000000-0000-0000-0000-000000000000" // Replace with your subscription ID
   }
   
   resource "azurerm_container_app_environment" "my_env" {
       name                = "my-container-app-env" // Replace with your container app environment name
       resource_group_name = "my-resource-group"    // Replace with your resource group name
       location            = "eastus"
   }
   
   module "my_container_app" {
     source  = "DataDog/container-app-datadog/azurerm"
     version = "~> 1.0"
   
     name                         = "my-container-app" // Replace with your container app name
     resource_group_name          = "my-resource-group" // Replace with your resource group name
     container_app_environment_id = azurerm_container_app_environment.my_env.id
   
     datadog_api_key = var.datadog_api_key
     datadog_site    = "datadoghq.com" // Replace with your Datadog site
     datadog_service = "my-service"    // Replace with your service name
     datadog_env     = "dev"           // Replace with your environment (e.g. prod, staging, dev)
     datadog_version = "0.1.0"         // Replace with your application version
   
     revision_mode         = "Single"
     workload_profile_name = "Consumption"
     ingress = {
       external_enabled = true
       target_port      = 8080
       traffic_weight = [{
         percentage      = 100
         latest_revision = true
       }]
     }
     template = {
       container = [{
         cpu    = 0.5
         memory = "1Gi"
         image  = "docker.io/your-docker-image:latest" // Replace with your Docker image
         name   = "main"
       }]
     }
   }
   ```

Finally, run `terraform apply`, and follow any prompts.

The [Datadog Container App module](https://registry.terraform.io/modules/DataDog/container-app-datadog/azurerm/latest) only deploys the Container App resource, so you need to build and push your container separately.

See the Environment Variables for more information on the configuration options available through the `env`.

Ensure the container port for the main container is the same as the one exposed in your Dockerfile/service.

If you haven't already, initialize your Terraform project:

   ```shell
   terraform init
   ```

To deploy your app, run:

   ```shell
   terraform apply
   ```

      {% /tab %}

   {% tab title="Bicep" %}
   Configuration: 
Update your existing Container App bicep to include the necessary Datadog App Settings and sidecar, as follows:

   ```bicep
   @secure()
   param datadogApiKey string
   param datadogSite string
   param service string = 'my-service'
   param env string = 'dev'
   param version string = '0.0.0'
   
   resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
     // ...
     properties: {
       template: {
         volumes: [
           {
             name: 'shared-volume'
             storageType: 'EmptyDir'
           }
           // Additional volumes
         ]
         containers: [
           {
             name: 'main'
             image: 'index.docker.io/your/image:tag' // Replace with your Application Image
             resources: {
               cpu: 1
               memory: '2Gi'
             }
             env: [
               { name: 'DD_ENV', value: env }
               { name: 'DD_SERVICE', value: name }
               { name: 'DD_VERSION', value: version }
               { name: 'DD_LOGS_INJECTION', value: 'true' }
               // Additional tracing/application env vars
             ]
             volumeMounts: [
               { volumeName: 'shared-volume', mountPath: '/shared-volume' }
               // Additional volume mounts
             ]
           }
           {
             name: 'datadog-sidecar'
             image: 'index.docker.io/datadog/serverless-init:latest'
             resources: {
               cpu: '0.5'
               memory: '1Gi'
             }
             env: [
               { name: 'DD_AZURE_SUBSCRIPTION_ID', value: subscription().subscriptionId }
               { name: 'DD_AZURE_RESOURCE_GROUP', value: resourceGroup().name }
               { name: 'DD_API_KEY', value: datadogApiKey }
               { name: 'DD_SITE', value: datadogSite }
               { name: 'DD_SERVICE', value: service }
               { name: 'DD_ENV', value: env }
               { name: 'DD_VERSION', value: version }
               // set this to wherever you write logs in the shared volume:
               { name: 'DD_SERVERLESS_LOG_PATH', value: '/shared-volume/logs/app.log' }
             ]
             volumeMounts: [{ volumeName: 'shared-volume', mountPath: '/shared-volume' }]
           }
         ]
         scale: { minReplicas: 1, maxReplicas: 1, rules: [] }
       }
     }
   }
   ```

Redeploy your updated template:

   ```shell
   az deployment group create --resource-group <RESOURCE GROUP> --template-file <TEMPLATE FILE>
   ```

See the Manual tab for descriptions of all environment variables.
   {% /tab %}

   {% tab title="ARM Template" %}
   Configuration: 
Update your existing Container App ARM Template to include the necessary Datadog App Settings and sidecar, as follows:

   ```jsonc
   {
     "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
     "contentVersion": "1.0.0.0",
     "parameters": {
       "datadogApiKey": {
         "type": "securestring"
       },
       "datadogSite": {
         "type": "string"
       },
       "service": {
         "type": "string",
         "defaultValue": "my-service"
       },
       "env": {
         "type": "string",
         "defaultValue": "dev"
       },
       "version": {
         "type": "string",
         "defaultValue": "0.0.0"
       }
     },
     "resources": [
       {
         "type": "Microsoft.App/containerApps",
         "apiVersion": "2024-03-01",
         // ...
         "properties": {
           "template": {
             "volumes": [
               {
                 "name": "shared-volume",
                 "storageType": "EmptyDir"
               }
               // Additional volumes
             ],
             "containers": [
               {
                 "name": "main",
                 "image": "index.docker.io/your/image:tag", // Replace with your Application Image
                 "resources": {
                   "cpu": 1,
                   "memory": "2Gi"
                 },
                 "env": [
                   {
                     "name": "DD_ENV",
                     "value": "[parameters('env')]"
                   },
                   {
                     "name": "DD_SERVICE",
                     "value": "[parameters('service')]"
                   },
                   {
                     "name": "DD_VERSION",
                     "value": "[parameters('version')]"
                   },
                   // Additional tracing/application env vars
                   {
                     "name": "DD_LOGS_INJECTION",
                     "value": "true"
                   }
                 ],
                 "volumeMounts": [
                   {
                     "volumeName": "shared-volume",
                     "mountPath": "/shared-volume"
                   }
                   // Additional volume mounts
                 ]
               },
               {
                 "name": "datadog-sidecar",
                 "image": "index.docker.io/datadog/serverless-init:latest",
                 "resources": {
                   "cpu": "0.5",
                   "memory": "1Gi"
                 },
                 "env": [
                   {
                     "name": "DD_AZURE_SUBSCRIPTION_ID",
                     "value": "[subscription().subscriptionId]"
                   },
                   {
                     "name": "DD_AZURE_RESOURCE_GROUP",
                     "value": "[resourceGroup().name]"
                   },
                   {
                     "name": "DD_API_KEY",
                     "value": "[parameters('datadogApiKey')]"
                   },
                   {
                     "name": "DD_SITE",
                     "value": "[parameters('datadogSite')]"
                   },
                   {
                     "name": "DD_SERVICE",
                     "value": "[parameters('service')]"
                   },
                   {
                     "name": "DD_ENV",
                     "value": "[parameters('env')]"
                   },
                   {
                     "name": "DD_VERSION",
                     "value": "[parameters('version')]"
                   },
                   {
                     "name": "DD_SERVERLESS_LOG_PATH",
                     // set this to wherever you write logs in the shared volume:
                     "value": "/shared-volume/logs/app.log"
                   }
                 ],
                 "volumeMounts": [
                   {
                     "volumeName": "shared-volume",
                     "mountPath": "/shared-volume"
                   }
                 ]
               }
             ],
             "scale": {
               "minReplicas": 1,
               "maxReplicas": 1,
               "rules": []
             }
           }
         }
       }
     ]
   }
   ```

Redeploy your updated template:

   ```shell
   az deployment group create --resource-group <RESOURCE GROUP> --template-file <TEMPLATE FILE>
   ```

See the Manual tab for descriptions of all environment variables.
   {% /tab %}

   {% tab title="Manual" %}
   Application environment variables: 
Because Azure Container Apps is built on Kubernetes, you cannot share environment variables between containers.

| Name         | Description                                                     |
| ------------ | --------------------------------------------------------------- |
| `DD_SERVICE` | How you want to tag your service. For example, `sidecar-azure`. |
| `DD_ENV`     | How you want to tag your env. For example, `prod`.              |
| `DD_VERSION` | How you want to tag your application version.                   |
Sidecar container: 
   1. In the Azure Portal, navigate to **Application** > **Revisions and replicas**. Select **Create new revision**.
   1. On the **Container** tab, under **Container image**, select **Add**. Choose **App container**.
   1. In the **Add a container** form, provide the following:
      - **Name**: `datadog`
      - **Image source**: Docker Hub or other registries
      - **Image type**: `Public`
      - **Registry login server**: `docker.io`
      - **Image and tag**: `datadog/serverless-init:<YOUR_TAG>`
      - Define your container resource allocation based on your usage.
   1. Add a volume mount using [replica-scoped storage](https://learn.microsoft.com/en-us/azure/container-apps/storage-mounts?pivots=azure-cli&tabs=smb#replica-scoped-storage). Use type "Ephemeral storage" when creating your volume. Ensure that the name and mount path matches the mount you configured in the application container.
   1. Set the environment variables in the following table:
Sidecar Environment variables: 
| Name                       | Description                                                                                                                                              |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DD_AZURE_SUBSCRIPTION_ID` | **Required**. Your Azure subscription ID.                                                                                                                |
| `DD_AZURE_RESOURCE_GROUP`  | **Required**. Your Azure resource group.                                                                                                                 |
| `DD_API_KEY`               | **Required**. Your [Datadog API key](https://app.datadoghq.com/organization-settings/api-keys).                                                          |
| `DD_SITE`                  | Your [Datadog site](https://docs.datadoghq.com/getting_started/site/). For example, `datadoghq.com`.                                                     |
| `DD_SERVICE`               | How you want to tag your service. For example, `sidecar-azure`.                                                                                          |
| `DD_ENV`                   | How you want to tag your env. For example, `prod`.                                                                                                       |
| `DD_VERSION`               | How you want to tag your application version.                                                                                                            |
| `DD_SERVERLESS_LOG_PATH`   | If using the agent for log collection, where you write your logs. For example, `/LogFiles/*.log`. This must match the logging path set up in Application |
Logging: 
If using the Datadog Agent for log collection, add a volume mount to the sidecar container *and* your application containers using [replica-scoped storage](https://learn.microsoft.com/en-us/azure/container-apps/storage-mounts?pivots=azure-cli&tabs=smb#replica-scoped-storage). Use type **Ephemeral storage** when creating your volume. The examples on this page use the volume name `logs` and the mount path `/LogFiles`.
   {% /tab %}

1. **Set up logs**.

In the previous step, you created a shared volume. In this step, configure your logging library to write logs to the file set in `DD_SERVERLESS_LOG_PATH`. In Node.js, we recommend writing logs in a JSON format. For example, you can use a third-party logging library such as `winston`:

   ```javascript
   const { createLogger, format, transports } = require('winston');
   
   const LOG_FILE = "/LogFiles/app.log"
   
   const logger = createLogger({
     level: 'info',
     exitOnError: false,
     format: format.json(),
     transports: [
       new transports.File({ filename: LOG_FILE }),
       new transports.Console()
     ],
   });
   
   logger.info('Hello world!');
```



Datadog recommends setting the environment variables `DD_LOGS_INJECTION=true` (in your main container) and `DD_SOURCE=nodejs` (in your sidecar container) to enable advanced Datadog log parsing.

For more information, see [Correlating Node.js Logs and Traces](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/nodejs/).

1. **Send custom metrics**.

To send custom metrics, [view code examples](https://docs.datadoghq.com/metrics/custom_metrics/dogstatsd_metrics_submission/?tab=nodejs#code-examples-5). In serverless, only the *distribution* metric type is supported.

1. **Enable profiling (preview)**.

To enable the [Continuous Profiler](https://docs.datadoghq.com/profiler/), set the environment variable `DD_PROFILING_ENABLED=true` in your application container.
Important alert (level: info): Datadog's Continuous Profiler is available in preview for Azure Container Apps.

### Environment variables{% #environment-variables %}

| Variable                 | Description                                                                                                                                                                                                                                                    | Container             |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `DD_API_KEY`             | [Datadog API key](https://app.datadoghq.com/organization-settings/api-keys) - **Required**                                                                                                                                                                     | Sidecar container     |
| `DD_SITE`                | [Datadog site](https://docs.datadoghq.com/getting_started/site/) - **Required**                                                                                                                                                                                | Sidecar container     |
| `DD_SERVICE`             | Datadog Service name. **Required**                                                                                                                                                                                                                             | Both containers       |
| `DD_SERVERLESS_LOG_PATH` | The path where the sidecar should tail logs from. Recommended to set to `/shared-volume/logs/app.log`.                                                                                                                                                         | Sidecar container     |
| `DD_LOGS_INJECTION`      | When true, enrich all logs with trace data for supported loggers. See [Correlate Logs and Traces](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/) for more information.                                                           | Application container |
| `DD_VERSION`             | See [Unified Service Tagging](https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/).                                                                                                                                                    | Both containers       |
| `DD_ENV`                 | See [Unified Service Tagging](https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/).                                                                                                                                                    | Both containers       |
| `DD_SOURCE`              | Set the log source to enable a [Log Pipeline](https://docs.datadoghq.com/logs/log_configuration/pipelines) for advanced parsing. To automatically apply language-specific parsing rules, set to `nodejs`, or use your custom pipeline. Defaults to `cloudrun`. | Sidecar container     |
| `DD_TAGS`                | Add custom tags to your logs, metrics, and traces. Tags should be comma separated in key/value format (for example: `key1:value1,key2:value2`).                                                                                                                | Sidecar container     |

**Do not set** the following environment variables in your serverless environment. They should only be set in non-serverless environments.

- `DD_AGENT_HOST`
- `DD_TRACE_AGENT_URL`

## Troubleshooting{% #troubleshooting %}

This integration depends on your runtime having a full SSL implementation. If you are using a slim image, you may need to add the following command to your Dockerfile to include certificates:

```dockerfile
RUN apt-get update && apt-get install -y ca-certificates
```

To have your Cloud Run services appear in the [software catalog](https://docs.datadoghq.com/internal_developer_portal/software_catalog/), you must set the `DD_SERVICE`, `DD_VERSION`, and `DD_ENV` environment variables.

## Further reading{% #further-reading %}

- [Tracing Node.js Applications](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/nodejs/)
- [Correlating Node.js Logs and Traces](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/nodejs/)
