Thomas Zhang 3 mesiacov pred
rodič
commit
95c8c07394
3 zmenil súbory, kde vykonal 345 pridanie a 10 odobranie
  1. 281 9
      package-lock.json
  2. 2 1
      package.json
  3. 62 0
      src/lib/server/logger.ts

+ 281 - 9
package-lock.json

@@ -53,7 +53,8 @@
 				"vaul-svelte": "^1.0.0-next.7",
 				"vite": "^7.3.1",
 				"vitest": "^4.1.0",
-				"vitest-browser-svelte": "^2.0.2"
+				"vitest-browser-svelte": "^2.0.2",
+				"winston": "^3.19.0"
 			}
 		},
 		"node_modules/@ark/schema": {
@@ -118,6 +119,28 @@
 			"dev": true,
 			"license": "MIT"
 		},
+		"node_modules/@colors/colors": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+			"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.1.90"
+			}
+		},
+		"node_modules/@dabh/diagnostics": {
+			"version": "2.0.8",
+			"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz",
+			"integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@so-ric/colorspace": "^1.1.6",
+				"enabled": "2.0.x",
+				"kuler": "^2.0.0"
+			}
+		},
 		"node_modules/@dagrejs/dagre": {
 			"version": "2.0.4",
 			"resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-2.0.4.tgz",
@@ -1538,6 +1561,17 @@
 			"license": "BSD-3-Clause",
 			"optional": true
 		},
+		"node_modules/@so-ric/colorspace": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz",
+			"integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color": "^5.0.2",
+				"text-hex": "1.0.x"
+			}
+		},
 		"node_modules/@standard-schema/spec": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
@@ -2067,6 +2101,13 @@
 				"undici-types": "~6.21.0"
 			}
 		},
+		"node_modules/@types/triple-beam": {
+			"version": "1.3.5",
+			"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+			"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/@types/trusted-types": {
 			"version": "2.0.7",
 			"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
@@ -2729,6 +2770,13 @@
 				"node": ">=12"
 			}
 		},
+		"node_modules/async": {
+			"version": "3.2.6",
+			"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+			"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/axobject-query": {
 			"version": "4.1.0",
 			"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -2879,6 +2927,20 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/color": {
+			"version": "5.0.3",
+			"resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz",
+			"integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "^3.1.3",
+				"color-string": "^2.1.3"
+			},
+			"engines": {
+				"node": ">=18"
+			}
+		},
 		"node_modules/color-convert": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2899,29 +2961,42 @@
 			"dev": true,
 			"license": "MIT"
 		},
-		"node_modules/color/node_modules/color-convert": {
-			"version": "3.1.3",
-			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
-			"integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
-			"extraneous": true,
+		"node_modules/color-string": {
+			"version": "2.1.4",
+			"resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz",
+			"integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"color-name": "^2.0.0"
 			},
 			"engines": {
-				"node": ">=14.6"
+				"node": ">=18"
 			}
 		},
-		"node_modules/color/node_modules/color-name": {
+		"node_modules/color-string/node_modules/color-name": {
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
 			"integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
-			"extraneous": true,
+			"dev": true,
 			"license": "MIT",
 			"engines": {
 				"node": ">=12.20"
 			}
 		},
+		"node_modules/color/node_modules/color-convert": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
+			"integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-name": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=14.6"
+			}
+		},
 		"node_modules/colorette": {
 			"version": "1.4.0",
 			"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -3449,6 +3524,13 @@
 				"fast-check": "^3.23.1"
 			}
 		},
+		"node_modules/enabled": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+			"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/enhanced-resolve": {
 			"version": "5.20.0",
 			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz",
@@ -3866,6 +3948,13 @@
 				}
 			}
 		},
+		"node_modules/fecha": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+			"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/file-entry-cache": {
 			"version": "8.0.0",
 			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3917,6 +4006,13 @@
 			"dev": true,
 			"license": "ISC"
 		},
+		"node_modules/fn.name": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+			"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/formsnap": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/formsnap/-/formsnap-2.0.1.tgz",
@@ -4093,6 +4189,13 @@
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
+		"node_modules/inherits": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+			"dev": true,
+			"license": "ISC"
+		},
 		"node_modules/inline-style-parser": {
 			"version": "0.2.7",
 			"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
@@ -4143,6 +4246,19 @@
 				"@types/estree": "^1.0.6"
 			}
 		},
+		"node_modules/is-stream": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+			"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
 		"node_modules/isexe": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -4268,6 +4384,13 @@
 			"dev": true,
 			"license": "MIT"
 		},
+		"node_modules/kuler": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+			"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/layerchart": {
 			"version": "2.0.0-next.62",
 			"resolved": "https://registry.npmjs.org/layerchart/-/layerchart-2.0.0-next.62.tgz",
@@ -4673,6 +4796,24 @@
 			"dev": true,
 			"license": "MIT"
 		},
+		"node_modules/logform": {
+			"version": "2.7.0",
+			"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
+			"integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@colors/colors": "1.6.0",
+				"@types/triple-beam": "^1.3.2",
+				"fecha": "^4.2.0",
+				"ms": "^2.1.1",
+				"safe-stable-stringify": "^2.3.1",
+				"triple-beam": "^1.3.0"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			}
+		},
 		"node_modules/lz-string": {
 			"version": "1.5.0",
 			"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
@@ -4904,6 +5045,16 @@
 			],
 			"license": "MIT"
 		},
