diff --git a/package.json b/package.json index c33bfba..f907afb 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "class-validator": "^0.15.1", "nestjs-pino": "^5.3.1", "pino": "^10.4.0", + "pino-pretty": "^13.2.0", "pino-roll": "^4.0.0", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1b9d16..0d63e3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,6 +199,9 @@ importers: pino: specifier: ^10.4.0 version: 10.4.0 + pino-pretty: + specifier: ^13.2.0 + version: 13.2.0 pino-roll: specifier: ^4.0.0 version: 4.0.0 @@ -1367,6 +1370,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1429,6 +1435,9 @@ packages: date-fns@4.4.0: resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1502,6 +1511,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -1567,6 +1579,9 @@ packages: resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} engines: {node: '>=8.0.0'} + fast-copy@4.1.2: + resolution: {integrity: sha512-DUHggaYcouhy5I1LacDJ+JDSqGlumVJP2EAi5Nwt1pWPeLpSvIjkrY+x4fsoI1/+GlTyq+DM9zdgWCFSfqNODA==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1673,6 +1688,9 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -1745,6 +1763,10 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -2093,6 +2115,10 @@ packages: pino-http@11.0.0: resolution: {integrity: sha512-wqg5XIAGRRIWtTk8qPGxkbrfiwEWz1lgedVLvhLALudKXvg1/L2lTFgTGPJ4Z2e3qcRmxoFxDuSdMdMGNM6I1g==} + pino-pretty@13.2.0: + resolution: {integrity: sha512-jjghD1ML+Di/WxjJDz6j6Y4FT7hIXOlb8h27AyJ+ohtAXJXH4PS/xkv7si+RCCIW59HMgZsMKTDgzdr0RhuRrg==} + hasBin: true + pino-roll@4.0.0: resolution: {integrity: sha512-axI1aQaIxXdw1F4OFFli1EDxIrdYNGLowkw/ZoZogX8oCSLHUghzwVVXUS8U+xD/Savwa5IXpiXmsSGKFX/7Sg==} @@ -2136,6 +2162,9 @@ packages: resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} engines: {node: '>= 0.10'} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} @@ -2213,6 +2242,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -2262,6 +2294,9 @@ packages: sonic-boom@4.2.1: resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + sonic-boom@5.0.2: + resolution: {integrity: sha512-/JEruzo6yhNVhsLblTRchgTQHIt7SsdJP0YyrfWaNKjIOQDfrdZv9gwYraYCAsmKV39/LAdV31FLL5NCDpoL/A==} + source-map-js@1.2.2: resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} @@ -2322,6 +2357,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + strtok3@10.3.5: resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} @@ -3452,6 +3491,8 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -3494,6 +3535,8 @@ snapshots: date-fns@4.4.0: {} + dateformat@4.6.3: {} + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 @@ -3550,6 +3593,10 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -3658,6 +3705,8 @@ snapshots: dependencies: pure-rand: 6.1.0 + fast-copy@4.1.2: {} + fast-deep-equal@3.1.3: {} fast-safe-stringify@2.1.1: {} @@ -3772,6 +3821,8 @@ snapshots: dependencies: function-bind: 1.1.2 + help-me@5.0.0: {} + html-escaper@2.0.2: {} http-errors@2.0.1: @@ -3843,6 +3894,8 @@ snapshots: jiti@2.7.0: {} + joycon@3.1.1: {} + js-tokens@10.0.0: {} js-yaml@5.4.2: @@ -4164,6 +4217,22 @@ snapshots: pino-std-serializers: 7.1.0 process-warning: 5.1.0 + pino-pretty@13.2.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 4.1.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pump: 3.0.4 + secure-json-parse: 4.1.0 + sonic-boom: 5.0.2 + strip-json-comments: 5.0.3 + pino-roll@4.0.0: dependencies: date-fns: 4.4.0 @@ -4217,6 +4286,11 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + pure-rand@6.1.0: {} qs@6.16.0: @@ -4309,6 +4383,8 @@ snapshots: safer-buffer@2.1.2: {} + secure-json-parse@4.1.0: {} + semver@7.8.5: {} send@1.2.1(supports-color@7.2.0): @@ -4380,6 +4456,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 + sonic-boom@5.0.2: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.2: {} source-map-support@0.5.21: @@ -4428,6 +4508,8 @@ snapshots: strip-bom@3.0.0: {} + strip-json-comments@5.0.3: {} + strtok3@10.3.5: dependencies: '@tokenizer/token': 0.3.0 diff --git a/src/logging/logger.config.ts b/src/logging/logger.config.ts index 36b50ac..92c2410 100644 --- a/src/logging/logger.config.ts +++ b/src/logging/logger.config.ts @@ -3,26 +3,24 @@ import { LoggerModule } from 'nestjs-pino'; /** * 日志配置:pino 结构化日志。 - * - stdout 默认开启 - * - 文件输出默认关闭,由环境变量 LOG_FILE_ENABLED=true 开启 + * - stdout 默认开启:开发环境用 pino-pretty 可读格式(LOG_PRETTY 默认 true),生产设 false 输出 JSON + * - 文件输出默认关闭,LOG_FILE_ENABLED=true 开启(文件始终为 JSON,便于采集) * - 级别 LOG_LEVEL(默认 info)、路径 LOG_FILE_PATH(默认 logs/app.log) */ export function createLoggerModule(): DynamicModule { const level = process.env.LOG_LEVEL ?? 'info'; + const pretty = process.env.LOG_PRETTY !== 'false'; const fileEnabled = process.env.LOG_FILE_ENABLED === 'true'; const filePath = process.env.LOG_FILE_PATH ?? 'logs/app.log'; - const pinoHttp = fileEnabled - ? { - level, - transport: { - targets: [ - { target: 'pino/file', options: { destination: 1 } }, // stdout - { target: 'pino-roll', options: { file: filePath, size: '10m', limit: { count: 10 } } }, // 文件按大小轮转 - ], - }, - } - : { level }; + const stdoutTarget = pretty + ? { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l' } } + : { target: 'pino/file', options: { destination: 1 } }; - return LoggerModule.forRoot({ pinoHttp }); + const targets: any[] = [stdoutTarget]; + if (fileEnabled) { + targets.push({ target: 'pino-roll', options: { file: filePath, size: '10m', limit: { count: 10 } } }); + } + + return LoggerModule.forRoot({ pinoHttp: { level, transport: { targets } } }); }