Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add metrics module #967

Open
weeco opened this issue Aug 13, 2018 · 42 comments
Open

Add metrics module #967

weeco opened this issue Aug 13, 2018 · 42 comments
Labels
priority: very low (5) Very low-priority issue for consideration scope: common type: feature 🎉

Comments

@weeco
Copy link

weeco commented Aug 13, 2018

For a better monitoring of my Nest microservices I'd like to have a metrics endpoint which can be scraped by monitoring systems like Prometheus.

I believe a module written for NestJS could provide quite a couple metrics by default:

  • Metrics about the Node process resources (offered by default in the prom-client library)
  • Requests per second
    • All endpoints alltogether
    • Each endpoint
  • Request duration
    • All endpoints alltogether
    • Each endpoint
  • Number of responses grouped by response status codes for
    • All endpoints alltogether
    • Each endpoint
  • Response times in a bucket ([0-20ms, 20-50ms, ...]) for
    • All endpoints alltogether
    • Each endpoint

Beside these default metrics which could be offered out of the box, it should be easily possible to inject the metrics module into services, so that users can create custom metrics for their business code (e. g. number of registrations).

Using these metrics we can easily attach grafana to it and monitor our services:

Grafana dashboard

@kamilmysliwiec
Copy link
Member

Sounds great! Do you have any further ideas regarding this feature request? if so, feel free to share them, I'd love to get familiar with the community expectations. 🔥

@weeco
Copy link
Author

weeco commented Aug 17, 2018

Well the list of possible integrations with NestJS is kinda endless. Beside the given integrations which could come out of the box in NestJS, you could also offer metrics about:

  • Number of total routes bound in NestJS
  • Integration of other NestJS modules (e. g. auth - so that you can see Logins (and registrations) grouped by strategy), or websockets (expose number of actibe websocket connections, ...)
  • Offer the possibility to manage these out of the box metrics. Basically let a user disable, rename or manipulate specific metrics
  • Default Grafana board for NestJS (I am happy to create this)

You may want to keep in mind that there are other metrics formats beside Prometheus (such as DataDog, Graphite, etc.) which you may want to add at some point.

Spring boot already offers such a metrics module, you can probably get further inspiration there: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html

@cyril-lakech
Copy link

Maybe Trace from risingstack?

@dawiss1337
Copy link

By the way, swagger-stats (http://swaggerstats.io/) is very easy to plug into nest.js app, and you get an API endpoint (+ nice UI), that can be used to scrape metrics. However, you can't add your own metrics that easily.

@weeco
Copy link
Author

weeco commented Sep 20, 2018

@DavisJaunzems That looks interesting. Maybe we can use this as inspiration for our own metrics module. Two questions I wasn't able to figure out at a first glance:

  1. How does swaggerstats persist the information it shows in the panel? Does it use prometheus and puts a UI on top of that (similiar to Grafana)?
  2. How do you configure dynamic routes (e. g. https://example.com/users/{id}) . How does it know it should aggregate stats on example.com/users instead of collecting stats for each queried userId ?

@dawiss1337
Copy link

@weeco swagger stats stores the data in memory attached to the main node process (when restarted it starts from scratch), and for some metrics it only keeps last 100 entries. Then these values are exposed through prometheus friendly format that prometheus can pull.
It uses swagger.json information to know which routes to aggregate.

I have a simple monitoring solution on top of nest - you create injectable X and register values/functions to it. Then there is a global injectable that scans the nest.js context for these X injectables, and reads their values. Then there is a route that takes the global injectable values and displays them when route is accessed. Pretty simple solution, but not sure if it would make sense to be part of the main nest.js.

@spike008t
Copy link

spike008t commented Oct 1, 2018

I've just write a nest module for prometheus (see: https://github.com/digikare/nestjs-prom).
At the moment the module is quite simple... that is my first nestjs module.

@cojack
Copy link
Contributor

cojack commented Dec 14, 2018

@weeco but exactly what do you need swaggerstats.io provide, and this what @spike008t create solve a own metrics. So basically thread to close, or provide an PR for documentation HOW TO.

We're using swaggerstats.io for few our projects, and this is really great.

@weeco
Copy link
Author

weeco commented Dec 14, 2018

No @cojack you are wrong. swagger-stats (as the name already says) relies on swagger definitions. It's written a generic JavaScript library and therefore not written for a specific framework.

  1. First of all the NestJS way to create swagger docs is using Type annotations using @nestjs/swagger , which is really nice because this way the swagger definition is very close to the corresponding code.

  2. Also in NestJS we've got a lot more potential to do way more things automatically, instead of relying on self written swagger definition, which in practice or probably often out of sync with the actual code. NestJS does know or routes and our params. That's why NestJS is capable of creating a swagger documentation without you needing to write any documentation. We should use this potential and automatically create our prometheus stats for the given endpoints too. We can nicely integrate it into the framework which leads to a very nice user experience for developers

  3. Using Swagger stats you couldn't easily add your own custom business metrics as proposed here in the issue.

@kamilmysliwiec
Copy link
Member

kamilmysliwiec commented Dec 14, 2018

I'm pretty sure that you started to work on such integration already @weeco, correct? :)

@weeco
Copy link
Author

weeco commented Dec 14, 2018

@kamilmysliwiec Well not really, but I am working on a proof of concept to show you and/or @BrunnerLivio afterwards :-).

@kamilmysliwiec
Copy link
Member

Looking forward to it! If you have something to show already, let me know :)

