@globalart/nestjs-logger 1.0.1

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.
Files changed (40) hide show
  1. package/README.md +263 -0
  2. package/dist/constants/index.d.ts +22 -0
  3. package/dist/constants/index.js +38 -0
  4. package/dist/contracts/index.d.ts +26 -0
  5. package/dist/contracts/index.js +2 -0
  6. package/dist/core/http-logger.interceptor.d.ts +16 -0
  7. package/dist/core/http-logger.interceptor.js +97 -0
  8. package/dist/core/logger.module.d.ts +20 -0
  9. package/dist/core/logger.module.js +103 -0
  10. package/dist/core/logger.service.d.ts +19 -0
  11. package/dist/core/logger.service.js +60 -0
  12. package/dist/decorators/index.d.ts +8 -0
  13. package/dist/decorators/index.js +15 -0
  14. package/dist/factories/formatter.factory.d.ts +5 -0
  15. package/dist/factories/formatter.factory.js +31 -0
  16. package/dist/formatters/base-formatter.d.ts +12 -0
  17. package/dist/formatters/base-formatter.js +44 -0
  18. package/dist/formatters/json-formatter.d.ts +6 -0
  19. package/dist/formatters/json-formatter.js +36 -0
  20. package/dist/formatters/pino-formatter.d.ts +6 -0
  21. package/dist/formatters/pino-formatter.js +28 -0
  22. package/dist/formatters/text-formatter.d.ts +6 -0
  23. package/dist/formatters/text-formatter.js +45 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +31 -0
  26. package/dist/interceptors/index.d.ts +1 -0
  27. package/dist/interceptors/index.js +5 -0
  28. package/dist/interfaces/index.d.ts +59 -0
  29. package/dist/interfaces/index.js +2 -0
  30. package/dist/types/index.d.ts +50 -0
  31. package/dist/types/index.js +18 -0
  32. package/dist/utils/context-resolver.d.ts +7 -0
  33. package/dist/utils/context-resolver.js +68 -0
  34. package/dist/utils/data-sanitizer.d.ts +9 -0
  35. package/dist/utils/data-sanitizer.js +56 -0
  36. package/dist/utils/request-id-generator.d.ts +8 -0
  37. package/dist/utils/request-id-generator.js +34 -0
  38. package/dist/writers/console-writer.d.ts +4 -0
  39. package/dist/writers/console-writer.js +19 -0
  40. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # @globalart/nestjs-logger
