From 2a96d3762cf7440dc6cb232b32bbf99fcea6d206 Mon Sep 17 00:00:00 2001 From: Levente Orban Date: Mon, 27 Oct 2025 09:33:00 +0100 Subject: [PATCH] feat: add pino logger for serverside --- package-lock.json | 294 +++++++++++++++++++++ package.json | 7 + src/hooks.server.ts | 8 +- src/lib/database/healthCheck.ts | 26 +- src/lib/logger.ts | 29 ++ src/routes/create/+page.server.ts | 6 +- src/routes/discover/+page.server.ts | 3 +- src/routes/event/+page.server.ts | 5 +- src/routes/event/[id]/+page.server.ts | 7 +- src/routes/event/[id]/edit/+page.server.ts | 3 +- tsconfig.json | 3 +- 11 files changed, 367 insertions(+), 24 deletions(-) create mode 100644 src/lib/logger.ts diff --git a/package-lock.json b/package-lock.json index 8c70d36..a97771d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "@sveltejs/adapter-node": "^5.3.1", "drizzle-orm": "^0.44.5", "fuse.js": "^7.1.0", + "pino": "^10.1.0", + "pino-pretty": "^13.1.2", "postgres": "^3.4.7" }, "devDependencies": { @@ -22,7 +24,12 @@ "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", +<<<<<<< HEAD "drizzle-kit": "^0.31.5", +======= + "@types/node": "^24.9.1", + "drizzle-kit": "^0.31.4", +>>>>>>> 222c2ee (feat: add pino logger for serverside) "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", @@ -1231,6 +1238,12 @@ "node": ">= 8" } }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -2095,6 +2108,20 @@ "dev": true, "license": "MIT" }, +<<<<<<< HEAD +======= + "node_modules/@types/node": { + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, +>>>>>>> 222c2ee (feat: add pino logger for serverside) "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -2432,6 +2459,15 @@ "node": ">= 0.4" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2561,6 +2597,12 @@ "dev": true, "license": "MIT" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2611,6 +2653,15 @@ "node": ">=4" } }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -2801,6 +2852,15 @@ } } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", @@ -3110,6 +3170,12 @@ "node": ">=0.10.0" } }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3161,6 +3227,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -3359,6 +3431,12 @@ "node": ">= 0.4" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3476,6 +3554,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3901,6 +3988,15 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -3989,6 +4085,24 @@ "dev": true, "license": "MIT" }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4096,6 +4210,79 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz", + "integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.2.tgz", + "integrity": "sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -4373,6 +4560,32 @@ } } }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4404,6 +4617,12 @@ ], "license": "MIT" }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -4418,6 +4637,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4545,6 +4773,31 @@ "node": ">=6" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -4601,6 +4854,15 @@ "node": ">=18" } }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4631,6 +4893,15 @@ "source-map": "^0.6.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4798,6 +5069,15 @@ "node": ">=18" } }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -4902,11 +5182,19 @@ } }, "node_modules/undici-types": { +<<<<<<< HEAD "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "license": "MIT", "optional": true +======= + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "devOptional": true, + "license": "MIT" +>>>>>>> 222c2ee (feat: add pino logger for serverside) }, "node_modules/uri-js": { "version": "4.4.1", @@ -5045,6 +5333,12 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/package.json b/package.json index ed485f8..a9b977c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,12 @@ "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", +<<<<<<< HEAD "drizzle-kit": "^0.31.5", +======= + "@types/node": "^24.9.1", + "drizzle-kit": "^0.31.4", +>>>>>>> 222c2ee (feat: add pino logger for serverside) "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", @@ -41,6 +46,8 @@ "@sveltejs/adapter-node": "^5.3.1", "drizzle-orm": "^0.44.5", "fuse.js": "^7.1.0", + "pino": "^10.1.0", + "pino-pretty": "^13.1.2", "postgres": "^3.4.7" } } diff --git a/src/hooks.server.ts b/src/hooks.server.ts index a0b3f5b..3610d7e 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -2,6 +2,7 @@ import type { Handle } from '@sveltejs/kit'; import { generateUserId } from '$lib/generateUserId.js'; import { ensureDatabaseConnection } from '$lib/database/healthCheck'; +import { logger } from '$lib/logger'; // Global flag to track if database health check has been performed let dbHealthCheckPerformed = false; @@ -18,7 +19,7 @@ export const handle: Handle = async ({ event, resolve }) => { }); dbHealthCheckPerformed = true; } catch (error) { - console.error('Database health check failed:', error); + logger.error({ error }, 'Database health check failed'); // The ensureDatabaseConnection function will exit the process // if the database is unavailable, so this catch is just for safety process.exit(1); @@ -33,11 +34,10 @@ export const handle: Handle = async ({ event, resolve }) => { const PATH = '/'; if (!cactoideUserId) { - console.debug(`There is no cactoideUserId cookie, generating new one...`); + logger.debug({ userId }, 'No cactoideUserId cookie found, generating new one'); event.cookies.set('cactoideUserId', userId, { path: PATH, maxAge: MAX_AGE }); } else { - console.debug(`cactoideUserId: ${cactoideUserId}`); - console.debug(`cactoideUserId cookie found, using existing one...`); + logger.debug({ cactoideUserId }, 'cactoideUserId cookie found, using existing one'); } return resolve(event); diff --git a/src/lib/database/healthCheck.ts b/src/lib/database/healthCheck.ts index de74c78..d1c3d52 100644 --- a/src/lib/database/healthCheck.ts +++ b/src/lib/database/healthCheck.ts @@ -1,5 +1,6 @@ import postgres from 'postgres'; import { env } from '$env/dynamic/private'; +import { logger } from '$lib/logger'; interface HealthCheckOptions { maxRetries?: number; @@ -29,7 +30,7 @@ export async function checkDatabaseHealth( } = options; if (!env.DATABASE_URL) { - console.error('DATABASE_URL environment variable is not set'); + logger.error('DATABASE_URL environment variable is not set'); return { success: false, error: 'DATABASE_URL environment variable is not set', @@ -39,10 +40,10 @@ export async function checkDatabaseHealth( let lastError: Error | null = null; - console.log(`Starting database health check (max retries: ${maxRetries})`); + logger.info({ maxRetries }, 'Starting database health check'); for (let attempt = 1; attempt <= maxRetries; attempt++) { - console.log(`Attempt ${attempt}/${maxRetries} - Testing database connection`); + logger.debug({ attempt, maxRetries }, 'Testing database connection'); try { // Create a new connection for the health check @@ -57,7 +58,7 @@ export async function checkDatabaseHealth( await client`SELECT 1 as health_check`; await client.end(); - console.log(`Database connection successful on attempt ${attempt}.`); + logger.info({ attempt }, 'Database connection successful'); return { success: true, @@ -66,12 +67,12 @@ export async function checkDatabaseHealth( } catch (error) { lastError = error as Error; const errorMessage = error instanceof Error ? error.message : 'Unknown error'; - console.error(`Connection failed on attempt ${attempt}: ${errorMessage}`); + logger.warn({ attempt, error: errorMessage }, 'Database connection failed'); // Don't wait after the last attempt if (attempt < maxRetries) { const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay); - console.log(`Waiting ${delay}ms before retry...`); + logger.debug({ delay }, 'Waiting before retry'); await new Promise((resolve) => setTimeout(resolve, delay)); } } @@ -79,7 +80,10 @@ export async function checkDatabaseHealth( const finalError = lastError?.message || 'Unknown database connection error'; - console.error(`All ${maxRetries} attempts failed. Final error: ${finalError}`); + logger.error( + { attempts: maxRetries, error: finalError }, + 'All database connection attempts failed' + ); return { success: false, @@ -95,10 +99,10 @@ export async function ensureDatabaseConnection(options?: HealthCheckOptions): Pr const result = await checkDatabaseHealth(options); if (!result.success) { - console.error('Database connection failed after all retry attempts'); - console.error(`Error: ${result.error}`); - console.error(`Attempts made: ${result.attempts}`); - console.error('Exiting application...'); + logger.fatal( + { error: result.error, attempts: result.attempts }, + 'Database connection failed after all retry attempts. Exiting application' + ); process.exit(1); } } diff --git a/src/lib/logger.ts b/src/lib/logger.ts new file mode 100644 index 0000000..b0200df --- /dev/null +++ b/src/lib/logger.ts @@ -0,0 +1,29 @@ +import pino from 'pino'; +import { LOG_PRETTY, LOG_LEVEL } from '$env/static/private'; + +const USE_PRETTY_LOGS = LOG_PRETTY === 'true'; + +const transport = USE_PRETTY_LOGS + ? { + target: 'pino-pretty', + options: { + colorize: true, + translateTime: 'SYS:standard', + ignore: 'pid,hostname' + } + } + : undefined; + +// Create the logger instance +export const logger = pino({ + level: LOG_LEVEL, + transport +}); + +// Export a helper to create child loggers with context +export function createChildLogger(bindings: Record) { + return logger.child(bindings); +} + +// Export types +export type Logger = typeof logger; diff --git a/src/routes/create/+page.server.ts b/src/routes/create/+page.server.ts index 657bb58..f642506 100644 --- a/src/routes/create/+page.server.ts +++ b/src/routes/create/+page.server.ts @@ -2,7 +2,11 @@ import { database } from '$lib/database/db'; import { events, inviteTokens } from '$lib/database/schema'; import { fail, redirect } from '@sveltejs/kit'; import type { Actions } from './$types'; +<<<<<<< HEAD import { generateInviteToken, calculateTokenExpiration } from '$lib/inviteTokenHelpers.js'; +======= +import { logger } from '$lib/logger'; +>>>>>>> 222c2ee (feat: add pino logger for serverside) // Generate a random URL-friendly ID function generateEventId(): string { @@ -116,7 +120,7 @@ export const actions: Actions = { userId: userId! }) .catch((error) => { - console.error('Unexpected error', error); + logger.error({ error, eventId, userId }, 'Unexpected error creating event'); throw error; }); diff --git a/src/routes/discover/+page.server.ts b/src/routes/discover/+page.server.ts index cec8aea..4d78b2d 100644 --- a/src/routes/discover/+page.server.ts +++ b/src/routes/discover/+page.server.ts @@ -2,6 +2,7 @@ import { database } from '$lib/database/db'; import { desc, inArray } from 'drizzle-orm'; import type { PageServerLoad } from './$types'; import { events } from '$lib/database/schema'; +import { logger } from '$lib/logger'; export const load: PageServerLoad = async () => { try { @@ -33,7 +34,7 @@ export const load: PageServerLoad = async () => { events: transformedEvents }; } catch (error) { - console.error('Error loading public events:', error); + logger.error({ error }, 'Error loading public events'); // Return empty array on error to prevent page crash return { diff --git a/src/routes/event/+page.server.ts b/src/routes/event/+page.server.ts index bac1dc8..f5cd8cc 100644 --- a/src/routes/event/+page.server.ts +++ b/src/routes/event/+page.server.ts @@ -3,6 +3,7 @@ import { events } from '$lib/database/schema'; import { fail } from '@sveltejs/kit'; import { eq, desc } from 'drizzle-orm'; import type { Actions } from './$types'; +import { logger } from '$lib/logger'; export const load = async ({ cookies }) => { const userId = cookies.get('cactoideUserId'); @@ -36,7 +37,7 @@ export const load = async ({ cookies }) => { return { events: transformedEvents }; } catch (error) { - console.error('Error loading user events:', error); + logger.error({ error, userId }, 'Error loading user events'); return { events: [] }; } }; @@ -68,7 +69,7 @@ export const actions: Actions = { return { success: true }; } catch (error) { - console.error('Error deleting event:', error); + logger.error({ error, eventId, userId }, 'Error deleting event'); return fail(500, { error: 'Failed to delete event' }); } } diff --git a/src/routes/event/[id]/+page.server.ts b/src/routes/event/[id]/+page.server.ts index afb8cc2..7e9c0a4 100644 --- a/src/routes/event/[id]/+page.server.ts +++ b/src/routes/event/[id]/+page.server.ts @@ -3,6 +3,7 @@ import { events, rsvps } from '$lib/database/schema'; import { eq, asc } from 'drizzle-orm'; import { error, fail } from '@sveltejs/kit'; import type { PageServerLoad, Actions } from './$types'; +import { logger } from '$lib/logger'; export const load: PageServerLoad = async ({ params, cookies }) => { const eventId = params.id; @@ -70,7 +71,7 @@ export const load: PageServerLoad = async ({ params, cookies }) => { } catch (err) { if (err instanceof Response) throw err; // This is the 404 error - console.error('Error loading event:', err); + logger.error({ error: err, eventId }, 'Error loading event'); throw error(500, 'Failed to load event'); } }; @@ -145,7 +146,7 @@ export const actions: Actions = { return { success: true, type: 'add' }; } catch (err) { - console.error('Error adding RSVP:', err); + logger.error({ error: err, eventId, userId, name }, 'Error adding RSVP'); return fail(500, { error: 'Failed to add RSVP' }); } }, @@ -163,7 +164,7 @@ export const actions: Actions = { await database.delete(rsvps).where(eq(rsvps.id, rsvpId)); return { success: true, type: 'remove' }; } catch (err) { - console.error('Error removing RSVP:', err); + logger.error({ error: err, rsvpId }, 'Error removing RSVP'); return fail(500, { error: 'Failed to remove RSVP' }); } } diff --git a/src/routes/event/[id]/edit/+page.server.ts b/src/routes/event/[id]/edit/+page.server.ts index 44c2040..fd61dd0 100644 --- a/src/routes/event/[id]/edit/+page.server.ts +++ b/src/routes/event/[id]/edit/+page.server.ts @@ -3,6 +3,7 @@ import { events, inviteTokens } from '$lib/database/schema'; import { eq, and } from 'drizzle-orm'; import { fail, redirect } from '@sveltejs/kit'; import type { Actions, PageServerLoad } from './$types'; +import { logger } from '$lib/logger'; export const load: PageServerLoad = async ({ params, cookies }) => { const eventId = params.id; @@ -165,7 +166,7 @@ export const actions: Actions = { }) .where(and(eq(events.id, eventId), eq(events.userId, userId))) .catch((error) => { - console.error('Unexpected error updating event', error); + logger.error({ error, eventId, userId }, 'Unexpected error updating event'); throw error; }); diff --git a/tsconfig.json b/tsconfig.json index a8f10c8..15f7fcc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "moduleResolution": "bundler" + "moduleResolution": "bundler", + "types": ["node"] } }