@Chris2011
Copy link

@spike008t thx for the module. I need such integration for prometheus too, will check your module, whether it is enough for us or not.

@iangregsondev
Copy link

@weeco @kamilmysliwiec Do you know if any progress has been made on the integration of prometheus into the core of nestjs ?

I need to add this functionality next week :-)

@weeco
Copy link
Author

weeco commented Mar 27, 2019

@appsolutegeek To be honest I haven't worked on it for months anymore, as I am barely using NodeJS these days. Back in the days I had my own prometheus module + service for each project and added all desired metrics for each project on my own.

That was some boilerplate which I wanted to avoid (which is why I created this issue), but it doesn't block you from adding metrics on your own. I am pretty sure you won't get metrics built into NestJS until next week. I am not sure if Kamil or anyone else is working on this at all. Still seems to be the most requested feature though.

@iangregsondev
Copy link

Ok, yep, I will have a go at doing something quick myself. I just didn't want to reinvent the wheel if there was something available

@iangregsondev
Copy link

iangregsondev commented Apr 28, 2019

@spike008t Just saw your module over at https://github.com/digikare/nestjs-prom

Looks great, I will probably try to adapt it for my use. I presume you are not currently updating it ?

@kamilmysliwiec have you thought about pulling this module into nest and offering it out of the box like terminus, typeorm etc.

I must admit, I haven't tested it yet :-) - But it looks pretty much complete although the author does state there were some things left to improve.

@iangregsondev
Copy link

I thought I would relay my findings here, I am currently using the module in its current state. The author doesn't have time to maintain it anymore but its a great start and currently it does what I need - so I am quite happy.

So confirmed, tested and using it now in production!

@yevdev-fiscalnote
Copy link

https://github.com/digikare/nestjs-prom

Seems to work well. With a small tweak it should be possible to add a middleware or guard to restrict access to /metrics unless you come in via a management port. In the case of people that are coming from SpringBoot using port 8888. Then simply restrict access to that port in your infrastructure for internal use only.

https://docs.nestjs.com/faq/multiple-servers

@ZenSoftware
Copy link

ZenSoftware commented Jun 29, 2019

It would be really nice if we could get some more attention with respect to this. Nest has a lot of potential to provide amazing telemetry by integrating Prometheus. Being able to visualize spikes of 400-500 status codes for example would have tremendous value.

@Insidexa
Copy link

@kamilmysliwiec maybe create metrics nestjs module with appmetrics to export metrics nodejs app and nestjs some metrics as some standart.
Who need to export to prometheus / influxdb get info from "some" nestjs metrics standart.
Example export metrics to influx db from node app - https://github.com/Insidexa/traefik/blob/master/node-app/index.js
and show metrics on grafana dashboard

