open-telemetry / opentelemetry-js-contrib

OpenTelemetry instrumentation for JavaScript modules
https://opentelemetry.io
Apache License 2.0
703 stars 522 forks source link

Hi, I am not able to trace the mongodb in opentelemetry #683

Closed eharaj1 closed 2 years ago

eharaj1 commented 3 years ago

I have integrated OpenTelemetry in Nestjs with Jaeger and it's working fine, but i am not able to trace the MongoDB interaction. I am using below code

const sdk = new opentelemetry.NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'demo-service',
  }),

  instrumentations: [getNodeAutoInstrumentations({
    "@opentelemetry/instrumentation-mongodb":{
        enhancedDatabaseReporting: true
        }
        }),

    ],
  spanProcessor: new BatchSpanProcessor(new JaegerExporter(options))
});

I tried without MongoDB instrument also

instrumentations: [getNodeAutoInstrumentations()],
  spanProcessor: new BatchSpanProcessor(new JaegerExporter(options))
});
Flarna commented 3 years ago

Which version of mongodb do you use?

eharaj1 commented 3 years ago

@Flarna Thanks for message. I am using Mongo 5.0.3 in docker

Flarna commented 3 years ago

@eharaj1 The latest version of mongodb driver according to https://www.npmjs.com/package/mongodb is 4.1.2

But the instrumentation only supports >=3.3 <4 as of now

eharaj1 commented 3 years ago

@Flarna I am running mongodb in docker container and there is showing mongo shell version 5.0.3 and mongo server version 5.0.3

eharaj1 commented 3 years ago

@Flarna , sorry you meant mongodb version in nodejs, Yes i am using mongodb 4.1.1

eharaj1 commented 3 years ago

@Flarna Now also tried mongodb 3.7.1 version but not getting the trace.

Flarna commented 3 years ago

Have you tried to additionally use @opentelemetry/instrumentation-nestjs-core as you wrote that you use NestJs? Most likely there is some context loss somewhere in your application. If possible provide a short reproducer here otherwise it's quite hard to debug this.

eharaj1 commented 3 years ago

@Flarna I tried @opentelemetry/instrumentation-nestjs-core and from this Jaeger not showing the service, below is the code which i tried.

import {NestInstromentaion} from '@opentelemetry/instrumentation-nestjs-core'

instrumentations: [new NestInstrumentation()],
  spanProcessor: new BatchSpanProcessor(new JaegerExporter(options))
});

But when i tried below code i am getting the trace of service on Jaeger but only the issue is not getting trace of mongodb interaction

import  { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node"

instrumentations: [getNodeAutoInstrumentations()],
  spanProcessor: new BatchSpanProcessor(new JaegerExporter(options))
});
Flarna commented 3 years ago

In your code snippets no mongodb operations are done. You just show how you initialize OTel. Mongodb instrumentation works for sure in other scenarios. Therefore the culprit is somewhere in the way how your application uses OTel + mongodb + nestjs (and maybe more).

A reproducer which actually uses mongodb would be helpful for others to start debugging.

eharaj1 commented 3 years ago

@Flarna Ok let me share the whole code,

tracing.ts


/* tracing.js */

import { JaegerExporter } from "@opentelemetry/exporter-jaeger";
const { BatchSpanProcessor } = require("@opentelemetry/tracing");
import  * as process from "process"
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
// Require dependencies
import * as opentelemetry  from "@opentelemetry/sdk-node";
//const prometheusExporter = new PrometheusExporter();
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";

const options =  {
  tags: [], // optional
  // You can use the default UDPSender
  host:'localhost', // optional
  port: 6832, // optional
  // OR you can use the HTTPSender as follows
  //endpoint: 'http://localhost:4317',
  maxPacketSize: 65000 // optional
}
const sdk = new opentelemetry.NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: process.env.JAEGER_SERVICE_NAME,
  }),
  //traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
  //metricExporter: prometheusExporter,
  instrumentations: [getNodeAutoInstrumentations()],
  spanProcessor: new BatchSpanProcessor(new JaegerExporter(options))
});

process.on("SIGTERM", () => {
  sdk
    .shutdown()
    .then(
      () => console.log("SDK shut down successfully"),
      (err) => console.log("Error shutting down SDK", err)
    )
    .finally(() => process.exit(0));
});

