# Unlocking the Power of OpenTelemetry: A Comprehensive Guide

In today’s complex, microservices-driven world, understanding how applications perform is more critical than ever. Enter OpenTelemetry, an open-source observability framework that simplifies capturing and correlating telemetry data across distributed systems. In this blog, we’ll explore what OpenTelemetry is, how it works, and why it’s a game-changer—with real-world examples to make things more relatable.

### What is OpenTelemetry?

Imagine you’re managing a delivery service with hundreds of drivers, each taking unique routes. To ensure timely deliveries, you need real-time updates on driver locations, road conditions, and package statuses. OpenTelemetry does something similar for your applications—it collects data about their health and performance, helping you stay in control.

OpenTelemetry is an open-source observability framework that collects telemetry data—metrics, logs, and traces—from cloud-native applications. Governed by the Cloud Native Computing Foundation (CNCF), it’s designed to simplify monitoring for distributed systems.

### Key Features of OpenTelemetry

1. **Cross-Language Support**: Use it with Java, Python, JavaScript, Go, .NET, and more.
    
2. **Unified Data Model**: Collect metrics, logs, and traces with a single API.
    
3. **Interoperability**: Works with tools like Prometheus, Grafana, and Jaeger.
    
4. **Auto-Instrumentation**: Add monitoring to your app without writing extra code.
    

### Why OpenTelemetry? A Real-Life Scenario

Imagine you run an e-commerce platform. During a sale, users complain about slow checkout times. Without observability, you’d be guessing the cause—a slow database, a buggy API, or overloaded servers. With OpenTelemetry, you’d have detailed traces showing:

* A specific API call causing the delay
    
* How long it takes for the database to respond
    
* Which microservice is the bottleneck
    

This clear view helps you fix the issue faster and keeps your customers happy.

### Benefits of OpenTelemetry

#### 1\. **End-to-End Observability**

Picture this: a user clicks “Buy Now,” and OpenTelemetry tracks that request from the frontend through APIs, databases, and back—pinpointing slow spots instantly.

#### 2\. **Vendor Agnostic**

Say goodbye to being locked into a single monitoring tool. Instrument your code once, and send data to any backend you prefer, from Prometheus to Datadog.

#### 3\. **Developer-Friendly**

Forget juggling multiple libraries for logs, traces, and metrics. With OpenTelemetry’s unified APIs, you can spend more time coding and less time configuring.

## Let’s Get Practical: Implementing OpenTelemetry

### **Step 1: Set Up a Basic Node.js Application**

1. **Initialize the Project:**
    

```bash
mkdir opentelemetry-demo
cd opentelemetry-demo
npm init -y
```

2. **Install Express**:
    

```bash
npm install express
```

3. **Create the Application File**: Create a file named `app.js` with the following content:
    

```javascript
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, OpenTelemetry!');
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});
```

### **Step 2: Install OpenTelemetry Packages**

Install the necessary OpenTelemetry packages:

```bash
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
```

### **Step 3: Configure OpenTelemetry**

1. **Create a Tracing Configuration File**: Create a file named `tracing.js` with the following content:
    

```javascript
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-base');

const sdk = new NodeSDK({
// for demostration purpose I am just using console exporter here
// so that we get span in console when we make any request
  traceExporter: new ConsoleSpanExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();
```