@SqueezeToyAliens
Copy link

Hi,

My company relies on Nest, and we forked and improved a Github project that integrates with Prometheus. It exports a Nest module and provides metrics for NodeJS and a few standard metrics for HTTP services(both are optional).

I can provide the Nest team access to the project for reviewing it if you think that it might be usable for you.

@kamilmysliwiec
Copy link
Member

I can provide the Nest team access to the project for reviewing it if you think that it might be usable for you.

That would be great @SqueezeToyAliens!

@omerxx
Copy link

omerxx commented Oct 29, 2019

Asking everyone on this thread (and @kamilmysliwiec @weeco @spike008t @SqueezeToyAliens in particular) Any progress with this? It would be awesome to implement something of this kind on our own product.
Thank you, guys!

@iangregsondev
Copy link

@omerxx I am using this https://github.com/digikare/nestjs-prom - it works well, i would love it to be merged into nestjs though.

Also would be interesting in knowing how the @SqueezeToyAliens implementation is/

@weeco
Copy link
Author

weeco commented Nov 24, 2019

In case it's helpful, that's the approach I use to instrument request durations in Go. I simply create a middleware which gets the "routePattern" (to avoid highly cardinal labels on dynamic routes), measure the request duration and put that along with the response status code into my Histogram:

https://github.com/kafka-owl/kafka-owl/blob/master/backend/pkg/common/middleware/instrument.go

PS: I'd also highly recommend to add metrics in the logger, which should be kinda easy if you can create a hook for the log events, see: https://github.com/kafka-owl/kafka-owl/blob/master/backend/pkg/common/logging/logger.go#L29-L54

logs

@Avejack
Copy link

Avejack commented Jun 11, 2020

I totally love nestjs - and it already comes with a lot of powerful tools and extensions. But this would be an enormous improvement!

Is there any progress or has this idea been abandoned?

@fieldju
Copy link

fieldju commented Jun 24, 2020

👋 , Hello I am a metrics nerd and primary maintainer of a few metrics/observability/canary libraries Kayenta, Node Measured, Armory's Spinnaker Observability Plugin

I am also a typescript advocate, I recently have discovered NestJs and +1 @Avejack's comment.

I would like to volunteer to own integrating a vendor-agnostic library and establish patterns for observability for NestJs similar to Springboot and Micrometer.

I think Node-Measured could fit the bill here.
I would want to take care of the following issue first yaorg/node-measured#82
But it would be great to integrate a vendor-agnostic metrics instrumentation library into this framework.

I wouldn't want to invest the time into ramping up in the NestJs internals and make the PR for this unless there was buy-in from the project owners and community.

Should we start and RFC, what would that look like I wonder?

https://discord.com/channels/520622812742811698/527863537708695562/725430518815916052

@kamilmysliwiec kamilmysliwiec added the priority: very low (5) Very low-priority issue for consideration label Feb 2, 2021
@mentos1386
Copy link

Hi all. Adding another promising library that handles metrics and tracing. OpenTelemetry which describes itself as "An observability framework for cloud-native software." and it's a part of CNCF and it's vendor agnostic.

NodeJS library written in Typescript can be found at https://github.com/open-telemetry/opentelemetry-js. I would expect from Nest Module to support some decorators for easier use, such as @SpanSetAttribute() for tracing which would set span attribute for the method called, or for metrics @IncementCounter(name) which would increment specific counter when method is called.

Ecosystem behind it has support for a bunch of services/providers. So writing a Nest module for it would bring Nest support for all of those services/providers.

@cojack
Copy link
Contributor

cojack commented Mar 16, 2021

@kamilmysliwiec I know how to do that without rewriting nest logic, add and implement @Proxy (build in JavaScript Proxy feature) decorator, that as the argument takes list of the classes for execution for set/get, this will allow us to unlimited operations before ANY method execution on ANY object that come from DI.

With great power comes great responsibility, but this will flip table upside down, there is no such a thing in any framework.

@jmcdo29
Copy link
Member

jmcdo29 commented Mar 17, 2021

