DEV Community

Cover image for Exploring OpenTelemetry Tracing in NestJS with RedisX
Suren Krmoian
Suren Krmoian

Posted on

Exploring OpenTelemetry Tracing in NestJS with RedisX

In today's complex application landscapes, observability is essential, providing insights into application performance and system behavior. OpenTelemetry has emerged as a robust standard for distributed tracing, enabling developers to capture detailed telemetry data across diverse systems. When combined with the power of NestJS and RedisX, OpenTelemetry tracing can provide unparalleled visibility into Redis operations and application performance.

Why OpenTelemetry?

OpenTelemetry offers a vendor-agnostic way to collect telemetry data, such as traces and metrics, from applications. It supports various backends like Jaeger, Zipkin, and Prometheus, making it a versatile choice for observability in distributed systems.

RedisX and OpenTelemetry

NestJS RedisX is a modular toolkit designed to integrate seamlessly with Redis, offering a suite of plugins for caching, locking, rate limiting, and more. The Tracing Plugin within RedisX leverages OpenTelemetry to trace every Redis command executed through the toolkit, providing insights into operations like cache hits/misses, lock acquisitions, and stream processing.

Setting Up OpenTelemetry Tracing in NestJS with RedisX

To integrate OpenTelemetry tracing in your NestJS application using RedisX, you need to follow these steps:

  1. Install Necessary Packages: Install the core and tracing packages:
   npm install @nestjs-redisx/core @nestjs-redisx/tracing
Enter fullscreen mode Exit fullscreen mode
  1. Configure the Tracing Plugin: Use TracingPlugin.registerAsync() for configuration, which allows dynamic setup with the ConfigService.
   import { Module } from '@nestjs/common';
   import { ConfigModule, ConfigService } from '@nestjs/config';
   import { RedisModule } from '@nestjs-redisx/core';
   import { TracingPlugin } from '@nestjs-redisx/tracing';

   @Module({
     imports: [
       ConfigModule.forRoot({ isGlobal: true }),
       RedisModule.forRootAsync({
         imports: [ConfigModule],
         inject: [ConfigService],
         plugins: [
           TracingPlugin.registerAsync({
             useFactory: (config: ConfigService) => ({
               enabled: config.get('TRACING_ENABLED', true),
               serviceName: config.get('SERVICE_NAME', 'my-service'),
               exporter: {
                 type: 'otlp',
                 endpoint: config.get('OTLP_ENDPOINT', 'http://localhost:4318'),
               },
               sampling: {
                 strategy: 'ratio',
                 ratio: config.get('TRACING_SAMPLE_RATIO', 1.0),
               },
             }),
             inject: [ConfigService],
           }),
         ],
         useFactory: (config: ConfigService) => ({
           clients: {
             host: config.get('REDIS_HOST', 'localhost'),
             port: config.get('REDIS_PORT', 6379),
           },
         }),
       }),
     ],
   })
   export class AppModule {}
Enter fullscreen mode Exit fullscreen mode
  1. Implement Tracing in Services: With RedisX, tracing is automatically applied to all Redis operations. However, you can also create custom spans for more granular insights.
   import { Injectable, Inject } from '@nestjs/common';
   import { TRACING_SERVICE, ITracingService } from '@nestjs-redisx/tracing';

   @Injectable()
   export class UserService {
     constructor(@Inject(TRACING_SERVICE) private readonly tracing: ITracingService) {}

     async getUser(id: string): Promise<unknown> {
       return this.tracing.withSpan('user.get', async () => {
         this.tracing.setAttribute('user.id', id);
         const user = await this.userRepo.findById(id);
         this.tracing.addEvent('user.found', { 'user.email': user.email });
         return user;
       });
     }
   }
Enter fullscreen mode Exit fullscreen mode

Benefits of Tracing with RedisX

  • Detailed Insights: Every Redis command is traced, providing a clear picture of how data flows through your application.
  • Performance Monitoring: Identify bottlenecks and optimize Redis usage by analyzing trace data.
  • Error Diagnosis: Quickly pinpoint where errors occur in the Redis interaction chain.
  • Seamless Integration: The Tracing Plugin integrates smoothly with other RedisX plugins, sharing the same Redis connection.

Integrating OpenTelemetry tracing with NestJS and RedisX will not only enhance your observability but also empower you to make data-driven decisions to optimize application performance. With the detailed insights that tracing provides, teams can improve system reliability and user experience, making it an indispensable part of modern application development.
nestjs redis tracing

Top comments (1)

Collapse
 
mickyarun profile image
arun rajkumar

The auto-tracing-on-every-Redis-command default is the right call — the failures that actually cost us were the ones where Redis looked fine in isolation but a cache miss cascaded into a slow downstream call nobody was tracing. One thing worth flagging for anyone wiring this up in prod: ratio sampling at 1.0 is great in dev but will bury you in span volume (and cost) under real traffic. We sample head-based low and force-sample anything that errors or crosses a latency threshold, so the spans we keep are the ones we'd actually open. Have you wired the RedisX spans into the wider trace context, so a cache lookup shows up on the same trace as the HTTP request that triggered it?