***Span:*** <mark>A Span represents a unit of work. They can be thought of as the work being done during an operation’s execution. You can read more about it </mark> [<mark>https://medium.com/dzerolabs/observability-journey-understanding-logs-events-traces-and-spans-836524d63172</mark>](https://medium.com/dzerolabs/observability-journey-understanding-logs-events-traces-and-spans-836524d63172)

2. **Integrate Tracing into Our Application:** In your main application file (e.g., `app.js`), we have to first import `tracing.js` for initializing it
    

```javascript
require('./tracing'); // Initialize tracing

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, OpenTelemetry!');
});

app.get('/products', (req, res) => {
    res.send('products fetching');
  });

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});
```

In above example we uses `ConsoleSpanExporter` to get the spans in console. Now when you make a request to `/products` route. it will show different state of a call. Let say you make a call to `/products` route. it will generate spans for `'GET /products'` , `'request handler - /products'`, `'middleware-expressInit’` `'middleware - query',` with all the details like timestamp, duration, status\_code etc. Here we are using only 1 service but it is more useful when your product have micro-services talking to each other for a operation to be completely done.

## Spans Generated for each step in console -

1. ### Parent Span - `/products`
    

```javascript
{
  resource: {
    attributes: {
      'service.name': 'unknown_service:node',
      'telemetry.sdk.language': 'nodejs',
      'telemetry.sdk.name': 'opentelemetry',
      'telemetry.sdk.version': '1.30.1',
      'process.pid': 83799,
      'process.executable.name': 'node',
      'process.executable.path': '/path/to/node',
      'process.command_args': [
        '/path/to/node',
        '/path/to/app.js'
      ],
      'process.runtime.version': '23.4.0',
      'process.runtime.name': 'nodejs',
      'process.runtime.description': 'Node.js',
      'process.command': '/path/to/app.js',
      'process.owner': 'user',
      'host.name': 'host-name.local',
      'host.arch': 'arm64',
      'host.id': '8c0CB8DB-47FF-5BC2-A89D-EF1D94077FFE' // using representation of host id for demostration only
    }
  },
  instrumentationScope: {
    name: '@opentelemetry/instrumentation-http',
    version: '0.57.1',
    schemaUrl: undefined
  },
  traceId: '843f7b03dc67f95b775f3e5e63e8e191',
  parentId: undefined,
  traceState: undefined,
  name: 'GET /products', // genrated when execution come to /products endpoint
  id: 'f07cbc8ef59a1f6d',
  kind: 1,
  timestamp: 1740487705464000,
  duration: 14133.75,
  attributes: {
    'http.url': 'http://localhost:3000/products',
    'http.host': 'localhost:3000',
    'net.host.name': 'localhost',
    'http.method': 'GET',
    'http.scheme': 'http',
    'http.target': '/products',
    'http.user_agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
    'http.flavor': '1.1',
    'net.transport': 'ip_tcp',
    'net.host.ip': '::1',
    'net.host.port': 3000,
    'net.peer.ip': '::1',
    'net.peer.port': 63507,
    'http.status_code': 304,
    'http.status_text': 'NOT MODIFIED',
    'http.route': '/products'
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

2. ### Child Span - `request handler - /products`
    

```javascript
{
  resource: {
    attributes: {
      'service.name': 'unknown_service:node',
      'telemetry.sdk.language': 'nodejs',
      'telemetry.sdk.name': 'opentelemetry',
      'telemetry.sdk.version': '1.30.1',
      'process.pid': 83799,
      'process.executable.name': 'node',
      'process.executable.path': '/path/to/node',
      'process.command_args': [
        '/path/to/node',
        '/path/to/app.js'
      ],
      'process.runtime.version': '23.4.0',
      'process.runtime.name': 'nodejs',
      'process.runtime.description': 'Node.js',
      'process.command': '/path/to/app.js',
      'process.owner': 'user',
      'host.name': 'host-name.local',
      'host.arch': 'arm64',
      'host.id': '8c0CB8DB-47FF-5BC2-A89D-EF1D94077FFE' // using representation of host id for demostration only
    }
  },
  instrumentationScope: {
    name: '@opentelemetry/instrumentation-express',
    version: '0.47.0',
    schemaUrl: undefined
  },
  traceId: '843f7b03dc67f95b775f3e5e63e8e191',
  parentId: 'f07cbc8ef59a1f6d',
  traceState: undefined,
  name: 'request handler - /products',
  id: '31f73561dab0b8f7',
  kind: 0,
  timestamp: 1740487705471000,
  duration: 23.75,
  attributes: {
    'http.route': '/products',
    'express.name': '/products',
    'express.type': 'request_handler'
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

3. ### Child Span - `middleware - expressInit`
    

```javascript
{
  resource: {
    attributes: {
      'service.name': 'unknown_service:node',
      'telemetry.sdk.language': 'nodejs',
      'telemetry.sdk.name': 'opentelemetry',
      'telemetry.sdk.version': '1.30.1',
      'process.pid': 83799,
      'process.executable.name': 'node',
      'process.executable.path': '/path/to/node',
      'process.command_args': [
        '/path/to/node',
        '/path/to/app.js'
      ],
      'process.runtime.version': '23.4.0',
      'process.runtime.name': 'nodejs',
      'process.runtime.description': 'Node.js',
      'process.command': '/path/to/app.js',
      'process.owner': 'user',
      'host.name': 'host-name.local',
      'host.arch': 'arm64',
      'host.id': '8c0CB8DB-47FF-5BC2-A89D-EF1D94077FFE' // using representation of host id for demostration only
    }
  },
  instrumentationScope: {
    name: '@opentelemetry/instrumentation-express',
    version: '0.47.0',
    schemaUrl: undefined
  },
  traceId: '843f7b03dc67f95b775f3e5e63e8e191',
  parentId: 'f07cbc8ef59a1f6d',
  traceState: undefined,
  name: 'middleware - expressInit',
  id: '11b1672790af89b6',
  kind: 0,
  timestamp: 1740487705471000,
  duration: 411.75,
  attributes: {
    'http.route': '/',
    'express.name': 'expressInit',
    'express.type': 'middleware'
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

4. ### Child Span - `'middleware - query'`
    

```javascript
{
  resource: {
    attributes: {
      'service.name': 'unknown_service:node',
      'telemetry.sdk.language': 'nodejs',
      'telemetry.sdk.name': 'opentelemetry',
      'telemetry.sdk.version': '1.30.1',
      'process.pid': 83799,
      'process.executable.name': 'node',
      'process.executable.path': '/path/to/node',
      'process.command_args': [
        '/path/to/node',
        '/path/to/app.js'
      ],
      'process.runtime.version': '23.4.0',
      'process.runtime.name': 'nodejs',
      'process.runtime.description': 'Node.js',
      'process.command': '/path/to/app.js',
      'process.owner': 'user',
      'host.name': 'host-name.local',
      'host.arch': 'arm64',
      'host.id': '8c0CB8DB-47FF-5BC2-A89D-EF1D94077FFE' // using representation of host id for demostration only
    }
  },
  instrumentationScope: {
    name: '@opentelemetry/instrumentation-express',
    version: '0.47.0',
    schemaUrl: undefined
  },
  traceId: '843f7b03dc67f95b775f3e5e63e8e191',
  parentId: 'f07cbc8ef59a1f6d',
  traceState: undefined,
  name: 'middleware - query',
  id: 'd874c9995a60bfc3',
  kind: 0,
  timestamp: 1740487705469000,
  duration: 894.458,
  attributes: {
    'http.route': '/',
    'express.name': 'query',
    'express.type': 'middleware'
  },
  status: { code: 0 },
  events: [],
  links: []
}
```

You can access the source code [here](https://github.com/Abhishek332/my-blog-code-examples/tree/main/OpenTelemetry). Don't forget to follow me! 😊

### Common Use Cases

1. **Distributed Tracing**: Track requests across microservices to find performance bottlenecks.
    
2. **Performance Monitoring**: Measure how your application uses CPU, memory, and other resources.
    
3. **Error Diagnosis**: Correlate logs and traces to debug faster.
    

### The Future of OpenTelemetry

With its growing community and vendor-agnostic approach, OpenTelemetry is set to become the backbone of observability for modern applications. Its support for logs, metrics, and traces under one roof is transforming how developers monitor their systems.

### Wrapping Up

OpenTelemetry isn’t just another tool; it’s a revolution in observability. Whether you’re debugging a slow API or scaling a microservices architecture, it offers the insights you need to act fast. Start small, experiment, and watch as it transforms your approach to monitoring and performance optimization.

Why wait? Dive into OpenTelemetry today and see the difference firsthand!

For more information, check out the documentation: [https://opentelemetry.io/docs/](https://opentelemetry.io/docs/)

A curated list of OpenTelemetry Resources: [https://github.com/magsther/awesome-opentelemetry](https://github.com/magsther/awesome-opentelemetry)

Logfire is a great example of OpenTelemetry in use: [https://pydantic.dev/logfire](https://pydantic.dev/logfire).
