@laqus/logsjs
v1.0.16
Published
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;
Readme
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/logsjsVariá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 | CriticalPara da variável
$LAQUS_APP_NAMEcaso não seja passado valores para ela, o valor atribuito seráNone.A variável
$LAQUS_LOG_LEVELaceita 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:
req.userId/req.tenantId(populado pelo guard)req.user.id/req.user.tenantId(populado pelo guard)- 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 | ID do objeto afetado |
| 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 |
