npm.io
1.1.0 • Published 1 week ago

@laqus/logsjs

Licence
ISC
Version
1.1.0
Deps
3
Size
129 kB
Vulns
0
Weekly
0

Laqus.LogsJS

Essa biblioteca tem o Objetivo de simplificar o processo de "Logs", com LogLevels, Timestamps e Obscurecencia de Atributos, assim alinhados com os Logs do CloudWatch, juntamente com seus respectivos filtros;

Como instalar

    john@doe:~$ npm install @laqus/logsjs

Variáveis de Ambiente

Para a utilização dessa biblioteca é necessário duas Variáveis de Ambiente

    LAQUS_APP_NAME = $LAQUS_APP_NAME | None
    LAQUS_LOG_LEVEL = Information | Debug | Warning | Error | Critical
  • Para da variável $LAQUS_APP_NAME caso não seja passado valores para ela, o valor atribuito será None.

  • A variável $LAQUS_LOG_LEVEL aceita o Enum acima, para que a aplicação saiba, qual tipo de LogLevel ela estará mostrando no stdout, caso seja passado um tipo Diferente, não será mostrado nada no stdout;

    /* Example */
    require('dotenv/config')

    /* 
        # Example .env
        LAQUS_APP_NAME = Laqus_Emissoes
        LAQUS_LOG_LEVEL = Information
    */

    const { LaqusLogger } = require('@laqus/logsjs');
    const Logger = new LaqusLogger('Application/Test');

    Logger.info({ message: "text test" }); // Will show off
    Logger.warn({ message: "text test" }); // Will NOT show off

    /* OUTPUT
        > node index.js

        {
            "appName": "Laqus_Emissoes",
            "dateTime": "01-09-2023 13:04:42",
            "LogLevel": "Information",
            "text": "text test",
            "category": "Application/Test"
        }
    */

Exemplo de utilização

    require('dotenv/config')
    const { LaqusLogger } = require('@laqus/logsjs')
    const logger = new LaqusLogger('Application/Test')

    logger.info({
            message: 'blah blah blah',
            correlationId: '14ee059c-6e06-460f-b29b-c74f14789bbf',
            obscuredFields: null,
            data: {
                app: 'onboarding-api',
                context: 'cadastro',
                error: null,
                props: null,
                sourceClass: 'OnboardingController',
                sourceMethod: 'getAll'
            }
    });

    /* OUTPUT:  
        {
            "dateTime": "01-09-2023 11:28:10",
            "LogLevel": "INFO",
            "text": [
                {
                "teste": {
                    "a": [
                        {
                            "abc": "abc"
                        }
                    ]
                },
                "bool": "******",
                "abc": "abc"
                }
            ]
        }
    */

OBS: O atributo dateTime está formatado com o formato PT-BR, e com o timezone America/Recife.


Audit Logs (NestJS)

Módulo para envio de logs de auditoria para o serviço central laqus-audit-logs. Funciona com interceptor do NestJS, capturando request/response automaticamente.

Como importar

    import { AuditLogModule, AuditLog } from '@laqus/logsjs/audit';

Configuração no módulo principal

    // app.module.ts
    import { Module } from '@nestjs/common';
    import { APP_INTERCEPTOR } from '@nestjs/core';
    import { AuditLogModule, AuditLogInterceptor } from '@laqus/logsjs/audit';

    @Module({
        imports: [
            AuditLogModule.forRoot({
                sourceMicroservice: 'meu-servico-lindo-maraviloso',
                serviceUrl: 'http://audit-api.laqus.io/api/v1',
                globalMaskedFields: ['password', 'token', 'secret'],
                debug: false
            })
        ],
        providers: [
            {
                provide: APP_INTERCEPTOR,
                useClass: AuditLogInterceptor
            }
        ]
    })
    export class AppModule {}

Configuração com Async (usando ConfigService)

    // app.module.ts
    import { Module } from '@nestjs/common';
    import { ConfigModule, ConfigService } from '@nestjs/config';
    import { APP_INTERCEPTOR } from '@nestjs/core';
    import { AuditLogModule, AuditLogInterceptor } from '@laqus/logsjs/audit';

    @Module({
        imports: [
            ConfigModule.forRoot(),
            AuditLogModule.forRootAsync({
                imports: [ConfigModule],
                useFactory: (config: ConfigService) => ({
                    sourceMicroservice: config.get('SERVICE_NAME'),
                    serviceUrl: config.get('AUDIT_SERVICE_URL'),
                    globalMaskedFields: ['password', 'token']
                }),
                inject: [ConfigService]
            })
        ],
        providers: [
            {
                provide: APP_INTERCEPTOR,
                useClass: AuditLogInterceptor
            }
        ]
    })
    export class AppModule {}

Múltiplos interceptors globais

Se a app já usa outro APP_INTERCEPTOR, não tem problema. O NestJS aceita múltiplos:

    @Module({
        imports: [
            AuditLogModule.forRoot({ ... })
        ],
        providers: [
            {
                provide: APP_INTERCEPTOR,
                useClass: LoggingInterceptor  // interceptor existente
            },
            {
                provide: APP_INTERCEPTOR,
                useClass: AuditLogInterceptor
            }
        ]
    })
    export class AppModule {}