@cojack this sounds really interesting. Is this something that can be made as a third party package, or does the @nestjs/commmon and @nestjs/core packages need to have modifications?

@cojack
Copy link
Contributor

cojack commented Mar 17, 2021

@jmcdo29 so this have to be done in the place where nest is creating instance of injectable class.

@Legion2
Copy link

Legion2 commented Mar 17, 2021

@cojack @jmcdo29 Implementing a Proxy features similar to what java ee cdi has with Client Proxy and Interceptors should be carefully designed and discussed in a separate issue.

@cojack
Copy link
Contributor

cojack commented Mar 17, 2021

@Legion2 what happen?!

@MetinSeylan
Copy link

MetinSeylan commented Jun 6, 2021

NestJS OpenTelemetry logo

NestJS OpenTelemetry

This library provides deeply integrated protocol-agnostic Nestjs OpenTelemetry instrumentations, metrics and SDK.

https://github.com/MetinSeylan/Nestjs-OpenTelemetry

Description

Nestjs is a protocol-agnostic framework. That's why this library can able to work with different protocols like RabbitMQ, GRPC and HTTP. Also you can observe and trace Nestjs specific layers like Pipe, Guard, Controller and Provider.

It also includes auto trace and metric instrumentations for some popular Nestjs libraries.

Installation

npm install @metinseylan/nestjs-opentelemetry --save

Configuration

This is a basic configuration without any trace and metric exporter, but includes default metrics and injectors

import { OpenTelemetryModule } from '@metinseylan/nestjs-opentelemetry';

@Module({
  imports: [OpenTelemetryModule.forRoot()]
})
export class AppModule {}

Default Parameters

key value description
traceAutoInjectors ControllerInjector, GuardInjector, EventEmitterInjector, ScheduleInjector, PipeInjector, LoggerInjector default auto trace instrumentations
metricAutoObservers ResourceMetric, ProcessStartTimeMetric, ProcessOpenFdsMetric, ProcessMaxFdsMetric, ActiveHandlesMetric, ActiveHandlesTotalMetric, HttpRequestDurationSeconds, GrpcRequestDurationSeconds, RabbitMqRequestDurationSeconds default auto metric collectors
autoDetectResources true inherited from NodeSDKConfiguration
contextManager AsyncLocalStorageContextManager default trace context manager inherited from NodeSDKConfiguration
instrumentations HttpInstrumentation default instrumentations inherited from NodeSDKConfiguration
spanProcessor NoopSpanProcessor default spanProcessor inherited from NodeSDKConfiguration
textMapPropagator JaegerPropagator, B3Propagator default textMapPropagator inherited from NodeSDKConfiguration

OpenTelemetryModule.forRoot() takes OpenTelemetryModuleConfig as a parameter, this type is inherited by NodeSDKConfiguration so you can use same OpenTelemetry SDK parameter.


Distributed Tracing

Simple setup with Zipkin exporter, including with default trace instrumentations.

import { OpenTelemetryModule } from '@metinseylan/nestjs-opentelemetry';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';

@Module({
  imports: [
    OpenTelemetryModule.forRoot({
      spanProcessor: new SimpleSpanProcessor(
        new ZipkinExporter({
          url: 'your-zipkin-url',
        })
      ),
    }),
  ],
})
export class AppModule {}

After setup, your application will be instrumented, so that you can see almost every layer of application in ZipkinUI, including Guards, Pipes, Controllers even global layers like this

Example trace output

List of supported official exporters here.


Trace Decorators

This library supports auto instrumentations for Nestjs layers, but sometimes you need to define custom span for specific method blocks like providers methods. In this case @Span decorator will help you.

import { Injectable } from '@nestjs/common';
import { Span } from '@metinseylan/nestjs-opentelemetry';

@Injectable()
export class AppService {
  @Span()
  getHello(): string {
    return 'Hello World!';
  }
}

Also @Span decorator takes name field as a parameter

@Span('hello')

Trace Providers

In an advanced usage case, you need to access the native OpenTelemetry Trace provider to access them from Nestjs application context.

