@adatechnology/logger 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @adatechnology/logger
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - fix to use packages logger and use
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # Logger provider
2
+
3
+ Pacote que expõe um provider de logs seguindo o padrão das outras libs do monorepo.
4
+
5
+ Exporta `LoggerModule` e o token `LOGGER_PROVIDER`.
6
+
7
+ ## Exemplos de uso
8
+
9
+ 1. Uso padrão (Winston como implementação padrão):
10
+
11
+ ```ts
12
+ import { Module } from "@nestjs/common";
13
+ import { LoggerModule } from "@adatechnology/logger";
14
+
15
+ @Module({
16
+ imports: [
17
+ // Opção 1: Configuração estática (forRoot)
18
+ LoggerModule.forRoot({
19
+ level: 'debug',
20
+ context: 'MyService',
21
+ isProduction: process.env.NODE_ENV === 'production',
22
+ colorize: true,
23
+ }),
24
+
25
+ // Opção 2: Configuração dinâmica (forRootAsync)
26
+ LoggerModule.forRootAsync({
27
+ useFactory: (configService: ConfigService) => ({
28
+ level: configService.get('LOG_LEVEL'),
29
+ isProduction: configService.get('NODE_ENV') === 'production',
30
+ }),
31
+ inject: [ConfigService],
32
+ }),
33
+ ],
34
+ })
35
+ export class AppModule {}
36
+ ```
37
+
38
+ 2. Customizando o Winston e adicionando chaves sensíveis para ofuscar:
39
+
40
+ ```ts
41
+ import { Module } from "@nestjs/common";
42
+ import { LoggerModule } from "@adatechnology/logger";
43
+ import { transports } from "winston";
44
+
45
+ const loggerOptions = {
46
+ level: "debug",
47
+ transports: [new transports.Console()],
48
+ };
49
+
50
+ @Module({
51
+ imports: [
52
+ LoggerModule.forRoot({
53
+ loggerOptions,
54
+ // obfuscatorKeys aceita strings ou objetos { key, obfuscator }
55
+ obfuscatorKeys: [
56
+ "password",
57
+ {
58
+ key: "creditCard",
59
+ obfuscator: (v: any) =>
60
+ typeof v === "string" ? v.replace(/\d(?=\d{4})/g, "*") : "****",
61
+ },
62
+ ],
63
+ }),
64
+ ],
65
+ })
66
+ export class AppModule {}
67
+ ```
68
+
69
+ 3. Injetando o provider e usando nos serviços:
70
+
71
+ ```ts
72
+ import { Inject, Injectable } from "@nestjs/common";
73
+ import { LOGGER_PROVIDER } from "@adatechnology/logger";
74
+ import type { LoggerProviderInterface } from "@adatechnology/logger";
75
+
76
+ @Injectable()
77
+ export class FooService {
78
+ constructor(
79
+ @Inject(LOGGER_PROVIDER) private readonly logger: LoggerProviderInterface,
80
+ ) {
81
+ this.logger.info({ message: "iniciando FooService" });
82
+ }
83
+ }
84
+ ```
85
+
86
+ Observação: o obfuscator padrão é aplicado recursivamente em objetos e aceita entradas do tipo string (nome do campo) ou objetos `{ key, obfuscator }` para permitir funções customizadas do usuário.
87
+
88
+ Se quiser, eu adiciono um exemplo de teste unitário para validar o comportamento do obfuscator.
89
+
90
+ ## Padrão de Logging (Desenvolvimento)
91
+
92
+ Este pacote implementa um formato de log padronizado para todo o monorepo, facilitando o rastreamento de chamadas entre múltiplas bibliotecas e serviços.
93
+
94
+ ### Formato Final
95
+ `[App-name@version][lib-name:version][requestId][timestamp][source][libMethod][LEVEL] - message - {payload}`
96
+
97
+ ### Propriedades do Payload
98
+ Ao realizar um log, você pode passar as seguintes propriedades para enriquecer o contexto:
99
+
100
+ - `message`: A mensagem principal do log.
101
+ - `context`: O contexto geral (ex: nome da classe da biblioteca).
102
+ - `source`: O chamador original (breadcrumb). Ex: `HttpClientController.listPokemon`.
103
+ - `lib`: Nome da biblioteca que está gerando o log. Ex: `@adatechnology/http-client`.
104
+ - `libVersion`: Versão da biblioteca.
105
+ - `libMethod`: O método interno da biblioteca sendo executado. Ex: `get`.
106
+ - `meta`: Objeto com metadados adicionais (será exibido em uma única linha compacta).
107
+
108
+ ### Exemplo de Log de Biblioteca
109
+ Para uma biblioteca que segue o padrão:
110
+
111
+ ```ts
112
+ this.logger.info({
113
+ message: 'HTTP Request GET https://pokeapi.co/api/v2/pokemon',
114
+ context: 'HttpRedisClient',
115
+ lib: '@adatechnology/http-client',
116
+ libVersion: '0.0.2',
117
+ libMethod: 'get',
118
+ source: 'HttpClientController.listPokemon', // vindo do logContext da chamada
119
+ meta: { ... }
120
+ });
121
+ ```
122
+
123
+ Resultado visual:
124
+ `[App-example@0.0.3][@adatechnology/http-client:0.0.2][req-id][2026-03-29...][HttpClientController.listPokemon][HttpRedisClient.get][INFO] - HTTP Request... - { headers: ... }`
125
+
126
+ ## Middleware e contexto automático
127
+
128
+ O pacote oferece um middleware `RequestContextMiddleware` que injeta um `requestId` (a partir do header `x-request-id` ou gerando um UUID) e executa a request dentro de um contexto assíncrono (AsyncLocalStorage). Para usá-lo no NestJS:
129
+
130
+ ```ts
131
+ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
132
+ import { RequestContextMiddleware, LoggerModule } from '@adatechnology/logger';
133
+
134
+ @Module({ imports: [LoggerModule.forRoot()] })
135
+ export class AppModule implements NestModule {
136
+ configure(consumer: MiddlewareConsumer) {
137
+ consumer.apply(RequestContextMiddleware).forRoutes('*');
138
+ }
139
+ }
140
+ ```
141
+
142
+ Com o middleware ativo, o logger automaticamente incluirá `requestId` nos metadados quando não for passado explicitamente.
143
+
144
+ ## Request-scoped provider
145
+
146
+ Se desejar um provider por request (cada request recebe uma instância com `setContext` isolado), passe `requestScoped: true` ao `forRoot`:
147
+
148
+ ```ts
149
+ LoggerModule.forRoot({ requestScoped: true })
150
+ ```
151
+
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: logger
3
+ description: Patterns for @adatechnology/logger. Use when configuring Winston logging, managing Request-ID context (AsyncLocalStorage), or obfuscating sensitive data.
4
+ ---
5
+
6
+ # 📝 Logger Standards
7
+
8
+ ## 🚀 Setup Example
9
+ ```typescript
10
+ @Module({
11
+ imports: [
12
+ LoggerModule.forRoot({
13
+ level: 'info',
14
+ sensitiveKeys: ['password', 'token', 'clientSecret'],
15
+ }),
16
+ ],
17
+ })
18
+ export class AppModule implements NestModule {
19
+ configure(consumer: MiddlewareConsumer) {
20
+ // Required to enable Request-ID tracking across async calls
21
+ consumer.apply(RequestContextMiddleware).forRoutes('*');
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## 🏗️ Usage Pattern
27
+ ```typescript
28
+ @Injectable()
29
+ export class MyService {
30
+ constructor(
31
+ @Inject(LOGGER_PROVIDER) private readonly logger: LoggerProviderInterface
32
+ ) {}
33
+
34
+ doWork() {
35
+ this.logger.info('Action performed', { userId: '123' });
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## 🔐 Obfuscation
41
+ The logger automatically hides values for keys defined in `sensitiveKeys`.
42
+ - **Default Keys**: `password`, `token`, `authorization`, `cookie`, `secret`.
43
+ - **Custom Keys**: Add via `LoggerModule.forRoot()`.
44
+
45
+ ## 🛠️ Internal Mechanics
46
+ - **Async Context**: Uses `AsyncLocalStorage` to store the Request-ID.
47
+ - **Context Access**: Use `getContext()` to retrieve the current request state anywhere in the call stack.
@@ -0,0 +1,103 @@
1
+ import { DynamicModule, NestMiddleware } from '@nestjs/common';
2
+ import { LoggerOptions } from 'winston';
3
+
4
+ interface ObfuscatorKey {
5
+ key: string;
6
+ obfuscator: Obfuscator;
7
+ }
8
+ interface WinstonModuleConfig {
9
+ loggerOptions?: LoggerOptions;
10
+ obfuscator?: Obfuscator;
11
+ obfuscatorKeys?: Array<string | ObfuscatorKey>;
12
+ }
13
+ type Obfuscator = (value: unknown) => unknown;
14
+
15
+ declare enum LoggerLevel {
16
+ DEBUG = "debug",
17
+ INFO = "info",
18
+ WARN = "warn",
19
+ ERROR = "error"
20
+ }
21
+ interface LogPayload {
22
+ message: string;
23
+ context?: string;
24
+ meta?: Record<string, unknown>;
25
+ }
26
+ interface LoggerProviderInterface {
27
+ debug(payload: LogPayload): void;
28
+ info(payload: LogPayload): void;
29
+ warn(payload: LogPayload): void;
30
+ error(payload: LogPayload): void;
31
+ setContext?(context: string): void;
32
+ }
33
+
34
+ interface LoggerConfig extends WinstonModuleConfig {
35
+ /**
36
+ * Define se o provider do logger deve ser request-scoped
37
+ */
38
+ requestScoped?: boolean;
39
+ /**
40
+ * Nível de log padrão (string compatível com winston)
41
+ */
42
+ level?: LoggerLevel | string;
43
+ /**
44
+ * Contexto padrão para os logs
45
+ */
46
+ context?: string;
47
+ /**
48
+ * Define se o log deve ser formatado para produção (ex.: JSON)
49
+ */
50
+ isProduction?: boolean;
51
+ /**
52
+ * Define se deve colorir a saída (útil para desenvolvimento local)
53
+ */
54
+ colorize?: boolean;
55
+ /**
56
+ * Nome da aplicação para exibição nos logs
57
+ */
58
+ appName?: string;
59
+ /**
60
+ * Versão da aplicação para exibição nos logs
61
+ */
62
+ appVersion?: string;
63
+ /**
64
+ * Identificação da biblioteca/módulo que está gerando o log
65
+ */
66
+ lib?: string;
67
+ /**
68
+ * Versão da biblioteca/módulo que está gerando o log
69
+ */
70
+ libVersion?: string;
71
+ }
72
+ declare const DEFAULT_LOGGER_CONFIG: LoggerConfig;
73
+
74
+ declare const LOGGER_PROVIDER = "LOGGER_PROVIDER";
75
+
76
+ declare class LoggerModule {
77
+ static forRoot(config?: LoggerConfig): DynamicModule;
78
+ static forRootAsync(options: {
79
+ imports?: any[];
80
+ useFactory: (...args: any[]) => Promise<LoggerConfig> | LoggerConfig;
81
+ inject?: any[];
82
+ }): DynamicModule;
83
+ }
84
+
85
+ type RequestLike = {
86
+ headers?: Record<string, unknown> | undefined;
87
+ [key: string]: unknown;
88
+ };
89
+ type ResponseLike = {
90
+ [key: string]: unknown;
91
+ };
92
+ type NextFunctionLike = (err?: unknown) => void;
93
+
94
+ declare class RequestContextMiddleware implements NestMiddleware {
95
+ use(req: RequestLike, _res: ResponseLike, next: NextFunctionLike): void;
96
+ }
97
+
98
+ type RequestContext = Record<string, unknown> | undefined;
99
+
100
+ declare function getContext(): RequestContext;
101
+ declare function runWithContext<T>(ctx: Record<string, unknown>, fn: () => T): T;
102
+
103
+ export { DEFAULT_LOGGER_CONFIG, LOGGER_PROVIDER, type LogPayload, type LoggerConfig, LoggerLevel, LoggerModule, type LoggerProviderInterface, RequestContextMiddleware, getContext, runWithContext };