mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
feat: switch to pino for logs (#1855)
- switch to json logs in production - add option to support http logging
This commit is contained in:
@@ -79,6 +79,7 @@
|
||||
"mime-types": "^2.1.35",
|
||||
"nanoid": "3.3.11",
|
||||
"nestjs-kysely": "^1.2.0",
|
||||
"nestjs-pino": "^4.5.0",
|
||||
"nodemailer": "^7.0.12",
|
||||
"openid-client": "^5.7.1",
|
||||
"otpauth": "^9.4.1",
|
||||
@@ -89,6 +90,8 @@
|
||||
"pg": "^8.16.3",
|
||||
"pg-tsquery": "^8.4.2",
|
||||
"pgvector": "^0.2.1",
|
||||
"pino-http": "^11.0.0",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"postmark": "^4.0.5",
|
||||
"react": "^18.3.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
|
||||
@@ -18,6 +18,7 @@ import { SecurityModule } from './integrations/security/security.module';
|
||||
import { TelemetryModule } from './integrations/telemetry/telemetry.module';
|
||||
import { RedisModule } from '@nestjs-labs/nestjs-ioredis';
|
||||
import { RedisConfigService } from './integrations/redis/redis-config.service';
|
||||
import { LoggerModule } from './common/logger/logger.module';
|
||||
|
||||
const enterpriseModules = [];
|
||||
try {
|
||||
@@ -35,6 +36,7 @@ try {
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
LoggerModule,
|
||||
CoreModule,
|
||||
DatabaseModule,
|
||||
EnvironmentModule,
|
||||
|
||||
@@ -8,9 +8,11 @@ import { QueueModule } from '../../integrations/queue/queue.module';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { HealthModule } from '../../integrations/health/health.module';
|
||||
import { CollaborationController } from './collaboration.controller';
|
||||
import { LoggerModule } from '../../common/logger/logger.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
LoggerModule,
|
||||
DatabaseModule,
|
||||
EnvironmentModule,
|
||||
CollaborationModule,
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { TransformHttpResponseInterceptor } from '../../common/interceptors/http-response.interceptor';
|
||||
import { InternalLogFilter } from '../../common/logger/internal-log-filter';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Logger as PinoLogger } from 'nestjs-pino';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
@@ -17,10 +17,12 @@ async function bootstrap() {
|
||||
maxParamLength: 500,
|
||||
}),
|
||||
{
|
||||
logger: new InternalLogFilter(),
|
||||
bufferLogs: true,
|
||||
},
|
||||
);
|
||||
|
||||
app.useLogger(app.get(PinoLogger));
|
||||
|
||||
app.setGlobalPrefix('api', { exclude: ['/'] });
|
||||
|
||||
app.enableCors();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';
|
||||
import { createPinoConfig } from './pino.config';
|
||||
|
||||
@Module({
|
||||
imports: [PinoLoggerModule.forRoot(createPinoConfig())],
|
||||
exports: [PinoLoggerModule],
|
||||
})
|
||||
export class LoggerModule {}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Params } from 'nestjs-pino';
|
||||
import { stdTimeFunctions } from 'pino';
|
||||
|
||||
const CONTEXTS_TO_IGNORE = [
|
||||
'InstanceLoader',
|
||||
'RoutesResolver',
|
||||
'RouterExplorer',
|
||||
'WebSocketsController',
|
||||
];
|
||||
|
||||
export function createPinoConfig(): Params {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const isDebugMode = process.env.DEBUG_MODE === 'true';
|
||||
const logHttp = process.env.LOG_HTTP === 'true';
|
||||
|
||||
const level = isProduction && !isDebugMode ? 'info' : 'debug';
|
||||
|
||||
return {
|
||||
pinoHttp: {
|
||||
level,
|
||||
timestamp: stdTimeFunctions.isoTime,
|
||||
transport: !isProduction
|
||||
? {
|
||||
target: 'pino-pretty',
|
||||
options: {
|
||||
colorize: true,
|
||||
singleLine: true,
|
||||
translateTime: 'SYS:standard',
|
||||
ignore: 'pid,hostname',
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
formatters: {
|
||||
level: (label) => ({ level: label }),
|
||||
log: (object: Record<string, unknown>) => {
|
||||
if (isProduction && !isDebugMode) {
|
||||
const context = object['context'] as string | undefined;
|
||||
if (context && CONTEXTS_TO_IGNORE.includes(context)) {
|
||||
return { filtered: true };
|
||||
}
|
||||
}
|
||||
return object;
|
||||
},
|
||||
},
|
||||
serializers: {
|
||||
req: (req) => {
|
||||
const forwardedFor = req.headers?.['x-forwarded-for'];
|
||||
const ip =
|
||||
req.headers?.['cf-connecting-ip'] ||
|
||||
(typeof forwardedFor === 'string' ? forwardedFor.split(',')[0]?.trim() : undefined) ||
|
||||
req.remoteAddress;
|
||||
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
ip,
|
||||
userAgent: req.headers?.['user-agent'],
|
||||
};
|
||||
},
|
||||
res: (res) => ({
|
||||
statusCode: res.statusCode,
|
||||
}),
|
||||
},
|
||||
customLogLevel: (_req, res, err) => {
|
||||
if (res.statusCode >= 500 || err) return 'error';
|
||||
if (res.statusCode >= 400) return 'warn';
|
||||
return 'info';
|
||||
},
|
||||
autoLogging: logHttp
|
||||
? {
|
||||
ignore: (req) =>
|
||||
req.url === '/api/health' || req.url === '/api/health/live',
|
||||
}
|
||||
: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Logger, NotFoundException, ValidationPipe } from '@nestjs/common';
|
||||
import { Logger as PinoLogger } from 'nestjs-pino';
|
||||
import { TransformHttpResponseInterceptor } from './common/interceptors/http-response.interceptor';
|
||||
import { WsRedisIoAdapter } from './ws/adapter/ws-redis.adapter';
|
||||
import { InternalLogFilter } from './common/logger/internal-log-filter';
|
||||
import fastifyMultipart from '@fastify/multipart';
|
||||
import fastifyCookie from '@fastify/cookie';
|
||||
|
||||
@@ -24,10 +24,12 @@ async function bootstrap() {
|
||||
}),
|
||||
{
|
||||
rawBody: true,
|
||||
logger: new InternalLogFilter(),
|
||||
bufferLogs: true,
|
||||
},
|
||||
);
|
||||
|
||||
app.useLogger(app.get(PinoLogger));
|
||||
|
||||
app.setGlobalPrefix('api', {
|
||||
exclude: ['robots.txt', 'share/:shareId/p/:pageSlug'],
|
||||
});
|
||||
@@ -99,9 +101,7 @@ async function bootstrap() {
|
||||
|
||||
const port = process.env.PORT || 3000;
|
||||
await app.listen(port, '0.0.0.0', () => {
|
||||
logger.log(
|
||||
`Listening on http://127.0.0.1:${port} / ${process.env.APP_URL}`,
|
||||
);
|
||||
logger.log(`Listening on http://127.0.0.1:${port} / ${process.env.APP_URL}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user