import { Injectable } from '@nestjs/common';
import { Tracer } from '@opentelemetry/sdk-trace-base';

@Injectable()
export class AppService {
  constructor(private readonly tracer: Tracer) {}

  getHello(): string {
    const span = this.tracer.startSpan('important_section_start');
    // do something important
    span.setAttributes({ userId: 1150 });
    span.end();
    return 'Hello World!';
  }
}

TraceService can access directly current span context and start new span.

import { Injectable } from '@nestjs/common';
import { TraceService } from '@metinseylan/nestjs-opentelemetry';

@Injectable()
export class AppService {
  constructor(private readonly traceService: TraceService) {}

  getHello(): string {
    const span = this.traceService.startSpan('hello');
    // do something
    span.end();
    return 'Hello World!';
  }
}

Auto Trace Instrumentations

The most helpful part of this library is that you already get all of the instrumentations by default if you set up a module without any extra configuration. If you need to avoid some of them, you can use the traceAutoInjectors parameter.

import { Module } from '@nestjs/common';
import {
  OpenTelemetryModule,
  ControllerInjector,
  EventEmitterInjector,
  GuardInjector,
  LoggerInjector,
  PipeInjector,
  ScheduleInjector,
} from '@metinseylan/nestjs-opentelemetry';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';

@Module({
  imports: [
    OpenTelemetryModule.forRoot({
      traceAutoInjectors: [
        ControllerInjector,
        GuardInjector,
        EventEmitterInjector,
        ScheduleInjector,
        PipeInjector,
        LoggerInjector,
      ],
      spanProcessor: new SimpleSpanProcessor(
        new ZipkinExporter({
          url: 'your-zipkin-url',
        }),
      ),
    }),
  ]
})
export class AppModule {}

List of Trace Injectors

Instance Description
ControllerInjector Auto trace all of module controllers
GuardInjector Auto trace all of module guards including global guards
PipeInjector Auto trace all of module pipes including global pipes
EventEmitterInjector Auto trace for @nestjs/event-emitter library, supports all features
ScheduleInjector Auto trace for @nestjs/schedule library, supports all features
LoggerInjector ConsoleLogger and Logger class tracer, logs with traceId

Distributed Logging with Trace ID

When you set up your environment with the LoggerInjector class or default configuration, you can see trace id with every log.

Example trace output


Metrics

Simple setup with Prometheus exporter, you need install @opentelemetry/exporter-prometheus

import { OpenTelemetryModule } from '@metinseylan/nestjs-opentelemetry';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';

@Module({
  imports: [OpenTelemetryModule.forRoot({
    metricExporter: new PrometheusExporter({
      endpoint: 'metrics',
      port: 9464,
    })
  })]
})
export class AppModule {}

Now you can access Prometheus exporter with auto collected metrics http://localhost:9464/metrics.
Also, you can find different exporters here


Metric Decorators

If you need to observe simple block of function, you can use some basic decorators like @Counter and @Observer

Counter

import { Injectable } from '@nestjs/common';
import { Counter } from '@metinseylan/nestjs-opentelemetry';

@Injectable()
export class AppService {
  @Counter()
  getHello(): string {
    return 'Hello World!';
  }
}

@Counter decorator is uses OpenTelemetry Counter metric, If you check prometheus exporter you will see metric appservice_gethello_total

@Counter('call_me_mr_fahrenheit', {
  description: 'important function call counting here.'
})

And of course, you can configure your decorator metric, the first parameter is "name" and the second one is MetricOptions

Observer

import {Injectable} from '@nestjs/common';
import {Observer} from "./Observer";

@Injectable()
export class AppService {
  @Observer('nice_one_observer', {
    description: 'some description here.',
    boundaries: [10, 20, 30],
  })
  getHello(): string {
    return 'Hello World!';
  }
}

@Observer decorator uses OpenTelemetry ValueRecorder metric. If you check Prometheus exporter, you will see metric and configuration parameters same as @Counter.


Metric Providers

In advanced usage cases, you need to access the native OpenTelemetry Metric provider to access them from the Nestjs application context.