Usando só em controllers específicos

Se não quiser usar global, dá pra aplicar só onde precisar:

    import { Controller, UseInterceptors } from '@nestjs/common';
    import { AuditLogInterceptor } from '@laqus/logsjs/audit';

    @Controller('users')
    @UseInterceptors(AuditLogInterceptor)
    export class UsersController { ... }

Usando o decorator @AuditLog

O decorator marca quais endpoints devem gerar audit log. Endpoints sem o decorator não geram log.

    // users.controller.ts
    import { Controller, Post, Get, Body, Param } from '@nestjs/common';
    import { AuditLog } from '@laqus/logsjs/audit';

    @Controller('users')
    export class UsersController {

        @Post()
        @AuditLog({
            context: 'UserManagement',
            domain: 'Users',
            action: 'CREATE',
            maskRequestFields: ['password', 'cpf']
        })
        private create(@Body() dto: CreateUserDto): any {
            return this.usersService.create(dto);
        }

        @Get(':id')  // sem @AuditLog = não gera log
        private findOne(@Param('id') id: string): any {
            return this.usersService.findOne(id);
        }
    }

Target Object dinâmico

Para capturar o ID do objeto afetado dinamicamente:

    @Delete(':id')
    @AuditLog({
        context: 'Gestao de usuários',
        domain: 'Users',
        action: 'DELETE',
        targetObject: (ctx) => `User:${ctx.params.id}`
    })
    remove(@Param('id') id: string) {
        return this.usersService.remove(id);
    }

Extração de userId e tenantId

Por padrão, o interceptor tenta extrair userId e tenantId na seguinte ordem:

  1. req.userId / req.tenantId (populado pelo guard)
  2. req.user.id / req.user.tenantId (populado pelo guard)
  3. Headers x-user-id / x-tenant-id (fallback)

Se o guard da app popula o req.user, não precisa configurar nada.

Para casos especiais, use extractors customizados:

    AuditLogModule.forRoot({
        sourceMicroservice: 'meu-servico-maroto',
        serviceUrl: 'http://audit-api.laqus.io/api/v1',
        userIdExtractor: (req: any) => req.user?.id,
        tenantIdExtractor: (req: any) => req.user?.tenantId
    })

Usando com Mensageria (SQS/RabbitMQ)

Para enviar logs via mensageria (mais performático), passe um adapter:

    AuditLogModule.forRoot({
        sourceMicroservice: 'meu-servico',
        serviceUrl: 'http://audit-api.laqus.io/api/v1',
        messagingAdapter: laqusMensageriaAdapterExemplo,  // implementando IAuditLogMessagingAdapter
        exchange: 'platform-audit-logs-ex',
        queue: 'platform-audit-logs'
    })

O adapter precisa implementar:

    interface IAuditLogMessagingAdapter {
        isReady(): boolean;
        publish(exchange: string, queue: string, message: string): Promise<void>;
    }

Se a mensagem for muito grande pro SQS (>200KB), o módulo faz fallback automático pra HTTP.

Enviando audit logs manualmente

Para logs fora de controllers (jobs, consumers, etc):

    import { Injectable } from '@nestjs/common';
    import { AuditLogClientService } from '@laqus/logsjs/audit';

    @Injectable()
    export class UmServicoQueDeveSerAuditavelService {
        constructor(private readonly auditClient: AuditLogClientService) {}

        private async doTheJob() {
            // fazer o que tem que ser feito

            await this.auditClient.log({
                userId: 'uuid-do-usuario',
                tenantId: 'uuid-do-tenant',
                context: 'BackgroundJobs',
                domain: 'Gestao de usuariso',
                action: 'Listar',
                targetObject: 'usurio:123',
                statusCode: 200,
                requestUrl: '/users',
                requestMethod: 'INTERNAL'
            });
        }
    }

Opções do decorator @AuditLog

Opção Tipo Descrição
context string Contexto de negócio (ex: 'UserManagement')
domain string Domínio (ex: 'Users', 'Orders')
action string Ação (ex: 'CREATE', 'UPDATE', 'DELETE')
targetObject string function
maskRequestFields string[] Campos do request body pra mascarar
maskResponseFields string[] Campos do response body pra mascarar
skipRequestBody boolean Não logar request body
skipResponseBody boolean Não logar response body
disabled boolean Desabilita audit log pro endpoint

Opções do módulo

Opção Tipo Default Descrição
sourceMicroservice string - Nome do microsserviço (obrigatório)
serviceUrl string - URL do serviço de audit (obrigatório)
messagingAdapter IAuditLogMessagingAdapter - Adapter pra mensageria
exchange string - Exchange da mensageria
queue string - Queue da mensageria
globalMaskedFields string[] [] Campos mascarados em todos os logs
maxResponseBodyBytes number 50KB Tamanho máximo do response body
httpTimeoutMs number 5000 Timeout das requests HTTP
debug boolean false Logs de debug