2
+
3
+ Профессиональный модуль логирования для NestJS с чистой архитектурой, строгой типизацией и расширяемостью.
4
+
5
+ ## 🚀 Особенности
6
+
7
+ - **Clean Architecture** - разделение ответственности, SOLID принципы
8
+ - **Строгая типизация** - полная типобезопасность TypeScript
9
+ - **Производительность** - оптимизированная архитектура без лишних аллокаций
10
+ - **Расширяемость** - легко добавлять новые форматтеры и транспорты
11
+ - **Тестируемость** - dependency injection, легкое мокирование
12
+ - **Автоматический контекст** - определение класса из стека вызовов
13
+ - **HTTP логирование** - детальное логирование запросов
14
+ - **Безопасность** - автоматическая санитизация чувствительных данных
15
+ - **Цветной вывод** - красивые логи в консоли
16
+
17
+ ## 📦 Установка
18
+
19
+ ```bash
20
+ npm install @globalart/nestjs-logger
21
+ ```
22
+
23
+ ## 🎯 Быстрый старт
24
+
25
+ ```typescript
26
+ import { Module } from '@nestjs/common';
27
+ import { LoggerModule } from '@globalart/nestjs-logger';
28
+
29
+ @Module({
30
+ imports: [
31
+ LoggerModule.forRoot({
32
+ level: 'info',
33
+ timestamp: true,
34
+ colors: true,
35
+ format: 'text',
36
+ }),
37
+ ],
38
+ })
39
+ export class AppModule {}
40
+ ```
41
+
42
+ ## 🔧 Конфигурация
43
+
44
+ ### Синхронная конфигурация
45
+
46
+ ```typescript
47
+ LoggerModule.forRoot({
48
+ level: 'debug',
49
+ timestamp: true,
50
+ colors: true,
51
+ format: 'pino',
52
+ sensitiveFields: ['password', 'secret'],
53
+ })
54
+ ```
55
+
56
+ ### Асинхронная конфигурация
57
+
58
+ ```typescript
59
+ LoggerModule.forRootAsync({
60
+ useFactory: (configService: ConfigService) => ({
61
+ level: configService.get('LOG_LEVEL', 'info'),
62
+ format: configService.get('LOG_FORMAT', 'text'),
63
+ colors: !configService.get('PRODUCTION'),
64
+ }),
65
+ inject: [ConfigService],
66
+ })
67
+ ```
68
+
69
+ ## 📝 Использование
70
+
71
+ ### В сервисах
72
+
73
+ ```typescript
74
+ import { Injectable } from '@nestjs/common';
75
+ import { LoggerService } from '@globalart/nestjs-logger';
76
+
77
+ @Injectable()
78
+ export class UserService {
79
+ constructor(private readonly logger: LoggerService) {}
80
+
81
+ async createUser(userData: CreateUserDto) {
82
+ this.logger.log('Creating new user', undefined, { userId: userData.email });
83
+
84
+ try {
85
+ const user = await this.userRepository.save(userData);
86
+ this.logger.log('User created successfully', undefined, { id: user.id });
87
+ return user;
88
+ } catch (error) {
89
+ this.logger.error('Failed to create user', error.stack, undefined, {
90
+ email: userData.email
91
+ });
92
+ throw error;
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ### HTTP логирование
99
+
100
+ ```typescript
101
+ import { Controller, UseInterceptors } from '@nestjs/common';
102
+ import { HttpLoggerInterceptor, LogContext } from '@globalart/nestjs-logger';
103
+
104
+ @Controller('users')
105
+ @UseInterceptors(HttpLoggerInterceptor)
106
+ @LogContext('UserController')
107
+ export class UserController {
108
+ // Все HTTP запросы будут автоматически логироваться
109
+ }
110
+ ```
111
+
112
+ ### Глобальное HTTP логирование
113
+
114
+ ```typescript
115
+ import { Module } from '@nestjs/common';
116
+ import { APP_INTERCEPTOR } from '@nestjs/core';
117
+ import { LoggerModule, HttpLoggerInterceptor } from '@globalart/nestjs-logger';
118
+
119
+ @Module({
120
+ imports: [LoggerModule.forRoot()],
121
+ providers: [
122
+ {
123
+ provide: APP_INTERCEPTOR,
124
+ useClass: HttpLoggerInterceptor,
125
+ },
126
+ ],
127
+ })
128
+ export class AppModule {}
129
+ ```
130
+
131
+ ## 🎨 Форматы вывода
132
+
133
+ ### Text (по умолчанию)
134
+ ```
135
+ [2024-01-15T10:30:45.123Z] [INFO] [UserService] Creating new user {"userId":"123"}
136
+ ```
137
+
138
+ ### JSON
139
+ ```json
140
+ {
141
+ "timestamp": "2024-01-15T10:30:45.123Z",
142
+ "level": "info",
143
+ "message": "Creating new user",
144
+ "context": "UserService",
145
+ "metadata": {"userId": "123"}
146
+ }
147
+ ```
148
+
149
+ ### Pino (HTTP запросы)
150
+ ```json
151
+ {"level":30,"time":1642247445123,"pid":1234,"hostname":"app-server","req":{"id":"req-123","method":"GET","url":"/users","query":{},"params":{},"headers":{},"remoteAddress":"127.0.0.1"},"res":{"statusCode":200,"headers":{}},"responseTime":15,"msg":"request completed"}
152
+ ```
153
+
154
+ ## 🎯 API Reference
155
+
156
+ ### LoggerService
157
+
158
+ | Метод | Описание |
159
+ |-------|----------|
160
+ | `log(message, context?, metadata?)` | Информационное сообщение |
161
+ | `error(message, trace?, context?, metadata?)` | Ошибка с трейсом |
162
+ | `warn(message, context?, metadata?)` | Предупреждение |
163
+ | `debug(message, context?, metadata?)` | Отладочная информация |
164
+ | `verbose(message, context?, metadata?)` | Подробное логирование |
165
+ | `setContext(context)` | Установка контекста |
166
+
167
+ ### Декораторы
168
+
169
+ - `@LogContext(context)` - Установка контекста для класса/метода
170
+ - `@LogMetadata(metadata)` - Добавление метаданных
171
+
172
+ ### Конфигурация
173
+
174
+ | Опция | Тип | По умолчанию | Описание |
175
+ |-------|-----|--------------|----------|
176
+ | `level` | `LogLevel` | `'info'` | Уровень логирования |
177
+ | `timestamp` | `boolean` | `true` | Показывать время |
178
+ | `colors` | `boolean` | `true` | Цветной вывод |
179
+ | `format` | `LogFormat` | `'text'` | Формат вывода |
180
+ | `context` | `string` | `undefined` | Контекст по умолчанию |
181
+ | `sensitiveFields` | `string[]` | `[...]` | Поля для санитизации |
182
+
183
+ ## 🏗️ Архитектура
184
+
185
+ Пакет построен на принципах Clean Architecture:
186
+
187
+ - **Types** - строгая типизация
188
+ - **Contracts** - интерфейсы для расширяемости
189
+ - **Core** - основная бизнес-логика
190
+ - **Utils** - вспомогательные утилиты
191
+ - **Formatters** - форматирование логов
192
+ - **Writers** - вывод логов
193
+
194
+ ## 🔒 Безопасность
195
+
196
+ Автоматическая санитизация чувствительных полей:
197
+ - `password`, `pass`
198
+ - `token`, `accessToken`, `refreshToken`
199
+ - `secret`, `key`, `apiKey`
200
+ - `authorization`, `auth`
201
+ - `credential`, `credentials`
202
+
203
+ ## 🧪 Тестирование
204
+
205
+ ```typescript
206
+ import { LoggerService } from '@globalart/nestjs-logger';
207
+
208
+ describe('UserService', () => {
209
+ let service: UserService;
210
+ let logger: jest.Mocked<LoggerService>;
211
+
212
+ beforeEach(() => {
213
+ logger = {
214
+ log: jest.fn(),
215
+ error: jest.fn(),
216
+ // ... другие методы
217
+ } as any;
218
+
219
+ service = new UserService(logger);
220
+ });
221
+
222
+ it('should log user creation', () => {
223
+ service.createUser(userData);
224
+ expect(logger.log).toHaveBeenCalledWith(
225
+ 'Creating new user',
226
+ undefined,
227
+ { userId: userData.email }
228
+ );
229
+ });
230
+ });
231
+ ```
232
+
233
+ ## 🔄 Миграция с v1
234
+
235
+ ```typescript
236
+ // v1 (старый API)
237
+ import { LoggerModule, LoggerInterceptor } from '@globalart/nestjs-logger';
238
+
239
+ // v2 (новый API)
240
+ import { LoggerModule, HttpLoggerInterceptor } from '@globalart/nestjs-logger';
241
+
242
+ // Для совместимости доступны legacy экспорты:
243
+ import { LegacyLoggerModule, LoggerInterceptor } from '@globalart/nestjs-logger';
244
+ ```
245
+
246
+ ## 📈 Производительность
247
+
248
+ - Минимальные аллокации в горячих путях
249
+ - Ленивая инициализация форматтеров
250
+ - Оптимизированное определение контекста
251
+ - Эффективная санитизация данных
252
+
253
+ ## 🤝 Вклад в развитие
254
+
255
+ 1. Fork репозитория
256
+ 2. Создайте feature branch
257
+ 3. Внесите изменения
258
+ 4. Добавьте тесты
259
+ 5. Создайте Pull Request
260
+
261
+ ## 📄 Лицензия
262
+
263
+ MIT License
@@ -0,0 +1,22 @@
1
+ export declare const LOGGER_CONFIG_TOKEN = "LOGGER_CONFIG";
2
+ export declare const LOGGER_CONTEXT_METADATA = "LOGGER_CONTEXT";
3
+ export declare const LOGGER_METADATA_METADATA = "LOGGER_METADATA";
4
+ export declare const DEFAULT_SENSITIVE_FIELDS: readonly ["password", "pass", "token", "accessToken", "refreshToken", "secret", "key", "apiKey", "authorization", "auth", "credential", "credentials"];
5
+ export declare const COLORS: {
6
+ readonly reset: "\u001B[0m";
7
+ readonly red: "\u001B[31m";
8
+ readonly green: "\u001B[32m";
9
+ readonly yellow: "\u001B[33m";
10
+ readonly blue: "\u001B[34m";
11
+ readonly magenta: "\u001B[35m";
12
+ readonly cyan: "\u001B[36m";
13
+ readonly gray: "\u001B[90m";
14
+ readonly bright: "\u001B[1m";
15
+ };
16
+ export declare const DEFAULT_LOGGER_CONFIG: {
17
+ readonly level: "info";
18
+ readonly timestamp: true;
19
+ readonly colors: true;
20
+ readonly format: "text";
21
+ readonly sensitiveFields: readonly ["password", "pass", "token", "accessToken", "refreshToken", "secret", "key", "apiKey", "authorization", "auth", "credential", "credentials"];
22
+ };
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_LOGGER_CONFIG = exports.COLORS = exports.DEFAULT_SENSITIVE_FIELDS = exports.LOGGER_METADATA_METADATA = exports.LOGGER_CONTEXT_METADATA = exports.LOGGER_CONFIG_TOKEN = void 0;
4
+ exports.LOGGER_CONFIG_TOKEN = "LOGGER_CONFIG";
5
+ exports.LOGGER_CONTEXT_METADATA = "LOGGER_CONTEXT";
6
+ exports.LOGGER_METADATA_METADATA = "LOGGER_METADATA";
7
+ exports.DEFAULT_SENSITIVE_FIELDS = [
8
+ "password",
9
+ "pass",
10
+ "token",
11
+ "accessToken",
12
+ "refreshToken",
13
+ "secret",
14
+ "key",
15
+ "apiKey",
16
+ "authorization",
17
+ "auth",
18
+ "credential",
19
+ "credentials",
20
+ ];
21
+ exports.COLORS = {
22
+ reset: "\x1b[0m",
23
+ red: "\x1b[31m",
24
+ green: "\x1b[32m",
25
+ yellow: "\x1b[33m",
26
+ blue: "\x1b[34m",
27
+ magenta: "\x1b[35m",
28
+ cyan: "\x1b[36m",
29
+ gray: "\x1b[90m",
30
+ bright: "\x1b[1m",
31
+ };
32
+ exports.DEFAULT_LOGGER_CONFIG = {
33
+ level: "info",
34
+ timestamp: true,
35
+ colors: true,
36
+ format: "text",
37
+ sensitiveFields: exports.DEFAULT_SENSITIVE_FIELDS,
38
+ };
@@ -0,0 +1,26 @@
1
+ import { LogEntry, HttpRequestLogEntry } from "../types";
2
+ export interface ILogger {
3
+ log(message: string, context?: string, metadata?: Record<string, unknown>): void;
4
+ error(message: string, trace?: string, context?: string, metadata?: Record<string, unknown>): void;
5
+ warn(message: string, context?: string, metadata?: Record<string, unknown>): void;
6
+ debug(message: string, context?: string, metadata?: Record<string, unknown>): void;
7
+ verbose(message: string, context?: string, metadata?: Record<string, unknown>): void;
8
+ setContext(context: string): void;
9
+ logHttpRequest(entry: HttpRequestLogEntry): void;
10
+ }
11
+ export interface ILogFormatter {
12
+ format(entry: LogEntry): string;
13
+ formatHttpRequest(entry: HttpRequestLogEntry): string;
14
+ }
15
+ export interface ILogWriter {
16
+ write(formattedLog: string): void;
17
+ }
18
+ export interface IContextResolver {
19
+ resolve(): string;
20
+ }
21
+ export interface IDataSanitizer {
22
+ sanitize(data: unknown): unknown;
23
+ }
24
+ export interface IRequestIdGenerator {
25
+ generate(): string;
26
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,16 @@
1
+ import { NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
2
+ import { Observable } from "rxjs";
3
+ import { LoggerService } from "./logger.service";
4
+ import { IDataSanitizer, IRequestIdGenerator } from "../contracts";
5
+ export declare class HttpLoggerInterceptor implements NestInterceptor {
6
+ private readonly logger;
7
+ private readonly dataSanitizer;
8
+ private readonly requestIdGenerator;
9
+ private readonly hostname;
10
+ private readonly pid;
11
+ constructor(logger: LoggerService, dataSanitizer: IDataSanitizer, requestIdGenerator: IRequestIdGenerator);
12
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
13
+ private createLogEntry;
14
+ private getClientIp;
15
+ private sanitizeHeaders;
16
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.HttpLoggerInterceptor = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const operators_1 = require("rxjs/operators");
15
+ const logger_service_1 = require("./logger.service");
16
+ const os_1 = require("os");
17
+ let HttpLoggerInterceptor = class HttpLoggerInterceptor {
18
+ constructor(logger, dataSanitizer, requestIdGenerator) {
19
+ this.logger = logger;
20
+ this.dataSanitizer = dataSanitizer;
21
+ this.requestIdGenerator = requestIdGenerator;
22
+ this.hostname = (0, os_1.hostname)();
23
+ this.pid = process.pid;
24
+ }
25
+ intercept(context, next) {
26
+ const request = context.switchToHttp().getRequest();
27
+ const response = context.switchToHttp().getResponse();
28
+ const requestId = this.requestIdGenerator.generate();
29
+ const startTime = Date.now();
30
+ return next.handle().pipe((0, operators_1.tap)(() => {
31
+ const entry = this.createLogEntry(request, response, requestId, startTime, 30, // INFO level
32
+ "request completed");
33
+ this.logger.logHttpRequest(entry);
34
+ }), (0, operators_1.catchError)((error) => {
35
+ const entry = this.createLogEntry(request, response, requestId, startTime, 50, // ERROR level
36
+ "request failed");
37
+ this.logger.logHttpRequest(entry);
38
+ throw error;
39
+ }));
40
+ }
41
+ createLogEntry(request, response, requestId, startTime, level, message) {
42
+ const responseTime = Date.now() - startTime;
43
+ const ip = this.getClientIp(request);
44
+ const httpRequest = {
45
+ id: requestId,
46
+ method: request.method,
47
+ url: request.url,
48
+ query: request.query || {},
49
+ params: request.params || {},
50
+ headers: this.sanitizeHeaders(request.headers || {}),
51
+ remoteAddress: ip,
52
+ remotePort: request.connection?.remotePort,
53
+ body: this.dataSanitizer.sanitize(request.body),
54
+ };
55
+ const httpResponse = {
56
+ statusCode: response.statusCode || 500,
57
+ headers: this.sanitizeHeaders(response.getHeaders?.() || {}),
58
+ };
59
+ return {
60
+ level,
61
+ time: Date.now(),
62
+ pid: this.pid,
63
+ hostname: this.hostname,
64
+ req: httpRequest,
65
+ res: httpResponse,
66
+ responseTime,
67
+ msg: message,
68
+ };
69
+ }
70
+ getClientIp(request) {
71
+ return (request.headers["x-forwarded-for"] ||
72
+ request.headers["x-real-ip"] ||
73
+ request.connection?.remoteAddress ||
74
+ request.socket?.remoteAddress ||
75
+ "unknown");
76
+ }
77
+ sanitizeHeaders(headers) {
78
+ const sanitized = {};
79
+ for (const [key, value] of Object.entries(headers)) {
80
+ if (typeof value === "string") {
81
+ sanitized[key] = value;
82
+ }
83
+ else if (Array.isArray(value)) {
84
+ sanitized[key] = value.join(", ");
85
+ }
86
+ else {
87
+ sanitized[key] = String(value);
88
+ }
89
+ }
90
+ return this.dataSanitizer.sanitize(sanitized);
91
+ }
92
+ };
93
+ exports.HttpLoggerInterceptor = HttpLoggerInterceptor;
94
+ exports.HttpLoggerInterceptor = HttpLoggerInterceptor = __decorate([
95
+ (0, common_1.Injectable)(),
96
+ __metadata("design:paramtypes", [logger_service_1.LoggerService, Object, Object])
97
+ ], HttpLoggerInterceptor);
@@ -0,0 +1,20 @@
1
+ import { DynamicModule } from "@nestjs/common";
2
+ export interface LoggerModuleOptions {
3
+ level?: "error" | "warn" | "info" | "debug" | "verbose";
4
+ timestamp?: boolean;
5
+ colors?: boolean;
6
+ context?: string;
7
+ format?: "json" | "text" | "pino";
8
+ sensitiveFields?: string[];
9
+ }
10
+ export interface LoggerModuleAsyncOptions {
11
+ useFactory: (...args: any[]) => LoggerModuleOptions | Promise<LoggerModuleOptions>;
12
+ inject?: any[];
13
+ }
14
+ export declare class LoggerModule {
15
+ static forRoot(options?: LoggerModuleOptions): DynamicModule;
16
+ static forRootAsync(options: LoggerModuleAsyncOptions): DynamicModule;
17
+ private static createConfiguration;
18
+ private static createProviders;
19
+ private static createCoreProviders;
20
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var LoggerModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.LoggerModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const logger_service_1 = require("./logger.service");
13
+ const http_logger_interceptor_1 = require("./http-logger.interceptor");
14
+ const formatter_factory_1 = require("../factories/formatter.factory");
15
+ const console_writer_1 = require("../writers/console-writer");
16
+ const context_resolver_1 = require("../utils/context-resolver");
17
+ const data_sanitizer_1 = require("../utils/data-sanitizer");
18
+ const request_id_generator_1 = require("../utils/request-id-generator");
19
+ const constants_1 = require("../constants");
20
+ let LoggerModule = LoggerModule_1 = class LoggerModule {
21
+ static forRoot(options = {}) {
22
+ const config = this.createConfiguration(options);
23
+ const providers = this.createProviders(config);
24
+ return {
25
+ module: LoggerModule_1,
26
+ providers,
27
+ exports: [logger_service_1.LoggerService, http_logger_interceptor_1.HttpLoggerInterceptor],
28
+ global: true,
29
+ };
30
+ }
31
+ static forRootAsync(options) {
32
+ const configProvider = {
33
+ provide: constants_1.LOGGER_CONFIG_TOKEN,
34
+ useFactory: async (...args) => {
35
+ const userOptions = await options.useFactory(...args);
36
+ return this.createConfiguration(userOptions);
37
+ },
38
+ inject: options.inject || [],
39
+ };
40
+ const providers = [configProvider, ...this.createCoreProviders()];
41
+ return {
42
+ module: LoggerModule_1,
43
+ providers,
44
+ exports: [logger_service_1.LoggerService, http_logger_interceptor_1.HttpLoggerInterceptor],
45
+ global: true,
46
+ };
47
+ }
48
+ static createConfiguration(options) {
49
+ return {
50
+ ...constants_1.DEFAULT_LOGGER_CONFIG,
51
+ ...options,
52
+ sensitiveFields: options.sensitiveFields ?? constants_1.DEFAULT_LOGGER_CONFIG.sensitiveFields,
53
+ };
54
+ }
55
+ static createProviders(config) {
56
+ return [
57
+ {
58
+ provide: constants_1.LOGGER_CONFIG_TOKEN,
59
+ useValue: config,
60
+ },
61
+ ...this.createCoreProviders(),
62
+ ];
63
+ }
64
+ static createCoreProviders() {
65
+ return [
66
+ formatter_factory_1.FormatterFactory,
67
+ console_writer_1.ConsoleWriter,
68
+ context_resolver_1.ContextResolver,
69
+ request_id_generator_1.RequestIdGenerator,
70
+ {
71
+ provide: data_sanitizer_1.DataSanitizer,
72
+ useFactory: (config) => new data_sanitizer_1.DataSanitizer(config.sensitiveFields),
73
+ inject: [constants_1.LOGGER_CONFIG_TOKEN],
74
+ },
75
+ {
76
+ provide: logger_service_1.LoggerService,
77
+ useFactory: (config, formatterFactory, writer, contextResolver) => {
78
+ const formatter = formatterFactory.create(config.format, {
79
+ colors: config.colors,
80
+ timestamp: config.timestamp,
81
+ context: config.context,
82
+ });
83
+ return new logger_service_1.LoggerService(config, formatter, writer, contextResolver);
84
+ },
85
+ inject: [
86
+ constants_1.LOGGER_CONFIG_TOKEN,
87
+ formatter_factory_1.FormatterFactory,
88
+ console_writer_1.ConsoleWriter,
89
+ context_resolver_1.ContextResolver,
90
+ ],
91
+ },
92
+ {
93
+ provide: http_logger_interceptor_1.HttpLoggerInterceptor,
94
+ useFactory: (logger, dataSanitizer, requestIdGenerator) => new http_logger_interceptor_1.HttpLoggerInterceptor(logger, dataSanitizer, requestIdGenerator),
95
+ inject: [logger_service_1.LoggerService, data_sanitizer_1.DataSanitizer, request_id_generator_1.RequestIdGenerator],
96
+ },
97
+ ];
98
+ }
99
+ };
100
+ exports.LoggerModule = LoggerModule;
101
+ exports.LoggerModule = LoggerModule = LoggerModule_1 = __decorate([
102
+ (0, common_1.Module)({})
103
+ ], LoggerModule);
@@ -0,0 +1,19 @@
1
+ import { LoggerService as NestLoggerService } from "@nestjs/common";
2
+ import { ILogger, ILogFormatter, ILogWriter, IContextResolver } from "../contracts";
3
+ import { HttpRequestLogEntry, LoggerConfiguration } from "../types";
4
+ export declare class LoggerService implements NestLoggerService, ILogger {
5
+ private readonly config;
6
+ private readonly formatter;
7
+ private readonly writer;
8
+ private readonly contextResolver;
9
+ private context?;
10
+ constructor(config: LoggerConfiguration, formatter: ILogFormatter, writer: ILogWriter, contextResolver: IContextResolver);
11
+ setContext(context: string): void;
12
+ log(message: string, context?: string, metadata?: Record<string, unknown>): void;
13
+ error(message: string, trace?: string, context?: string, metadata?: Record<string, unknown>): void;
14
+ warn(message: string, context?: string, metadata?: Record<string, unknown>): void;
15
+ debug(message: string, context?: string, metadata?: Record<string, unknown>): void;
16
+ verbose(message: string, context?: string, metadata?: Record<string, unknown>): void;
17
+ logHttpRequest(entry: HttpRequestLogEntry): void;
18
+ private writeLog;
19
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.LoggerService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ let LoggerService = class LoggerService {
15
+ constructor(config, formatter, writer, contextResolver) {
16
+ this.config = config;
17
+ this.formatter = formatter;
18
+ this.writer = writer;
19
+ this.contextResolver = contextResolver;
20
+ }
21
+ setContext(context) {
22
+ this.context = context;
23
+ }
24
+ log(message, context, metadata) {
25
+ this.writeLog("info", message, context, metadata);
26
+ }
27
+ error(message, trace, context, metadata) {
28
+ this.writeLog("error", message, context, metadata, trace);
29
+ }
30
+ warn(message, context, metadata) {
31
+ this.writeLog("warn", message, context, metadata);
32
+ }
33
+ debug(message, context, metadata) {
34
+ this.writeLog("debug", message, context, metadata);
35
+ }
36
+ verbose(message, context, metadata) {
37
+ this.writeLog("verbose", message, context, metadata);
38
+ }
39
+ logHttpRequest(entry) {
40
+ const formatted = this.formatter.formatHttpRequest(entry);
41
+ this.writer.write(formatted);
42
+ }
43
+ writeLog(level, message, context, metadata, trace) {
44
+ const entry = {
45
+ level,
46
+ message,
47
+ timestamp: new Date(),
48
+ context: context ?? this.context ?? this.contextResolver.resolve(),
49
+ metadata,
50
+ trace,
51
+ };
52
+ const formatted = this.formatter.format(entry);
53
+ this.writer.write(formatted);
54
+ }
55
+ };
56
+ exports.LoggerService = LoggerService;
57
+ exports.LoggerService = LoggerService = __decorate([
58
+ (0, common_1.Injectable)(),
59
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
60
+ ], LoggerService);