Monitoring Express.js with OpenTelemetry and Uptrace

vmihailenco

Vladimir Mihailenco

Posted on August 1, 2023

Monitoring Express.js with OpenTelemetry and Uptrace

What is tracing?

In modern applications, especially those based on microservices or serverless architectures, different services often interact with each other to fulfill a single user request. This makes it challenging to identify performance bottlenecks, diagnose issues, and analyze the overall system behavior.

Distributed tracing aims to address these challenges by creating a trace, which is a representation of a single user request's journey through the various services and components. Each trace consists of a series of interconnected spans, where each span represents an individual operation or activity within a specific service or component.

What is OpenTelemetry?

OpenTelemetry is an open source observability framework hosted by Cloud Native Computing Foundation. It is a merger of OpenCensus and OpenTracing projects.

OpenTelemetry aims to provide a single standard across all types of observability signals such as OpenTemetry logs, distributed tracing, and metrics.

OpenTelemetry specifies how to collect and send telemetry data to backend platforms. With OpenTelemetry, you can instrument your application once and then add or change vendors without changing the instrumentation.

Creating spans

To start creating spans, you need a tracer. You can create a tracer by providing the name and version of the library/application doing the instrumentation:

const otel = require('@opentelemetry/api')

const tracer = otel.trace.getTracer('app_or_package_name', '1.0.0')
Enter fullscreen mode Exit fullscreen mode

Once you have a tracer, creating spans is easy:

// Create a span with name "operation-name" and kind="server".
tracer.startActiveSpan('operation-name', { kind: otel.SpanKind.SERVER }, (span) => {
  doSomeWork()
  span.end()
})
Enter fullscreen mode Exit fullscreen mode

OpenTelemetry Node.js

Using the OpenTelemetry Node.js library, you can easily add distributed tracing capabilities to your Express.js applications.

To instrument an Express.js app, you need to install OpenTelemetry Node.js SDK and available instrumentations:

# Using npm
npm install @opentelemetry/sdk-node @opentelemetry/api @opentelemetry/auto-instrumentations-node

# Using yarn
yarn add @opentelemetry/sdk-node @opentelemetry/api @opentelemetry/auto-instrumentations-node
Enter fullscreen mode Exit fullscreen mode

You can let OpenTelemetry to instrument your application automatically or do it explicitly by installing required instrumentations, for example, OpenTelemetry Express instrumentation:

# Using npm
npm install @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express

# Using yarn
yarn add @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express
Enter fullscreen mode Exit fullscreen mode

Instrumenting Express.js with OpenTelemetry

After installing OpenTelemetry, you need to configure OpenTelemetry SDK to export data to an OpenTelemetry backend for strorage and visualization:

'use strict'

const otel = require('@opentelemetry/api')
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base')
const { Resource } = require('@opentelemetry/resources')
const { NodeSDK } = require('@opentelemetry/sdk-node')
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http')
const { AWSXRayIdGenerator } = require('@opentelemetry/id-generator-aws-xray')
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http')
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express')

const dsn = process.env.UPTRACE_DSN
console.log('using dsn:', dsn)

const exporter = new OTLPTraceExporter({
  url: 'http://localhost:14318/v1/traces',
  headers: { 'uptrace-dsn': dsn },
  compression: 'gzip',
})
const bsp = new BatchSpanProcessor(exporter, {
  maxExportBatchSize: 1000,
  maxQueueSize: 1000,
})

const sdk = new NodeSDK({
  spanProcessor: bsp,
  resource: new Resource({
    'service.name': 'myservice',
    'service.version': '1.0.0',
  }),
  idGenerator: new AWSXRayIdGenerator(),
  instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()],
})
sdk.start()
Enter fullscreen mode Exit fullscreen mode

To avoid potential issues, it is strongly recommended to put the OpenTelemetry initialization code into a separate file called otel.js and use the --require flag to load the tracing code before the application code:

# JavaScript
node --require ./otel.js app.js

# TypeScript
ts-node --require ./otel.ts app.ts
Enter fullscreen mode Exit fullscreen mode

See OpenTelemetry Express.js example for details.

What is Uptrace?

Uptrace is a popular DataDog alternative designed to monitor and analyze the performance of microservices-based architectures.

Uptrace provides end-to-end visibility into the flow of requests and transactions across a distributed system, enabling developers and operators to understand and optimize the behavior of their applications.

You can get started with Uptrace by downloading a DEB/RPM package or a pre-compiled Go binary.

What's next?

By integrating OpenTelemetry with Express.js, you can gain insight into your application's distributed traces, OpenTelemetry metrics, and logs. This helps you understand the behavior of your Express.js application across multiple services or microservices, and facilitates troubleshooting and performance optimization.

Next, instrument more operations to get a more detailed picture. Try to prioritize network calls, disk operations, database queries, error and logs.

You can also create your own instrumentations using OpenTelemetry JS Tracing API.

💖 💪 🙅 🚩
vmihailenco
Vladimir Mihailenco

Posted on August 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related