import { Injectable } from '@nestjs/common';
import { Meter } from '@opentelemetry/sdk-metrics-base';
import { Counter } from '@opentelemetry/api-metrics';

@Injectable()
export class AppService {
  private readonly counter: Counter;

  constructor(private readonly meter: Meter) {
    this.counter = this.meter.createCounter('handsome_counter');
  }

  getHello(): string {
    this.counter.add(1);
    return 'Hello World!';
  }
}

Auto Metric Observers

This library has extendable resource and protocol-specific Auto Observers. All of them come with default module configuration, which you can extend and configure.

import { Module } from '@nestjs/common';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
import {
  ActiveHandlesMetric,
  HttpRequestDurationSeconds,
  OpenTelemetryModule,
} from '@metinseylan/nestjs-opentelemetry';

@Module({
  imports: [
    OpenTelemetryModule.forRoot({
      metricAutoObservers: [
        HttpRequestDurationSeconds.build({
          boundaries: [20, 30, 100],
        }),
        ActiveHandlesMetric,
      ],
      metricExporter: new PrometheusExporter({
        endpoint: 'metrics',
        port: 9464,
      }),
      metricInterval: 1000,
    }),
  ],
})
export class AppModule {}

.build function takes MetricOptions as a parameter.

List Of Auto Observers

Metric Observer Provider Description Configurable
HttpRequestDurationSeconds Observe http request duration yes
GrpcRequestDurationSeconds Observe grpc request duration yes
RabbitMqRequestDurationSeconds Observe rabbitmq request duration yes
ResourceMetric Metrics of cpu, memory usage no
ProcessStartTimeMetric Start time of the process since unix epoch in seconds. no
ProcessOpenFdsMetric Number of open file descriptors. no
ProcessMaxFdsMetric Maximum number of open file descriptors. no
ActiveHandlesMetric Number of active libuv handles grouped by handle type. Every handle type is C++ class name. no
ActiveHandlesTotalMetric Total number of active handles. no

Example Output for HttpRequestDurationSeconds

Key Value
exception Empty string or exception instance name
method GET, POST, PUT, PATCH, DELETE
outcome INFORMATIONAL, SUCCESS, REDIRECTION, CLIENT_ERROR, SERVER_ERROR
status number of HttpStatus
uri url path

Lets Combine All of them

import { Module } from '@nestjs/common';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
import { OpenTelemetryModule } from '@metinseylan/nestjs-opentelemetry';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';

@Module({
  imports: [
    OpenTelemetryModule.forRoot({
      metricExporter: new PrometheusExporter({
        endpoint: 'metrics',
        port: 9464,
      }),
      metricInterval: 1000,
      spanProcessor: new SimpleSpanProcessor(
        new ZipkinExporter({
          url: 'your-zipkin-url',
        })
      ),
    }),
  ],
})
export class AppModule {}

@pragmaticivan
Copy link

I've been making some progress with a middleware here willsoto/nestjs-prometheus#950

It covers most of the cases here.

@lloydjatkinson
Copy link

I'm also very interested in this being a NestJS module - I think OpenTelemetry is going to be the "standard" for this stuff going forward. For example it's now officially supported in .NET: https://devblogs.microsoft.com/dotnet/opentelemetry-net-reaches-v1-0/

@pragmaticivan
Copy link

pragmaticivan commented Jun 25, 2021

If that helps someone here, I ended up creating a new library due to some urgency for some features and only relying on opentelemetry for both tracing and metrics.

Ended up solving some problems I had, but also documented how to integrate OTEL with things like structured logging.

https://github.com/pragmaticivan/nestjs-otel

It mainly uses open telemetry for everything. It covers:

  • System Metrics
  • NodeJS Metrics
  • Prometheus Exporter
  • API Metrics (Middleware)
  • New HTTP server on a different port for /metrics route.
  • OpenTelemetry Metrics support (Using is instead of Prometheus prom-client)
  • More to come this weekend.

@pragmaticivan
Copy link

Howdy! I've launched a new major version of nestjs-otel with improvements and now including full examples. (https://github.com/pragmaticivan/nestjs-otel)

