npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mobi4tech/nest-observability

v0.1.0

Published

Observability defaults for Mobi4Tech NestJS services

Readme

@mobi4tech/nest-observability

Defaults de observabilidade para aplicações NestJS: logs JSON com Pino, request ID, métricas Prometheus, liveness, readiness e eventos de negócio.

Compatibilidade

  • Node.js 20 ou 22;
  • NestJS 10 ou 11;
  • adapter HTTP Express;
  • rxjs 7.8 ou superior.

O pacote é estável. Fixe a versão durante a adoção para evitar upgrades acidentais.

Instalação

npm install @mobi4tech/[email protected]

Com Yarn:

yarn add @mobi4tech/[email protected]

Configuração mínima

Importe o módulo uma vez no módulo raiz:

import { Module } from '@nestjs/common';
import { ObservabilityModule } from '@mobi4tech/nest-observability';

@Module({
  imports: [
    ObservabilityModule.forRoot({
      serviceName: process.env.SERVICE_NAME ?? 'billing-api',
      environment: process.env.NODE_ENV ?? 'development',
      version: process.env.APP_VERSION ?? 'unknown',
      logLevel: process.env.LOG_LEVEL ?? 'info',
      ignoredHttpPathSuffixes: ['/refresh', '/notificacoes'],
      ignoredHttpPathPatterns: ['/portal-vendas/api/auth/*/silent-check'],
      ignoredHttpStatusCodeClasses: [3],
    }),
  ],
})
export class AppModule {}

No bootstrap, habilite o logger antes de configurar o prefixo global:

import { NestFactory } from '@nestjs/core';
import { configureObservability } from '@mobi4tech/nest-observability';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { bufferLogs: true });

  configureObservability(app);
  app.setGlobalPrefix('nome-do-servico/api');

  await app.listen(process.env.PORT ?? 3000);
}

void bootstrap();

O pacote passa a expor os endpoints abaixo do prefixo global:

| Endpoint | Comportamento | |---|---| | GET /nome-do-servico/api/metrics | Métricas Prometheus do processo e das requisições HTTP | | GET /nome-do-servico/api/health/live | HTTP 200 enquanto o processo estiver vivo | | GET /nome-do-servico/api/health/ready | HTTP 200 ou 503 conforme as dependências registradas |

Essas rotas devem ficar disponíveis apenas na rede interna. Não encaminhe /metrics ou /health/* pelo proxy público.

Configuração assíncrona

Use forRootAsync quando as opções vierem de outro provider:

import { ConfigModule, ConfigService } from '@nestjs/config';

ObservabilityModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    serviceName: config.getOrThrow<string>('SERVICE_NAME'),
    environment: config.get<string>('NODE_ENV', 'development'),
    version: config.get<string>('APP_VERSION', 'unknown'),
    logLevel: config.get<string>('LOG_LEVEL', 'info'),
    readinessTimeoutMs: 2_000,
  }),
});

Opções

| Opção | Obrigatória | Descrição | |---|---:|---| | serviceName | Sim | Nome estável do serviço, preferencialmente em kebab-case | | environment | Sim | Ambiente, como development, staging ou production | | version | Não | Versão/build exibido em logs e métricas | | logLevel | Não | Nível do Pino; padrão info | | redactPaths | Não | Caminhos adicionais que serão substituídos por [REDACTED] | | ignoredHttpPathSuffixes | Não | Sufixos cujos logs HTTP automáticos serão omitidos; métricas continuam ativas | | ignoredHttpPathPatterns | Não | Padrões glob (ex.: /auth/*/refresh) ou RegExp para omitir logs HTTP; métricas continuam ativas | | ignoredHttpStatusCodeClasses | Não | Classes HTTP a omitir dos logs automáticos (ex.: [3] para redirects); métricas continuam ativas | | readinessChecks | Não | Checks registrados durante a criação do módulo | | readinessTimeoutMs | Não | Timeout individual dos checks; padrão 2 segundos |

Logs JSON e request ID

O pacote usa stdout. PM2 ou o runtime do container deve capturar e rotacionar os logs; a aplicação não deve gravar arquivos próprios.

Uma requisição com X-Request-ID válido preserva o valor. Quando o header está ausente ou inválido, o pacote gera um UUID e devolve o identificador no header da resposta. Authorization, cookies, senhas, tokens, CPF/CNPJ e e-mail são redigidos por padrão.

