Nest.JS

TracesMetricsApp LogsCustom LogsProfiling

1. Prerequisites

Node.js 18.17.1+ and Python 3.8+ (for builds like node-gyp). Check with:

1node --version
2python3 --version
  • Middleware Host Agent on the same machine/cluster (Host mode). In containers, set MW_AGENT_SERVICE so your app can reach the agent:
    • Docker: MW_AGENT_SERVICE=172.17.0.1
    • Kubernetes: MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local (Use this only when the app isn’t on the host network namespace.)

2. Install Nest.js APM package

1npm install @middleware.io/nestjs-apm

3. Initialise the module (and add the interceptor)

Add the module in app.module.ts. Use serviceName (and optionally projectName). Then add the global interceptor in main.ts so requests/spans are captured.

app.module.ts:

1import { Module } from '@nestjs/common';
2import { MiddlewareApmModule } from '@middleware.io/nestjs-apm';
3
4
5@Module({
6  imports: [
7    MiddlewareApmModule.forRoot({
8      projectName: 'Your application name',
9      serviceName: 'Your service name',
10      // You may also set options via env vars (see table below)
11    }),
12  ],
13})
14export class AppModule {}

main.ts

1import { NestFactory, Reflector } from '@nestjs/core';
2import { AppModule } from './app.module';
3import { MiddlewareApmInterceptor } from '@middleware.io/nestjs-apm';
4
5async function bootstrap() {
6  const app = await NestFactory.create(AppModule);
7  app.useGlobalInterceptors(new MiddlewareApmInterceptor(app.get(Reflector)));
8  await app.listen(3000);
9}
10bootstrap();

4. Basic Usage

Ignore routes you don’t want traced (e.g., health checks):

1import { Controller, Get } from '@nestjs/common';
2import { IgnoreApmTrace } from '@middleware.io/nestjs-apm';
3
4@Controller('users')
5export class UsersController {
6  @IgnoreApmTrace()
7  @Get('health')
8  healthCheck() {
9    return 'OK';
10  }
11}

5. Advanced instrumentation

Custom attributes:

1import { Controller, Post } from '@nestjs/common';
2import { WithAttributes } from '@middleware.io/nestjs-apm';
3
4@Controller('orders')
5export class OrdersController {
6  @WithAttributes({ 'business.type': 'order', 'business.tier': 'premium' })
7  @Post()
8  createOrder() {}
9}

Custom spans:

1import { Injectable } from '@nestjs/common';
2import { CreateSpan } from '@middleware.io/nestjs-apm';
3
4@Injectable()
5export class UserService {
6  @CreateSpan('user.registration', { 'user.type': 'new' })
7  async registerUser() {}
8}

Record method params as span attributes:

1import { Controller, Post } from '@nestjs/common';
2import { RecordParams } from '@middleware.io/nestjs-apm';
3
4@Controller('users')
5export class UsersController {
6  @RecordParams(['userId', 'action'])
7  @Post(':userId/action')
8  performAction(userId: string, action: string) {}
9}

Logging integration (Nest logger is captured automatically):

1import { Logger, Injectable } from '@nestjs/common';
2
3@Injectable()
4export class UserService {
5  private readonly logger = new Logger(UserService.name);
6  async createUser() {
7    try {
8      this.logger.log('Creating new user');
9    } catch (e) {
10      this.logger.error('Failed to create user', e);
11      throw e;
12    }
13  }
14}

6. Serverless (no Host Agent)

Send directly to Middleware by supplying your tenant target and API key. Put options in forRoot (or via env vars).

1MiddlewareApmModule.forRoot({
2  serviceName: 'Your service',
3  projectName: 'Your app',
4  accessToken: '<MW_API_KEY>',
5  target: 'https://<MW_UID>.middleware.io:443',
6});

(Use secrets manager for keys in production.)

7. View your data

Give it 3–5 minutes after starting, then open APM → Traces, Logs, and APM → Continuous Profiling in your Middleware account.

8. Environment variables — quick reference

These map 1:1 to MiddlewareApmModule.forRoot options (env usually wins). Values shown are typical; defaults noted where the package defines them.

VariableMaps to (forRoot)Purpose / DefaultExample
MW_API_KEYaccessTokenAuth token used to export data. No default.xxxxxxxx…
MW_TARGETtargetOTLP endpoint (serverless/remote). Default: http://localhost:9319https://<MW_UID>.middleware.io:443
MW_SERVICE_NAMEserviceNameAPM service identifier.payments-svc
MW_PROJECT_NAMEprojectNameLogical project/app name.ShopApp
MW_CONSOLE_EXPORTERconsoleExporterLog spans/metrics to console (dev). Default: falsetrue
MW_APM_TRACES_ENABLEDpauseTracesEnable/disable traces. Default: truetrue
MW_APM_METRICS_ENABLEDpauseMetricsEnable/disable metrics. Default: truetrue
MW_SELF_INSTRUMENTATIONenableSelfInstrumentationTrace the APM itself. Default: falsefalse
MW_FS_INSTRUMENTATIONenableFsInstrumentationFilesystem tracing (⚠️ perf cost). Default: falsefalse
MW_NODE_DISABLED_INSTRUMENTATIONSdisabledInstrumentationsComma-separated list of instrumentations to disable.dns, net
MW_AGENT_SERVICE(Host-agent helper)Host/Service for agent in containers (Docker/K8s).172.17.0.1 / mw-service.mw-agent-ns.svc.cluster.local

(Env → option mappings and defaults come from the package README; MW_AGENT_SERVICE comes from the Node APM guidance for container networking.)

9. Troubleshooting quick checks

  • No traces/logs? Ensure the global interceptor is added (see step 3).
  • Container cannot reach Host Agent? Set MW_AGENT_SERVICE as per Docker/K8s examples above.
  • Local debugging: set MW_CONSOLE_EXPORTER=true to echo telemetry to stdout.