diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e99231e3..cf36301f 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -24,10 +24,12 @@ "@supabase/supabase-js": "^1.35.6", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", + "nestjs-pino": "^3.1.1", "nestjs-supabase-auth": "^1.0.9", "passport": "^0.6.0", "passport-jwt": "^4.0.0", "pg": "^8.8.0", + "pino-http": "^8.2.1", "rxjs": "^7.5.6", "semver": "^7.3.7", "typeorm": "^0.3.9", @@ -62,6 +64,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.0.1", "jest": "29.0.2", + "pino-pretty": "^9.1.1", "rimraf": "^3.0.2", "supertest": "^6.2.4", "ts-node": "^10.9.1", @@ -6438,6 +6441,12 @@ "color-support": "bin.js" } }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -7230,6 +7239,15 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -8631,6 +8649,12 @@ "node": ">=10.13.0" } }, + "node_modules/fast-copy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.0.tgz", + "integrity": "sha512-4HzS+9pQ5Yxtv13Lhs1Z1unMXamBdn5nA4bEi1abYpDNSpSp7ODYQ1KPMF6nTatfEzgH6/zPvXKU1zvHiUjWlA==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8709,6 +8733,19 @@ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==" }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, "node_modules/fastify": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.4.0.tgz", @@ -9444,6 +9481,56 @@ "node": ">=14.0.0" } }, + "node_modules/help-me": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-4.1.0.tgz", + "integrity": "sha512-5HMrkOks2j8Fpu2j5nTLhrBhT7VwHwELpqnSnx802ckofys5MO2SkLpgSz3dgNFHV7IYFX2igm5CM75SmuYidw==", + "dev": true, + "dependencies": { + "glob": "^8.0.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/help-me/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/help-me/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/help-me/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -10836,6 +10923,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11478,6 +11574,19 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/nestjs-pino": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/nestjs-pino/-/nestjs-pino-3.1.1.tgz", + "integrity": "sha512-T7ajfqYTSHKrirzrElQJ3EWO/OZF5fFFkgaRvD+I7F5YY2hU3X295E/CnTkgpHZozL0s/3Ud4OtTZlT3NisTBw==", + "hasInstallScript": true, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0", + "pino-http": "^6.4.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/nestjs-supabase-auth": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/nestjs-supabase-auth/-/nestjs-supabase-auth-1.0.9.tgz", @@ -12269,6 +12378,94 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/pino-http": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/pino-http/-/pino-http-8.2.1.tgz", + "integrity": "sha512-bdWAE4HYfFjDhKw2/N7BLNSIFAs+WDLZnetsGRpBdNEKq7/RoZUgblLS5OlMY257RPQml6J5QiiLkwxbstzWbA==", + "dependencies": { + "fast-url-parser": "^1.1.3", + "get-caller-file": "^2.0.5", + "pino": "^8.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-9.1.1.tgz", + "integrity": "sha512-iJrnjgR4FWQIXZkUF48oNgoRI9BpyMhaEmihonHeCnZ6F50ZHAS4YGfGBT/ZVNsPmd+hzkIPGzjKdY08+/yAXw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^4.0.1", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", + "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pino-std-serializers": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", @@ -12380,6 +12577,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 365d72b5..c239422e 100644 --- a/package.json +++ b/package.json @@ -63,10 +63,12 @@ "@supabase/supabase-js": "^1.35.6", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", + "nestjs-pino": "^3.1.1", "nestjs-supabase-auth": "^1.0.9", "passport": "^0.6.0", "passport-jwt": "^4.0.0", "pg": "^8.8.0", + "pino-http": "^8.2.1", "rxjs": "^7.5.6", "semver": "^7.3.7", "typeorm": "^0.3.9", @@ -101,6 +103,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.0.1", "jest": "29.0.2", + "pino-pretty": "^9.1.1", "rimraf": "^3.0.2", "supertest": "^6.2.4", "ts-node": "^10.9.1", diff --git a/src/app.module.ts b/src/app.module.ts index dc41babc..993e6470 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,9 +1,10 @@ -import { Module } from "@nestjs/common"; +import {Module, RequestMethod} from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { ConfigModule, ConfigService } from "@nestjs/config"; import { HttpModule } from "@nestjs/axios"; import { TerminusModule } from "@nestjs/terminus"; import { TypeOrmModuleOptions } from "@nestjs/typeorm/dist/interfaces/typeorm-options.interface"; +import { LoggerModule } from "nestjs-pino"; import { DataSource } from "typeorm"; import { RepoModule } from "./repo/repo.module"; @@ -59,6 +60,26 @@ import { UserModule } from "./user/user.module"; }) as TypeOrmModuleOptions, inject: [ConfigService], }), + LoggerModule.forRoot({ + pinoHttp: { + // name: "api.os", + level: process.env.NODE_ENV !== "production" ? "debug" : "info", + transport: process.env.NODE_ENV !== "production" + ? { + target: "pino-pretty", + options: { + colorize: true, + levelFirst: true, + translateTime: "UTC:hh:MM:ss.l", + // singleLine: true, + messageFormat: "\x1B[33m[{context}] \x1B[32m{msg}", + ignore: "pid,hostname,context", + }, + } + : undefined, + }, + exclude: [{ method: RequestMethod.ALL, path: "check" }], + }), TerminusModule, HttpModule, AuthModule, diff --git a/src/main.ts b/src/main.ts index 9fa8c878..ce2cbace 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import { SwaggerModule, DocumentBuilder, SwaggerCustomOptions } from "@nestjs/sw import { ValidationPipe, VersioningType } from "@nestjs/common"; import fastifyHelmet from "@fastify/helmet"; import { ConfigService } from "@nestjs/config"; +import { Logger, LoggerErrorInterceptor } from "nestjs-pino"; import fastifyRateLimit from "@fastify/rate-limit"; import path from "node:path"; import { writeFile } from "node:fs/promises"; @@ -19,10 +20,10 @@ async function bootstrap () { const app = await NestFactory.create( AppModule, new FastifyAdapter({ logger: false }), + { bufferLogs: true }, ); const configService = app.get(ConfigService); const apiDomain = String(configService.get("api.domain")); - const markdownDescription = ` ## Swagger-UI API Documentation @@ -66,6 +67,8 @@ code | condition ## Additional links`; + app.useLogger(app.get(Logger)); + app.useGlobalInterceptors((new LoggerErrorInterceptor)); app.enableCors(); app.enableVersioning({ type: VersioningType.URI,