Rotas muito frequentes e de baixo valor podem ser removidas apenas do log HTTP automático:

ignoredHttpPathSuffixes: ['/refresh', '/notificacoes'],
ignoredHttpPathPatterns: ['/portal-vendas/api/auth/*/silent-check'],
ignoredHttpStatusCodeClasses: [3],

A correspondência de sufixos e padrões ignora a query string; nos padrões, * representa qualquer trecho do caminho e também é possível passar um RegExp. ignoredHttpStatusCodeClasses: [3] remove redirects (3xx) apenas dos logs automáticos. As métricas HTTP continuam sendo coletadas. Não ignore login, alteração de senha ou outra rota de segurança sem manter eventos explícitos de sucesso e falha.

Para logs com atributos explícitos, injete StructuredLogger:

import { Injectable } from '@nestjs/common';
import { StructuredLogger } from '@mobi4tech/nest-observability';

@Injectable()
export class ImportService {
  constructor(private readonly logger: StructuredLogger) {}

  completed(records: number) {
    this.logger.info('import_completed', {
      file_type: 'proposal',
      records,
    });
  }

  failed(error: unknown) {
    this.logger.error(error, 'import_failed', {
      integration: 'carrier',
    });
  }
}

Não envie bodies, headers, DTOs, entidades ou mensagens de drivers inteiras para o logger. O serializer de erros remove error.message porque ela pode conter SQL, credenciais ou dados pessoais.

Cada log HTTP inclui req.path (o caminho real recebido) e req.route (a rota estável, como /clientes/:id). O segundo campo é o elo entre os painéis de métricas por rota e os logs no Grafana; não use o caminho real como rótulo de métrica, pois isso criaria uma série para cada identificador.

Eventos de negócio

Eventos devem usar nomes minúsculos separados por ponto e atributos de baixa cardinalidade:

this.logger.businessEvent({
  event: 'proposal.created',
  outcome: 'success',
  attributes: {
    carrier: 'example',
    proposal_type: 'individual',
  },
});

Também é possível registrar um evento de sucesso de forma abreviada:

this.logger.businessEvent('import.completed', { records: 10 });

Nunca use CPF/CNPJ, e-mail, token, request ID, IDs de banco ou URLs concretas como atributos de agregação ou labels.

Readiness

Checks podem ser informados nas opções ou registrados posteriormente:

import { Injectable, OnModuleInit } from '@nestjs/common';
import { ReadinessService } from '@mobi4tech/nest-observability';

@Injectable()
export class DatabaseReadinessProbe implements OnModuleInit {
  constructor(
    private readonly readiness: ReadinessService,
    private readonly database: DatabaseService,
  ) {}

  onModuleInit() {
    this.readiness.register('database', () => this.database.ping());
  }
}

O check deve ser leve e não deve lançar mensagens contendo credenciais ou dados pessoais, pois a mensagem resumida aparece na resposta interna de readiness.

Quando um serviço usa várias bases ou filas independentes, registre um check por dependência. Assim, /health/ready e as métricas indicam exatamente qual conexão falhou:

for (const name of databaseNames) {
  readiness.register(`database_${name.toLowerCase()}`, () =>
    databases.getDataSource(name).query('SELECT 1'),
  );
}

Use nomes estáveis, sem dados sensíveis. Cada check gera service_readiness_check_status (1 saudável, 0 indisponível) e service_readiness_check_duration_seconds.

Métricas fornecidas

  • http_server_requests_total;
  • http_server_request_duration_seconds;
  • http_server_requests_in_flight;
  • service_build_info;
  • métricas padrão do Node.js com prefixo nodejs_.

As labels HTTP são limitadas a método, rota normalizada e status code. IDs numéricos e UUIDs são normalizados para :id para evitar alta cardinalidade.

Produção com PM2

  • configure SERVICE_NAME, APP_VERSION, NODE_ENV e LOG_LEVEL;
  • não configure log_date_format, pois o prefixo quebra o JSON por linha;
  • configure rotação para os arquivos do PM2;
  • mantenha Prometheus e os endpoints internos acessíveis somente por loopback.

O playbook completo de migração e os problemas já conhecidos ficam no repositório de observabilidade.

Desenvolvimento e publicação

npm install
npm test --workspace=@mobi4tech/nest-observability
npm run publish:public --workspace=@mobi4tech/nest-observability

O comando de publicação executa build e testes por meio de prepublishOnly e publica a versão com a dist-tag beta.