+		"node_modules/one-time": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+			"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fn.name": "1.x.x"
+			}
+		},
 		"node_modules/openapi-typescript": {
 			"version": "7.13.0",
 			"resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz",
@@ -5488,6 +5639,21 @@
 			"license": "MIT",
 			"optional": true
 		},
+		"node_modules/readable-stream": {
+			"version": "3.6.2",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+			"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"inherits": "^2.0.3",
+				"string_decoder": "^1.1.1",
+				"util-deprecate": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
 		"node_modules/readdirp": {
 			"version": "4.1.2",
 			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@@ -5619,6 +5785,37 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/safe-buffer": {
+			"version": "5.2.1",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+			"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+			"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"
+				}
+			],
+			"license": "MIT"
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			}
+		},
 		"node_modules/safer-buffer": {
 			"version": "2.1.2",
 			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -5730,6 +5927,16 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/stack-trace": {
+			"version": "0.0.10",
+			"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+			"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "*"
+			}
+		},
 		"node_modules/stackback": {
 			"version": "0.0.2",
 			"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -5744,6 +5951,16 @@
 			"dev": true,
 			"license": "MIT"
 		},
+		"node_modules/string_decoder": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+			"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"safe-buffer": "~5.2.0"
+			}
+		},
 		"node_modules/strip-json-comments": {
 			"version": "3.1.1",
 			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -6096,6 +6313,13 @@
 				"url": "https://opencollective.com/webpack"
 			}
 		},
+		"node_modules/text-hex": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+			"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/tiny-case": {
 			"version": "1.0.3",
 			"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
@@ -6166,6 +6390,16 @@
 				"node": ">=6"
 			}
 		},
+		"node_modules/triple-beam": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+			"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 14.0.0"
+			}
+		},
 		"node_modules/ts-algebra": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
@@ -6643,6 +6877,44 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/winston": {
+			"version": "3.19.0",
+			"resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
+			"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@colors/colors": "^1.6.0",
+				"@dabh/diagnostics": "^2.0.8",
+				"async": "^3.2.3",
+				"is-stream": "^2.0.0",
+				"logform": "^2.7.0",
+				"one-time": "^1.0.0",
+				"readable-stream": "^3.4.0",
+				"safe-stable-stringify": "^2.3.1",
+				"stack-trace": "0.0.x",
+				"triple-beam": "^1.3.0",
+				"winston-transport": "^4.9.0"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			}
+		},
+		"node_modules/winston-transport": {
+			"version": "4.9.0",
+			"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
+			"integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"logform": "^2.7.0",
+				"readable-stream": "^3.6.2",
+				"triple-beam": "^1.3.0"
+			},
+			"engines": {
+				"node": ">= 12.0.0"
+			}
+		},
 		"node_modules/word-wrap": {
 			"version": "1.2.5",
 			"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",

+ 2 - 1
package.json

@@ -63,6 +63,7 @@
 		"vaul-svelte": "^1.0.0-next.7",
 		"vite": "^7.3.1",
 		"vitest": "^4.1.0",
-		"vitest-browser-svelte": "^2.0.2"
+		"vitest-browser-svelte": "^2.0.2",
+		"winston": "^3.19.0"
 	}
 }

+ 62 - 0
src/lib/server/logger.ts

@@ -0,0 +1,62 @@
+/**
+ * Structured logging via Winston.
+ *
+ * One root logger is created at module load. Each domain gets a child logger
+ * that adds a `domain` field to every log entry so log lines can be filtered
+ * and routed independently.
+ *
+ * A custom format reads the current request context from AsyncLocalStorage and
+ * injects `requestId` into every log entry automatically — no manual threading needed.
+ *
+ * Optional env vars:
+ *   LOG_LEVEL  — winston level (default: "info"; use "debug" for verbose output)
+ *   NODE_ENV   — when "development", logs are pretty-printed; otherwise JSON
+ */
+import { createLogger, format, transports } from 'winston';
+
+import { getContext } from '$lib/server/context';
+
+import { env } from '$env/dynamic/private';
+
+const level = env.LOG_LEVEL ?? 'info';
+
+// Injects requestId from AsyncLocalStorage into every log entry.
+const requestContextFormat = format((info) => {
+	const ctx = getContext();
+	if (ctx) info['requestId'] = ctx.requestId;
+	return info;
+});
+
+const productionFormat = format.combine(
+	requestContextFormat(),
+	format.timestamp(),
+	format.errors({ stack: true }),
+	format.json(),
+);
+
+const developmentFormat = format.combine(
+	requestContextFormat(),
+	format.timestamp({ format: 'HH:mm:ss' }),
+	format.errors({ stack: true }),
+	format.colorize(),
+	format.printf(({ timestamp, level, message, domain, requestId, ...rest }) => {
+		const domainTag = domain ? `[${domain}] ` : '';
+		const rid = requestId ? `(${requestId}) ` : '';
+		const extra = Object.keys(rest).length ? ' ' + JSON.stringify(rest) : '';
+		return `${timestamp} ${level} ${domainTag}${rid}${message}${extra}`;
+	}),
+);
+
+const root = createLogger({
+	level,
+	format: env.NODE_ENV === 'development' ? developmentFormat : productionFormat,
+	transports: [new transports.Console()],
+});
+
+const child = (domain: string) => root.child({ domain });
+
+// --- Domain loggers ---
+
+const serverLogger = child('server');
+
+export { root as logger, serverLogger };