export default sdk;

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './modules/app/app.module';
import sdk from './tracing';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

 await sdk.start();

  await app.listen(process.env.PORT || 3001);
}
bootstrap();

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsModule } from '../cats/cats.module';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';

/// Mongo Connection /////////
const mongooseModule  = MongooseModule.forRoot(process.env.MONGO_URL || 'mongodb://localhost:27017/demo');

@Module({
  imports: [
      CatsModule, 
     mongooseModule,
      ConfigModule.forRoot({
        isGlobal: true,
      })
    ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

cats.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsSchema } from '../schemas/cats.scheme';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
    imports : [
        MongooseModule.forFeature([{
            name: 'Cats',
            schema: CatsSchema,
          }])
        ],
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

cats.controller.ts

import { Controller, Get,  Query, Post, Body, HttpException, HttpStatus, Param, UseFilters } from '@nestjs/common';
import {CatCreateValidator} from '../dto/validator.dto'
import {CatsService} from './cats.service';

@Controller('cats')
export class CatsController {

constructor(private readonly catsService: CatsService, private readonly redis: RedisService) {}

  @Get()
  async findAll() {
    try{
        return this.catsService.getAll();
    }catch(error){
        throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR)
    }

  }

  @Get("/:id")
 async getCat(@Param('id') cat_id: string){

    try{
        return await this.catsService.getCat(cat_id);
    }catch(error){
        throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR)
    }
  }

  @Post()
  async insertCat(@Body() body: CatCreateValidator){
      try{
        return await this.catsService.insertCat(body);
      }catch(error){
        throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR)
      }

  }
}

cats.service.ts

import { Injectable } from '@nestjs/common';
import { ResponseDTO } from '../dto/response.dto';
import  {CATS_MESSAGES}  from 'src/shared/constants';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { ICats } from '../interfaces/cats.interface';
@Injectable()
export class CatsService {

    constructor(
        @InjectModel('Cats') private readonly catsModel: Model<ICats>
        ) {}

     async getAll(): Promise<any> {
        const resDTO = new ResponseDTO();
        const cats = await this.catsModel.find();
        resDTO.success = true;
        resDTO.data = cats;
        return resDTO;

    }

     async getCat(cat_id: string): Promise<any> {
        const resDTO = new ResponseDTO();
        const cat = await this.catsModel.findById(cat_id)
        if(cat){
            resDTO.success = true;
            resDTO.data = cat; 
        }else{
            resDTO.success = false;
            resDTO.message = CATS_MESSAGES.CAT_NOTFOUND;
        }
        return resDTO;
    }
    insertCat(cat: any): ResponseDTO{
        const resDTO = new ResponseDTO();
        this.catsModel.create(cat);
        resDTO.success = true;
        resDTO.data = cat;
        resDTO.message = CATS_MESSAGES.CAT_CREATED;
        return resDTO;
    }
  }

I hope this is enough to reproduce and check the code.

vmarchaud commented 3 years ago

You should import the tracing sdk before any other module, could you move up the tracing require before nest ?

eharaj1 commented 3 years ago

@vmarchaud Can you share the sequence of importing the module with example, It would be better to understand the sequence.

Flarna commented 3 years ago

in main.ts instead

import { NestFactory } from '@nestjs/core';
import { AppModule } from './modules/app/app.module';
import sdk from './tracing';

try

import sdk from './tracing';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './modules/app/app.module';
eharaj1 commented 3 years ago

Hi,

I tried this above sequence and still the same issue also in this case service name is getting undefined on Jaeger panel.

eharaj1 commented 3 years ago

Hi Team,

Please assist me on this, I am stuck from last few days.

YanivD commented 3 years ago

@eharaj1 I don't know why you don't get mongo spans. I just want to mention you might be able to use the mongoose instrumentation.

kubabialy commented 2 years ago

@eharaj1 I wonder if you managed to resolve the issues. If so, would you be so kind to share how you managed to do so?

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

github-actions[bot] commented 2 years ago

This issue was closed because it has been stale for 14 days with no activity.

ivar891 commented 2 years ago

@kubabialy , tracing should be started as the first thing during your application start const tracer = require('./tracing')('serviceName') ./tracing should register required instrumentations