A full working example can be found in /examples/nestjs-prom-grafana-tempo. This includes a nestjs application fully integrated with prometheus, grafana, loki and tempo.

A dashboard example is also available:
Screen Shot 2021-08-05 at 10 36 10 PM

Logs are automatically associated with tracing (Loki + Tempo):
Screen Shot 2021-08-05 at 10 37 35 PM

@pragmaticivan
Copy link

pragmaticivan commented Aug 18, 2021

Keep an eye for an upcoming package for NestJS self instrumentation with OpenTelemetry! https://github.com/open-telemetry/opentelemetry-js-contrib/pull/553/files

Also Fastify might be coming soon: open-telemetry/opentelemetry-js-contrib#611

@the-homeless-god
Copy link

the-homeless-god commented Feb 5, 2024

https://github.com/honnamkuan/nestjs-status-monitor/ works well without any 3rd-party-tool except socket.io

@ZenSoftware
Copy link

For those looking for some sample code of how to integrate OTEL into your Nest app, this was the only code that I needed to add to my project to do so:
https://github.com/ZenSoftware/zen/blob/otel/apps/api/src/tracing.ts

import { Logger } from '@nestjs/common';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { Resource } from '@opentelemetry/resources';
import {
  ConsoleMetricExporter,
  MeterProvider,
  MetricReader,
  PeriodicExportingMetricReader,
} from '@opentelemetry/sdk-metrics';
import {
  BatchSpanProcessor,
  ConsoleSpanExporter,
  SimpleSpanProcessor,
} from '@opentelemetry/sdk-trace-base';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { PrismaInstrumentation } from '@prisma/instrumentation';

import { environment } from './environments/environment';

const logger = new Logger('OTLP');

if (environment.openTelemetry) {
  const resource = Resource.default().merge(
    new Resource({
      [SemanticResourceAttributes.SERVICE_NAME]: environment.openTelemetry.serviceName,
    })
  );

  const useTracer =
    environment.openTelemetry.exporters?.traceConsole || environment.openTelemetry.exporters?.trace;
  const tracerProvider = useTracer ? new NodeTracerProvider({ resource }) : undefined;

  if (environment.openTelemetry.exporters?.traceConsole) {
    tracerProvider?.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
    logger.log('exporting traces to console');
  }

  if (environment.openTelemetry.exporters?.trace) {
    tracerProvider?.addSpanProcessor(
      new BatchSpanProcessor(new OTLPTraceExporter(environment.openTelemetry.exporters.trace))
    );
    logger.log(
      `exporting traces to ${
        environment.openTelemetry.exporters.trace.url ?? 'http://localhost:4318/v1/traces'
      }`
    );
  }
  tracerProvider?.register();

  /**
   * Metrics
   */
  const useMeter =
    environment.openTelemetry.exporters?.meterConsole || environment.openTelemetry.exporters?.meter;

  const readers: MetricReader[] = [];

  if (environment.openTelemetry.exporters?.meterConsole) {
    readers.push(
      new PeriodicExportingMetricReader({
        exporter: new ConsoleMetricExporter(),
        // exportIntervalMillis: 3000,
      })
    );
    logger.log('exporting metrics to console');
  }

  if (environment.openTelemetry.exporters?.meter) {
    readers.push(
      new PeriodicExportingMetricReader({
        exporter: new OTLPMetricExporter(environment.openTelemetry.exporters.meter),
        // exportIntervalMillis: 3000,
      })
    );
    logger.log(
      `exporting metrics to ${
        environment.openTelemetry.exporters.meter.url ?? 'http://localhost:4318/v1/metrics'
      }`
    );
  }

  const meterProvider = useMeter ? new MeterProvider({ resource, readers }) : undefined;

  registerInstrumentations({
    meterProvider,
    instrumentations: [
      new HttpInstrumentation(),
      new ExpressInstrumentation(),
      new GraphQLInstrumentation(),
      new PrismaInstrumentation(),
    ],
  });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: very low (5) Very low-priority issue for consideration scope: common type: feature 🎉
Projects
None yet
Development

No branches or pull requests