@loglayer/express 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Theo Gravity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Express integration for LogLayer
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/%40loglayer%2Fexpress)](https://www.npmjs.com/package/@loglayer/express)
4
+ [![NPM Downloads](https://img.shields.io/npm/dm/%40loglayer%2Fexpress)](https://www.npmjs.com/package/@loglayer/express)
5
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
6
+
7
+ An [Express](https://expressjs.com) middleware for [LogLayer](https://loglayer.dev) that provides request-scoped logging with automatic request/response logging and error handling.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @loglayer/express
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import express from "express";
19
+ import { LogLayer, StructuredTransport } from "loglayer";
20
+ import { expressLogLayer, expressLogLayerErrorHandler } from "@loglayer/express";
21
+
22
+ const log = new LogLayer({
23
+ transport: new StructuredTransport({ logger: console }),
24
+ });
25
+
26
+ const app = express();
27
+ app.use(expressLogLayer({ instance: log }));
28
+
29
+ app.get("/", (req, res) => {
30
+ req.log.info("Hello!");
31
+ res.send("Hello World!");
32
+ });
33
+
34
+ // Error handler (must be registered after routes)
35
+ app.use(expressLogLayerErrorHandler());
36
+
37
+ export default app;
38
+ ```
39
+
40
+ ## Documentation
41
+
42
+ For more details, visit [https://loglayer.dev/integrations/express](https://loglayer.dev/integrations/express)
package/dist/index.cjs ADDED
@@ -0,0 +1,154 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/plugin.ts
4
+ function resolveGroupConfig(group) {
5
+ if (!group) return {
6
+ nameGroup: void 0,
7
+ requestGroup: void 0,
8
+ responseGroup: void 0
9
+ };
10
+ if (group === true) return {
11
+ nameGroup: "express",
12
+ requestGroup: "express.request",
13
+ responseGroup: "express.response"
14
+ };
15
+ return {
16
+ nameGroup: group.name ?? "express",
17
+ requestGroup: group.request ?? "express.request",
18
+ responseGroup: group.response ?? "express.response"
19
+ };
20
+ }
21
+ function shouldIgnorePath(path, ignore) {
22
+ if (!ignore || ignore.length === 0) return false;
23
+ for (const pattern of ignore) if (typeof pattern === "string") {
24
+ if (path === pattern) return true;
25
+ } else if (pattern.test(path)) return true;
26
+ return false;
27
+ }
28
+ function getRequestId(request, requestIdConfig) {
29
+ if (requestIdConfig === false) return void 0;
30
+ if (typeof requestIdConfig === "function") return requestIdConfig(request);
31
+ return crypto.randomUUID();
32
+ }
33
+ function resolveLoggingConfig(value, defaultEnabled) {
34
+ if (value === void 0) return defaultEnabled ? {} : false;
35
+ if (value === true) return {};
36
+ if (value === false) return false;
37
+ return value;
38
+ }
39
+ /**
40
+ * Creates an Express middleware that integrates LogLayer for request-scoped logging.
41
+ *
42
+ * The middleware attaches a child LogLayer instance to `req.log` for each request.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * import express from "express";
47
+ * import { LogLayer, ConsoleTransport } from "loglayer";
48
+ * import { expressLogLayer } from "@loglayer/express";
49
+ *
50
+ * const log = new LogLayer({ transport: new ConsoleTransport() });
51
+ *
52
+ * const app = express();
53
+ * app.use(expressLogLayer({ instance: log }));
54
+ *
55
+ * app.get("/", (req, res) => {
56
+ * req.log.info("Hello from route!");
57
+ * res.send("Hello World!");
58
+ * });
59
+ * ```
60
+ */
61
+ function expressLogLayer(config) {
62
+ const { instance, requestId: requestIdConfig = true, autoLogging: autoLoggingConfig = true, contextFn, group: groupConfig } = config;
63
+ const { requestGroup, responseGroup } = resolveGroupConfig(groupConfig);
64
+ const autoLogging = autoLoggingConfig === true ? {} : autoLoggingConfig === false ? false : autoLoggingConfig;
65
+ const requestConfig = autoLogging ? resolveLoggingConfig(autoLogging.request, true) : false;
66
+ const responseConfig = autoLogging ? resolveLoggingConfig(autoLogging.response, true) : false;
67
+ const defaultLogLevel = autoLogging ? autoLogging.logLevel ?? "info" : "info";
68
+ const requestLogLevel = requestConfig ? requestConfig.logLevel ?? defaultLogLevel : defaultLogLevel;
69
+ const responseLogLevel = responseConfig ? responseConfig.logLevel ?? defaultLogLevel : defaultLogLevel;
70
+ return (req, res, next) => {
71
+ const context = {};
72
+ const reqId = getRequestId(req, requestIdConfig);
73
+ if (reqId) context.requestId = reqId;
74
+ if (contextFn) {
75
+ const additionalContext = contextFn(req);
76
+ if (additionalContext) Object.assign(context, additionalContext);
77
+ }
78
+ const childLogger = instance.child().withContext(context);
79
+ req.log = childLogger;
80
+ const startTime = Date.now();
81
+ const ignorePath = autoLogging ? shouldIgnorePath(req.path, autoLogging.ignore) : true;
82
+ if (requestConfig && !ignorePath) {
83
+ let builder = childLogger.withMetadata({ req: {
84
+ method: req.method,
85
+ url: req.originalUrl || req.url,
86
+ remoteAddress: req.ip
87
+ } });
88
+ if (requestGroup) builder = builder.withGroup(requestGroup);
89
+ builder[requestLogLevel]("incoming request");
90
+ }
91
+ if (responseConfig && !ignorePath) {
92
+ const onResponseComplete = () => {
93
+ res.removeListener("close", onResponseComplete);
94
+ res.removeListener("finish", onResponseComplete);
95
+ res.removeListener("error", onResponseComplete);
96
+ const responseTime = Date.now() - startTime;
97
+ let builder = childLogger.withMetadata({
98
+ req: {
99
+ method: req.method,
100
+ url: req.originalUrl || req.url,
101
+ remoteAddress: req.ip
102
+ },
103
+ res: { statusCode: res.statusCode },
104
+ responseTime
105
+ });
106
+ if (responseGroup) builder = builder.withGroup(responseGroup);
107
+ builder[responseLogLevel]("request completed");
108
+ };
109
+ res.on("close", onResponseComplete);
110
+ res.on("finish", onResponseComplete);
111
+ res.on("error", onResponseComplete);
112
+ }
113
+ next();
114
+ };
115
+ }
116
+ /**
117
+ * Creates an Express error-handling middleware that logs errors via LogLayer.
118
+ *
119
+ * This middleware should be registered after all routes. It logs the error
120
+ * using `req.log` (set by `expressLogLayer`) and passes the error to the
121
+ * next error handler via `next(err)`.
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * import express from "express";
126
+ * import { expressLogLayer, expressLogLayerErrorHandler } from "@loglayer/express";
127
+ *
128
+ * const app = express();
129
+ * app.use(expressLogLayer({ instance: log }));
130
+ *
131
+ * // ... routes ...
132
+ *
133
+ * app.use(expressLogLayerErrorHandler());
134
+ * app.use((err, req, res, next) => {
135
+ * res.status(500).send("Internal Server Error");
136
+ * });
137
+ * ```
138
+ */
139
+ function expressLogLayerErrorHandler(config) {
140
+ const { nameGroup } = resolveGroupConfig(config?.group);
141
+ return (err, req, _res, next) => {
142
+ if (req.log) {
143
+ let builder = req.log.withError(err).withMetadata({ url: req.originalUrl || req.url });
144
+ if (nameGroup) builder = builder.withGroup(nameGroup);
145
+ builder.error("Request error");
146
+ }
147
+ next(err);
148
+ };
149
+ }
150
+
151
+ //#endregion
152
+ exports.expressLogLayer = expressLogLayer;
153
+ exports.expressLogLayerErrorHandler = expressLogLayerErrorHandler;
154
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type { ErrorRequestHandler, NextFunction, Request, Response } from \"express\";\nimport type { ILogLayer } from \"loglayer\";\nimport type {\n ExpressAutoLoggingConfig,\n ExpressLogLayerConfig,\n ExpressRequestLoggingConfig,\n ExpressResponseLoggingConfig,\n} from \"./types.js\";\n\nfunction resolveGroupConfig(group: ExpressLogLayerConfig[\"group\"]) {\n if (!group) return { nameGroup: undefined, requestGroup: undefined, responseGroup: undefined };\n if (group === true)\n return { nameGroup: \"express\", requestGroup: \"express.request\", responseGroup: \"express.response\" };\n return {\n nameGroup: group.name ?? \"express\",\n requestGroup: group.request ?? \"express.request\",\n responseGroup: group.response ?? \"express.response\",\n };\n}\n\nfunction shouldIgnorePath(path: string, ignore?: Array<string | RegExp>): boolean {\n if (!ignore || ignore.length === 0) return false;\n\n for (const pattern of ignore) {\n if (typeof pattern === \"string\") {\n if (path === pattern) return true;\n } else if (pattern.test(path)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction getRequestId(request: Request, requestIdConfig: ExpressLogLayerConfig[\"requestId\"]): string | undefined {\n if (requestIdConfig === false) return undefined;\n if (typeof requestIdConfig === \"function\") return requestIdConfig(request);\n return crypto.randomUUID();\n}\n\nfunction resolveLoggingConfig<T>(value: boolean | T | undefined, defaultEnabled: boolean): T | false {\n if (value === undefined) return defaultEnabled ? ({} as T) : false;\n if (value === true) return {} as T;\n if (value === false) return false;\n return value;\n}\n\n/**\n * Creates an Express middleware that integrates LogLayer for request-scoped logging.\n *\n * The middleware attaches a child LogLayer instance to `req.log` for each request.\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { LogLayer, ConsoleTransport } from \"loglayer\";\n * import { expressLogLayer } from \"@loglayer/express\";\n *\n * const log = new LogLayer({ transport: new ConsoleTransport() });\n *\n * const app = express();\n * app.use(expressLogLayer({ instance: log }));\n *\n * app.get(\"/\", (req, res) => {\n * req.log.info(\"Hello from route!\");\n * res.send(\"Hello World!\");\n * });\n * ```\n */\nexport function expressLogLayer(config: ExpressLogLayerConfig) {\n const {\n instance,\n requestId: requestIdConfig = true,\n autoLogging: autoLoggingConfig = true,\n contextFn,\n group: groupConfig,\n } = config;\n const { requestGroup, responseGroup } = resolveGroupConfig(groupConfig);\n\n const autoLogging: ExpressAutoLoggingConfig | false =\n autoLoggingConfig === true ? {} : autoLoggingConfig === false ? false : autoLoggingConfig;\n\n // Resolve auto-logging configs once\n const requestConfig = autoLogging\n ? resolveLoggingConfig<ExpressRequestLoggingConfig>(autoLogging.request, true)\n : false;\n const responseConfig = autoLogging\n ? resolveLoggingConfig<ExpressResponseLoggingConfig>(autoLogging.response, true)\n : false;\n\n const defaultLogLevel = autoLogging ? (autoLogging.logLevel ?? \"info\") : \"info\";\n const requestLogLevel = requestConfig ? (requestConfig.logLevel ?? defaultLogLevel) : defaultLogLevel;\n const responseLogLevel = responseConfig ? (responseConfig.logLevel ?? defaultLogLevel) : defaultLogLevel;\n\n return (req: Request, res: Response, next: NextFunction) => {\n const context: Record<string, any> = {};\n\n const reqId = getRequestId(req, requestIdConfig);\n if (reqId) {\n context.requestId = reqId;\n }\n\n if (contextFn) {\n const additionalContext = contextFn(req);\n if (additionalContext) {\n Object.assign(context, additionalContext);\n }\n }\n\n // Create child logger and attach to req.log\n const childLogger = instance.child().withContext(context) as ILogLayer;\n (req as any).log = childLogger;\n\n const startTime = Date.now();\n const ignorePath = autoLogging ? shouldIgnorePath(req.path, autoLogging.ignore) : true;\n\n // Log incoming request\n if (requestConfig && !ignorePath) {\n let builder = childLogger.withMetadata({\n req: {\n method: req.method,\n url: req.originalUrl || req.url,\n remoteAddress: req.ip,\n },\n });\n if (requestGroup) builder = builder.withGroup(requestGroup);\n builder[requestLogLevel](\"incoming request\");\n }\n\n // Log response on completion (listen on close, finish, and error for reliability)\n if (responseConfig && !ignorePath) {\n const onResponseComplete = () => {\n res.removeListener(\"close\", onResponseComplete);\n res.removeListener(\"finish\", onResponseComplete);\n res.removeListener(\"error\", onResponseComplete);\n\n const responseTime = Date.now() - startTime;\n let builder = childLogger.withMetadata({\n req: {\n method: req.method,\n url: req.originalUrl || req.url,\n remoteAddress: req.ip,\n },\n res: {\n statusCode: res.statusCode,\n },\n responseTime,\n });\n if (responseGroup) builder = builder.withGroup(responseGroup);\n builder[responseLogLevel](\"request completed\");\n };\n\n res.on(\"close\", onResponseComplete);\n res.on(\"finish\", onResponseComplete);\n res.on(\"error\", onResponseComplete);\n }\n\n next();\n };\n}\n\n/**\n * Creates an Express error-handling middleware that logs errors via LogLayer.\n *\n * This middleware should be registered after all routes. It logs the error\n * using `req.log` (set by `expressLogLayer`) and passes the error to the\n * next error handler via `next(err)`.\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { expressLogLayer, expressLogLayerErrorHandler } from \"@loglayer/express\";\n *\n * const app = express();\n * app.use(expressLogLayer({ instance: log }));\n *\n * // ... routes ...\n *\n * app.use(expressLogLayerErrorHandler());\n * app.use((err, req, res, next) => {\n * res.status(500).send(\"Internal Server Error\");\n * });\n * ```\n */\nexport function expressLogLayerErrorHandler(config?: { group?: ExpressLogLayerConfig[\"group\"] }): ErrorRequestHandler {\n const { nameGroup } = resolveGroupConfig(config?.group);\n\n return (err: Error, req: Request, _res: Response, next: NextFunction) => {\n if ((req as any).log) {\n let builder = ((req as any).log as ILogLayer).withError(err).withMetadata({ url: req.originalUrl || req.url });\n if (nameGroup) builder = builder.withGroup(nameGroup);\n builder.error(\"Request error\");\n }\n next(err);\n };\n}\n"],"mappings":";;;AASA,SAAS,mBAAmB,OAAuC;AACjE,KAAI,CAAC,MAAO,QAAO;EAAE,WAAW;EAAW,cAAc;EAAW,eAAe;EAAW;AAC9F,KAAI,UAAU,KACZ,QAAO;EAAE,WAAW;EAAW,cAAc;EAAmB,eAAe;EAAoB;AACrG,QAAO;EACL,WAAW,MAAM,QAAQ;EACzB,cAAc,MAAM,WAAW;EAC/B,eAAe,MAAM,YAAY;EAClC;;AAGH,SAAS,iBAAiB,MAAc,QAA0C;AAChF,KAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO;AAE3C,MAAK,MAAM,WAAW,OACpB,KAAI,OAAO,YAAY,UACrB;MAAI,SAAS,QAAS,QAAO;YACpB,QAAQ,KAAK,KAAK,CAC3B,QAAO;AAIX,QAAO;;AAGT,SAAS,aAAa,SAAkB,iBAAyE;AAC/G,KAAI,oBAAoB,MAAO,QAAO;AACtC,KAAI,OAAO,oBAAoB,WAAY,QAAO,gBAAgB,QAAQ;AAC1E,QAAO,OAAO,YAAY;;AAG5B,SAAS,qBAAwB,OAAgC,gBAAoC;AACnG,KAAI,UAAU,OAAW,QAAO,iBAAkB,EAAE,GAAS;AAC7D,KAAI,UAAU,KAAM,QAAO,EAAE;AAC7B,KAAI,UAAU,MAAO,QAAO;AAC5B,QAAO;;;;;;;;;;;;;;;;;;;;;;;;AAyBT,SAAgB,gBAAgB,QAA+B;CAC7D,MAAM,EACJ,UACA,WAAW,kBAAkB,MAC7B,aAAa,oBAAoB,MACjC,WACA,OAAO,gBACL;CACJ,MAAM,EAAE,cAAc,kBAAkB,mBAAmB,YAAY;CAEvE,MAAM,cACJ,sBAAsB,OAAO,EAAE,GAAG,sBAAsB,QAAQ,QAAQ;CAG1E,MAAM,gBAAgB,cAClB,qBAAkD,YAAY,SAAS,KAAK,GAC5E;CACJ,MAAM,iBAAiB,cACnB,qBAAmD,YAAY,UAAU,KAAK,GAC9E;CAEJ,MAAM,kBAAkB,cAAe,YAAY,YAAY,SAAU;CACzE,MAAM,kBAAkB,gBAAiB,cAAc,YAAY,kBAAmB;CACtF,MAAM,mBAAmB,iBAAkB,eAAe,YAAY,kBAAmB;AAEzF,SAAQ,KAAc,KAAe,SAAuB;EAC1D,MAAM,UAA+B,EAAE;EAEvC,MAAM,QAAQ,aAAa,KAAK,gBAAgB;AAChD,MAAI,MACF,SAAQ,YAAY;AAGtB,MAAI,WAAW;GACb,MAAM,oBAAoB,UAAU,IAAI;AACxC,OAAI,kBACF,QAAO,OAAO,SAAS,kBAAkB;;EAK7C,MAAM,cAAc,SAAS,OAAO,CAAC,YAAY,QAAQ;AACzD,EAAC,IAAY,MAAM;EAEnB,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,aAAa,cAAc,iBAAiB,IAAI,MAAM,YAAY,OAAO,GAAG;AAGlF,MAAI,iBAAiB,CAAC,YAAY;GAChC,IAAI,UAAU,YAAY,aAAa,EACrC,KAAK;IACH,QAAQ,IAAI;IACZ,KAAK,IAAI,eAAe,IAAI;IAC5B,eAAe,IAAI;IACpB,EACF,CAAC;AACF,OAAI,aAAc,WAAU,QAAQ,UAAU,aAAa;AAC3D,WAAQ,iBAAiB,mBAAmB;;AAI9C,MAAI,kBAAkB,CAAC,YAAY;GACjC,MAAM,2BAA2B;AAC/B,QAAI,eAAe,SAAS,mBAAmB;AAC/C,QAAI,eAAe,UAAU,mBAAmB;AAChD,QAAI,eAAe,SAAS,mBAAmB;IAE/C,MAAM,eAAe,KAAK,KAAK,GAAG;IAClC,IAAI,UAAU,YAAY,aAAa;KACrC,KAAK;MACH,QAAQ,IAAI;MACZ,KAAK,IAAI,eAAe,IAAI;MAC5B,eAAe,IAAI;MACpB;KACD,KAAK,EACH,YAAY,IAAI,YACjB;KACD;KACD,CAAC;AACF,QAAI,cAAe,WAAU,QAAQ,UAAU,cAAc;AAC7D,YAAQ,kBAAkB,oBAAoB;;AAGhD,OAAI,GAAG,SAAS,mBAAmB;AACnC,OAAI,GAAG,UAAU,mBAAmB;AACpC,OAAI,GAAG,SAAS,mBAAmB;;AAGrC,QAAM;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BV,SAAgB,4BAA4B,QAA0E;CACpH,MAAM,EAAE,cAAc,mBAAmB,QAAQ,MAAM;AAEvD,SAAQ,KAAY,KAAc,MAAgB,SAAuB;AACvE,MAAK,IAAY,KAAK;GACpB,IAAI,UAAY,IAAY,IAAkB,UAAU,IAAI,CAAC,aAAa,EAAE,KAAK,IAAI,eAAe,IAAI,KAAK,CAAC;AAC9G,OAAI,UAAW,WAAU,QAAQ,UAAU,UAAU;AACrD,WAAQ,MAAM,gBAAgB;;AAEhC,OAAK,IAAI"}
@@ -0,0 +1,184 @@
1
+ import { ILogLayer, LogLevelType } from "loglayer";
2
+ import { ErrorRequestHandler, NextFunction, Request, Response } from "express";
3
+
4
+ //#region src/types.d.ts
5
+ /**
6
+ * Configuration for request logging.
7
+ * Logs when a request is received, before the route handler runs.
8
+ */
9
+ interface ExpressRequestLoggingConfig {
10
+ /**
11
+ * The log level to use for request logs.
12
+ * @default "info"
13
+ */
14
+ logLevel?: LogLevelType;
15
+ }
16
+ /**
17
+ * Configuration for response logging.
18
+ * Logs after the route handler completes and the response is sent.
19
+ */
20
+ interface ExpressResponseLoggingConfig {
21
+ /**
22
+ * The log level to use for response logs.
23
+ * @default "info"
24
+ */
25
+ logLevel?: LogLevelType;
26
+ }
27
+ /**
28
+ * Configuration for the auto-logging feature.
29
+ */
30
+ interface ExpressAutoLoggingConfig {
31
+ /**
32
+ * The log level to use for both request and response logs (can be overridden individually).
33
+ * @default "info"
34
+ */
35
+ logLevel?: LogLevelType;
36
+ /**
37
+ * Array of path patterns to ignore from auto-logging.
38
+ * Supports exact string matches and RegExp.
39
+ * @example ["/health", /^\/internal\//]
40
+ */
41
+ ignore?: Array<string | RegExp>;
42
+ /**
43
+ * Controls request logging (fires when request is received).
44
+ * When enabled, logs: `"incoming request"` with metadata `{ req: { method, url, remoteAddress } }`.
45
+ * - `true`: enables request logging (default)
46
+ * - `false`: disables request logging
47
+ * - `object`: enables with custom configuration
48
+ * @default true
49
+ */
50
+ request?: boolean | ExpressRequestLoggingConfig;
51
+ /**
52
+ * Controls response logging (fires after response is sent).
53
+ * When enabled, logs: `"request completed"` with metadata `{ req: { method, url, remoteAddress }, res: { statusCode }, responseTime }`.
54
+ * - `true`: enables response logging (default)
55
+ * - `false`: disables response logging
56
+ * - `object`: enables with custom configuration
57
+ * @default true
58
+ */
59
+ response?: boolean | ExpressResponseLoggingConfig;
60
+ }
61
+ /**
62
+ * Group names for auto-logged messages.
63
+ */
64
+ interface ExpressGroupConfig {
65
+ /**
66
+ * Group name for internal auto-logs (errors, etc.).
67
+ * @default "express"
68
+ */
69
+ name?: string;
70
+ /**
71
+ * Group name for auto-logged incoming request messages.
72
+ * @default "express.request"
73
+ */
74
+ request?: string;
75
+ /**
76
+ * Group name for auto-logged response messages.
77
+ * @default "express.response"
78
+ */
79
+ response?: string;
80
+ }
81
+ /**
82
+ * Configuration for the Express LogLayer integration middleware.
83
+ */
84
+ interface ExpressLogLayerConfig {
85
+ /**
86
+ * The LogLayer instance to use for logging.
87
+ * A child logger will be created for each request.
88
+ */
89
+ instance: ILogLayer;
90
+ /**
91
+ * Controls request ID generation.
92
+ * - `true`: generates a request ID using `crypto.randomUUID()` (default)
93
+ * - `false`: disables request ID generation
94
+ * - `function`: custom function to generate a request ID from the request
95
+ * @default true
96
+ */
97
+ requestId?: boolean | ((request: Request) => string);
98
+ /**
99
+ * Controls automatic request/response logging.
100
+ * - `true`: enables auto-logging with defaults (default)
101
+ * - `false`: disables auto-logging
102
+ * - `object`: enables auto-logging with custom configuration
103
+ * @default true
104
+ */
105
+ autoLogging?: boolean | ExpressAutoLoggingConfig;
106
+ /**
107
+ * Optional function to extract additional context from the request.
108
+ * The returned object will be merged into the per-request logger's context.
109
+ */
110
+ contextFn?: (request: Request) => Record<string, any>;
111
+ /**
112
+ * Tags auto-logged request/response messages with groups for filtering/routing.
113
+ * - `true`: tag with default group names (`"express.request"`, `"express.response"`)
114
+ * - `object`: tag with custom group names
115
+ *
116
+ * Only affects auto-logged messages. User logs from route handlers are not tagged.
117
+ *
118
+ * @see {@link https://loglayer.dev/logging-api/groups.html | Groups Docs}
119
+ */
120
+ group?: boolean | ExpressGroupConfig;
121
+ }
122
+ //#endregion
123
+ //#region src/plugin.d.ts
124
+ /**
125
+ * Creates an Express middleware that integrates LogLayer for request-scoped logging.
126
+ *
127
+ * The middleware attaches a child LogLayer instance to `req.log` for each request.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * import express from "express";
132
+ * import { LogLayer, ConsoleTransport } from "loglayer";
133
+ * import { expressLogLayer } from "@loglayer/express";
134
+ *
135
+ * const log = new LogLayer({ transport: new ConsoleTransport() });
136
+ *
137
+ * const app = express();
138
+ * app.use(expressLogLayer({ instance: log }));
139
+ *
140
+ * app.get("/", (req, res) => {
141
+ * req.log.info("Hello from route!");
142
+ * res.send("Hello World!");
143
+ * });
144
+ * ```
145
+ */
146
+ declare function expressLogLayer(config: ExpressLogLayerConfig): (req: Request, res: Response, next: NextFunction) => void;
147
+ /**
148
+ * Creates an Express error-handling middleware that logs errors via LogLayer.
149
+ *
150
+ * This middleware should be registered after all routes. It logs the error
151
+ * using `req.log` (set by `expressLogLayer`) and passes the error to the
152
+ * next error handler via `next(err)`.
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * import express from "express";
157
+ * import { expressLogLayer, expressLogLayerErrorHandler } from "@loglayer/express";
158
+ *
159
+ * const app = express();
160
+ * app.use(expressLogLayer({ instance: log }));
161
+ *
162
+ * // ... routes ...
163
+ *
164
+ * app.use(expressLogLayerErrorHandler());
165
+ * app.use((err, req, res, next) => {
166
+ * res.status(500).send("Internal Server Error");
167
+ * });
168
+ * ```
169
+ */
170
+ declare function expressLogLayerErrorHandler(config?: {
171
+ group?: ExpressLogLayerConfig["group"];
172
+ }): ErrorRequestHandler;
173
+ //#endregion
174
+ //#region src/index.d.ts
175
+ declare global {
176
+ namespace Express {
177
+ interface Request {
178
+ log: ILogLayer;
179
+ }
180
+ }
181
+ }
182
+ //#endregion
183
+ export { type ExpressAutoLoggingConfig, type ExpressGroupConfig, type ExpressLogLayerConfig, type ExpressRequestLoggingConfig, type ExpressResponseLoggingConfig, expressLogLayer, expressLogLayerErrorHandler };
184
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,184 @@
1
+ import { ILogLayer, LogLevelType } from "loglayer";
2
+ import { ErrorRequestHandler, NextFunction, Request, Response } from "express";
3
+
4
+ //#region src/types.d.ts
5
+ /**
6
+ * Configuration for request logging.
7
+ * Logs when a request is received, before the route handler runs.
8
+ */
9
+ interface ExpressRequestLoggingConfig {
10
+ /**
11
+ * The log level to use for request logs.
12
+ * @default "info"
13
+ */
14
+ logLevel?: LogLevelType;
15
+ }
16
+ /**
17
+ * Configuration for response logging.
18
+ * Logs after the route handler completes and the response is sent.
19
+ */
20
+ interface ExpressResponseLoggingConfig {
21
+ /**
22
+ * The log level to use for response logs.
23
+ * @default "info"
24
+ */
25
+ logLevel?: LogLevelType;
26
+ }
27
+ /**
28
+ * Configuration for the auto-logging feature.
29
+ */
30
+ interface ExpressAutoLoggingConfig {
31
+ /**
32
+ * The log level to use for both request and response logs (can be overridden individually).
33
+ * @default "info"
34
+ */
35
+ logLevel?: LogLevelType;
36
+ /**
37
+ * Array of path patterns to ignore from auto-logging.
38
+ * Supports exact string matches and RegExp.
39
+ * @example ["/health", /^\/internal\//]
40
+ */
41
+ ignore?: Array<string | RegExp>;
42
+ /**
43
+ * Controls request logging (fires when request is received).
44
+ * When enabled, logs: `"incoming request"` with metadata `{ req: { method, url, remoteAddress } }`.
45
+ * - `true`: enables request logging (default)
46
+ * - `false`: disables request logging
47
+ * - `object`: enables with custom configuration
48
+ * @default true
49
+ */
50
+ request?: boolean | ExpressRequestLoggingConfig;
51
+ /**
52
+ * Controls response logging (fires after response is sent).
53
+ * When enabled, logs: `"request completed"` with metadata `{ req: { method, url, remoteAddress }, res: { statusCode }, responseTime }`.
54
+ * - `true`: enables response logging (default)
55
+ * - `false`: disables response logging
56
+ * - `object`: enables with custom configuration
57
+ * @default true
58
+ */
59
+ response?: boolean | ExpressResponseLoggingConfig;
60
+ }
61
+ /**
62
+ * Group names for auto-logged messages.
63
+ */
64
+ interface ExpressGroupConfig {
65
+ /**
66
+ * Group name for internal auto-logs (errors, etc.).
67
+ * @default "express"
68
+ */
69
+ name?: string;
70
+ /**
71
+ * Group name for auto-logged incoming request messages.
72
+ * @default "express.request"
73
+ */
74
+ request?: string;
75
+ /**
76
+ * Group name for auto-logged response messages.
77
+ * @default "express.response"
78
+ */
79
+ response?: string;
80
+ }
81
+ /**
82
+ * Configuration for the Express LogLayer integration middleware.
83
+ */
84
+ interface ExpressLogLayerConfig {
85
+ /**
86
+ * The LogLayer instance to use for logging.
87
+ * A child logger will be created for each request.
88
+ */
89
+ instance: ILogLayer;
90
+ /**
91
+ * Controls request ID generation.
92
+ * - `true`: generates a request ID using `crypto.randomUUID()` (default)
93
+ * - `false`: disables request ID generation
94
+ * - `function`: custom function to generate a request ID from the request
95
+ * @default true
96
+ */
97
+ requestId?: boolean | ((request: Request) => string);
98
+ /**
99
+ * Controls automatic request/response logging.
100
+ * - `true`: enables auto-logging with defaults (default)
101
+ * - `false`: disables auto-logging
102
+ * - `object`: enables auto-logging with custom configuration
103
+ * @default true
104
+ */
105
+ autoLogging?: boolean | ExpressAutoLoggingConfig;
106
+ /**
107
+ * Optional function to extract additional context from the request.
108
+ * The returned object will be merged into the per-request logger's context.
109
+ */
110
+ contextFn?: (request: Request) => Record<string, any>;
111
+ /**
112
+ * Tags auto-logged request/response messages with groups for filtering/routing.
113
+ * - `true`: tag with default group names (`"express.request"`, `"express.response"`)
114
+ * - `object`: tag with custom group names
115
+ *
116
+ * Only affects auto-logged messages. User logs from route handlers are not tagged.
117
+ *
118
+ * @see {@link https://loglayer.dev/logging-api/groups.html | Groups Docs}
119
+ */
120
+ group?: boolean | ExpressGroupConfig;
121
+ }
122
+ //#endregion
123
+ //#region src/plugin.d.ts
124
+ /**
125
+ * Creates an Express middleware that integrates LogLayer for request-scoped logging.
126
+ *
127
+ * The middleware attaches a child LogLayer instance to `req.log` for each request.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * import express from "express";
132
+ * import { LogLayer, ConsoleTransport } from "loglayer";
133
+ * import { expressLogLayer } from "@loglayer/express";
134
+ *
135
+ * const log = new LogLayer({ transport: new ConsoleTransport() });
136
+ *
137
+ * const app = express();
138
+ * app.use(expressLogLayer({ instance: log }));
139
+ *
140
+ * app.get("/", (req, res) => {
141
+ * req.log.info("Hello from route!");
142
+ * res.send("Hello World!");
143
+ * });
144
+ * ```
145
+ */
146
+ declare function expressLogLayer(config: ExpressLogLayerConfig): (req: Request, res: Response, next: NextFunction) => void;
147
+ /**
148
+ * Creates an Express error-handling middleware that logs errors via LogLayer.
149
+ *
150
+ * This middleware should be registered after all routes. It logs the error
151
+ * using `req.log` (set by `expressLogLayer`) and passes the error to the
152
+ * next error handler via `next(err)`.
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * import express from "express";
157
+ * import { expressLogLayer, expressLogLayerErrorHandler } from "@loglayer/express";
158
+ *
159
+ * const app = express();
160
+ * app.use(expressLogLayer({ instance: log }));
161
+ *
162
+ * // ... routes ...
163
+ *
164
+ * app.use(expressLogLayerErrorHandler());
165
+ * app.use((err, req, res, next) => {
166
+ * res.status(500).send("Internal Server Error");
167
+ * });
168
+ * ```
169
+ */
170
+ declare function expressLogLayerErrorHandler(config?: {
171
+ group?: ExpressLogLayerConfig["group"];
172
+ }): ErrorRequestHandler;
173
+ //#endregion
174
+ //#region src/index.d.ts
175
+ declare global {
176
+ namespace Express {
177
+ interface Request {
178
+ log: ILogLayer;
179
+ }
180
+ }
181
+ }
182
+ //#endregion
183
+ export { type ExpressAutoLoggingConfig, type ExpressGroupConfig, type ExpressLogLayerConfig, type ExpressRequestLoggingConfig, type ExpressResponseLoggingConfig, expressLogLayer, expressLogLayerErrorHandler };
184
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ //#region src/plugin.ts
2
+ function resolveGroupConfig(group) {
3
+ if (!group) return {
4
+ nameGroup: void 0,
5
+ requestGroup: void 0,
6
+ responseGroup: void 0
7
+ };
8
+ if (group === true) return {
9
+ nameGroup: "express",
10
+ requestGroup: "express.request",
11
+ responseGroup: "express.response"
12
+ };
13
+ return {
14
+ nameGroup: group.name ?? "express",
15
+ requestGroup: group.request ?? "express.request",
16
+ responseGroup: group.response ?? "express.response"
17
+ };
18
+ }
19
+ function shouldIgnorePath(path, ignore) {
20
+ if (!ignore || ignore.length === 0) return false;
21
+ for (const pattern of ignore) if (typeof pattern === "string") {
22
+ if (path === pattern) return true;
23
+ } else if (pattern.test(path)) return true;
24
+ return false;
25
+ }
26
+ function getRequestId(request, requestIdConfig) {
27
+ if (requestIdConfig === false) return void 0;
28
+ if (typeof requestIdConfig === "function") return requestIdConfig(request);
29
+ return crypto.randomUUID();
30
+ }
31
+ function resolveLoggingConfig(value, defaultEnabled) {
32
+ if (value === void 0) return defaultEnabled ? {} : false;
33
+ if (value === true) return {};
34
+ if (value === false) return false;
35
+ return value;
36
+ }
37
+ /**
38
+ * Creates an Express middleware that integrates LogLayer for request-scoped logging.
39
+ *
40
+ * The middleware attaches a child LogLayer instance to `req.log` for each request.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import express from "express";
45
+ * import { LogLayer, ConsoleTransport } from "loglayer";
46
+ * import { expressLogLayer } from "@loglayer/express";
47
+ *
48
+ * const log = new LogLayer({ transport: new ConsoleTransport() });
49
+ *
50
+ * const app = express();
51
+ * app.use(expressLogLayer({ instance: log }));
52
+ *
53
+ * app.get("/", (req, res) => {
54
+ * req.log.info("Hello from route!");
55
+ * res.send("Hello World!");
56
+ * });
57
+ * ```
58
+ */
59
+ function expressLogLayer(config) {
60
+ const { instance, requestId: requestIdConfig = true, autoLogging: autoLoggingConfig = true, contextFn, group: groupConfig } = config;
61
+ const { requestGroup, responseGroup } = resolveGroupConfig(groupConfig);
62
+ const autoLogging = autoLoggingConfig === true ? {} : autoLoggingConfig === false ? false : autoLoggingConfig;
63
+ const requestConfig = autoLogging ? resolveLoggingConfig(autoLogging.request, true) : false;
64
+ const responseConfig = autoLogging ? resolveLoggingConfig(autoLogging.response, true) : false;
65
+ const defaultLogLevel = autoLogging ? autoLogging.logLevel ?? "info" : "info";
66
+ const requestLogLevel = requestConfig ? requestConfig.logLevel ?? defaultLogLevel : defaultLogLevel;
67
+ const responseLogLevel = responseConfig ? responseConfig.logLevel ?? defaultLogLevel : defaultLogLevel;
68
+ return (req, res, next) => {
69
+ const context = {};
70
+ const reqId = getRequestId(req, requestIdConfig);
71
+ if (reqId) context.requestId = reqId;
72
+ if (contextFn) {
73
+ const additionalContext = contextFn(req);
74
+ if (additionalContext) Object.assign(context, additionalContext);
75
+ }
76
+ const childLogger = instance.child().withContext(context);
77
+ req.log = childLogger;
78
+ const startTime = Date.now();
79
+ const ignorePath = autoLogging ? shouldIgnorePath(req.path, autoLogging.ignore) : true;
80
+ if (requestConfig && !ignorePath) {
81
+ let builder = childLogger.withMetadata({ req: {
82
+ method: req.method,
83
+ url: req.originalUrl || req.url,
84
+ remoteAddress: req.ip
85
+ } });
86
+ if (requestGroup) builder = builder.withGroup(requestGroup);
87
+ builder[requestLogLevel]("incoming request");
88
+ }
89
+ if (responseConfig && !ignorePath) {
90
+ const onResponseComplete = () => {
91
+ res.removeListener("close", onResponseComplete);
92
+ res.removeListener("finish", onResponseComplete);
93
+ res.removeListener("error", onResponseComplete);
94
+ const responseTime = Date.now() - startTime;
95
+ let builder = childLogger.withMetadata({
96
+ req: {
97
+ method: req.method,
98
+ url: req.originalUrl || req.url,
99
+ remoteAddress: req.ip
100
+ },
101
+ res: { statusCode: res.statusCode },
102
+ responseTime
103
+ });
104
+ if (responseGroup) builder = builder.withGroup(responseGroup);
105
+ builder[responseLogLevel]("request completed");
106
+ };
107
+ res.on("close", onResponseComplete);
108
+ res.on("finish", onResponseComplete);
109
+ res.on("error", onResponseComplete);
110
+ }
111
+ next();
112
+ };
113
+ }
114
+ /**
115
+ * Creates an Express error-handling middleware that logs errors via LogLayer.
116
+ *
117
+ * This middleware should be registered after all routes. It logs the error
118
+ * using `req.log` (set by `expressLogLayer`) and passes the error to the
119
+ * next error handler via `next(err)`.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * import express from "express";
124
+ * import { expressLogLayer, expressLogLayerErrorHandler } from "@loglayer/express";
125
+ *
126
+ * const app = express();
127
+ * app.use(expressLogLayer({ instance: log }));
128
+ *
129
+ * // ... routes ...
130
+ *
131
+ * app.use(expressLogLayerErrorHandler());
132
+ * app.use((err, req, res, next) => {
133
+ * res.status(500).send("Internal Server Error");
134
+ * });
135
+ * ```
136
+ */
137
+ function expressLogLayerErrorHandler(config) {
138
+ const { nameGroup } = resolveGroupConfig(config?.group);
139
+ return (err, req, _res, next) => {
140
+ if (req.log) {
141
+ let builder = req.log.withError(err).withMetadata({ url: req.originalUrl || req.url });
142
+ if (nameGroup) builder = builder.withGroup(nameGroup);
143
+ builder.error("Request error");
144
+ }
145
+ next(err);
146
+ };
147
+ }
148
+
149
+ //#endregion
150
+ export { expressLogLayer, expressLogLayerErrorHandler };
151
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type { ErrorRequestHandler, NextFunction, Request, Response } from \"express\";\nimport type { ILogLayer } from \"loglayer\";\nimport type {\n ExpressAutoLoggingConfig,\n ExpressLogLayerConfig,\n ExpressRequestLoggingConfig,\n ExpressResponseLoggingConfig,\n} from \"./types.js\";\n\nfunction resolveGroupConfig(group: ExpressLogLayerConfig[\"group\"]) {\n if (!group) return { nameGroup: undefined, requestGroup: undefined, responseGroup: undefined };\n if (group === true)\n return { nameGroup: \"express\", requestGroup: \"express.request\", responseGroup: \"express.response\" };\n return {\n nameGroup: group.name ?? \"express\",\n requestGroup: group.request ?? \"express.request\",\n responseGroup: group.response ?? \"express.response\",\n };\n}\n\nfunction shouldIgnorePath(path: string, ignore?: Array<string | RegExp>): boolean {\n if (!ignore || ignore.length === 0) return false;\n\n for (const pattern of ignore) {\n if (typeof pattern === \"string\") {\n if (path === pattern) return true;\n } else if (pattern.test(path)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction getRequestId(request: Request, requestIdConfig: ExpressLogLayerConfig[\"requestId\"]): string | undefined {\n if (requestIdConfig === false) return undefined;\n if (typeof requestIdConfig === \"function\") return requestIdConfig(request);\n return crypto.randomUUID();\n}\n\nfunction resolveLoggingConfig<T>(value: boolean | T | undefined, defaultEnabled: boolean): T | false {\n if (value === undefined) return defaultEnabled ? ({} as T) : false;\n if (value === true) return {} as T;\n if (value === false) return false;\n return value;\n}\n\n/**\n * Creates an Express middleware that integrates LogLayer for request-scoped logging.\n *\n * The middleware attaches a child LogLayer instance to `req.log` for each request.\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { LogLayer, ConsoleTransport } from \"loglayer\";\n * import { expressLogLayer } from \"@loglayer/express\";\n *\n * const log = new LogLayer({ transport: new ConsoleTransport() });\n *\n * const app = express();\n * app.use(expressLogLayer({ instance: log }));\n *\n * app.get(\"/\", (req, res) => {\n * req.log.info(\"Hello from route!\");\n * res.send(\"Hello World!\");\n * });\n * ```\n */\nexport function expressLogLayer(config: ExpressLogLayerConfig) {\n const {\n instance,\n requestId: requestIdConfig = true,\n autoLogging: autoLoggingConfig = true,\n contextFn,\n group: groupConfig,\n } = config;\n const { requestGroup, responseGroup } = resolveGroupConfig(groupConfig);\n\n const autoLogging: ExpressAutoLoggingConfig | false =\n autoLoggingConfig === true ? {} : autoLoggingConfig === false ? false : autoLoggingConfig;\n\n // Resolve auto-logging configs once\n const requestConfig = autoLogging\n ? resolveLoggingConfig<ExpressRequestLoggingConfig>(autoLogging.request, true)\n : false;\n const responseConfig = autoLogging\n ? resolveLoggingConfig<ExpressResponseLoggingConfig>(autoLogging.response, true)\n : false;\n\n const defaultLogLevel = autoLogging ? (autoLogging.logLevel ?? \"info\") : \"info\";\n const requestLogLevel = requestConfig ? (requestConfig.logLevel ?? defaultLogLevel) : defaultLogLevel;\n const responseLogLevel = responseConfig ? (responseConfig.logLevel ?? defaultLogLevel) : defaultLogLevel;\n\n return (req: Request, res: Response, next: NextFunction) => {\n const context: Record<string, any> = {};\n\n const reqId = getRequestId(req, requestIdConfig);\n if (reqId) {\n context.requestId = reqId;\n }\n\n if (contextFn) {\n const additionalContext = contextFn(req);\n if (additionalContext) {\n Object.assign(context, additionalContext);\n }\n }\n\n // Create child logger and attach to req.log\n const childLogger = instance.child().withContext(context) as ILogLayer;\n (req as any).log = childLogger;\n\n const startTime = Date.now();\n const ignorePath = autoLogging ? shouldIgnorePath(req.path, autoLogging.ignore) : true;\n\n // Log incoming request\n if (requestConfig && !ignorePath) {\n let builder = childLogger.withMetadata({\n req: {\n method: req.method,\n url: req.originalUrl || req.url,\n remoteAddress: req.ip,\n },\n });\n if (requestGroup) builder = builder.withGroup(requestGroup);\n builder[requestLogLevel](\"incoming request\");\n }\n\n // Log response on completion (listen on close, finish, and error for reliability)\n if (responseConfig && !ignorePath) {\n const onResponseComplete = () => {\n res.removeListener(\"close\", onResponseComplete);\n res.removeListener(\"finish\", onResponseComplete);\n res.removeListener(\"error\", onResponseComplete);\n\n const responseTime = Date.now() - startTime;\n let builder = childLogger.withMetadata({\n req: {\n method: req.method,\n url: req.originalUrl || req.url,\n remoteAddress: req.ip,\n },\n res: {\n statusCode: res.statusCode,\n },\n responseTime,\n });\n if (responseGroup) builder = builder.withGroup(responseGroup);\n builder[responseLogLevel](\"request completed\");\n };\n\n res.on(\"close\", onResponseComplete);\n res.on(\"finish\", onResponseComplete);\n res.on(\"error\", onResponseComplete);\n }\n\n next();\n };\n}\n\n/**\n * Creates an Express error-handling middleware that logs errors via LogLayer.\n *\n * This middleware should be registered after all routes. It logs the error\n * using `req.log` (set by `expressLogLayer`) and passes the error to the\n * next error handler via `next(err)`.\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { expressLogLayer, expressLogLayerErrorHandler } from \"@loglayer/express\";\n *\n * const app = express();\n * app.use(expressLogLayer({ instance: log }));\n *\n * // ... routes ...\n *\n * app.use(expressLogLayerErrorHandler());\n * app.use((err, req, res, next) => {\n * res.status(500).send(\"Internal Server Error\");\n * });\n * ```\n */\nexport function expressLogLayerErrorHandler(config?: { group?: ExpressLogLayerConfig[\"group\"] }): ErrorRequestHandler {\n const { nameGroup } = resolveGroupConfig(config?.group);\n\n return (err: Error, req: Request, _res: Response, next: NextFunction) => {\n if ((req as any).log) {\n let builder = ((req as any).log as ILogLayer).withError(err).withMetadata({ url: req.originalUrl || req.url });\n if (nameGroup) builder = builder.withGroup(nameGroup);\n builder.error(\"Request error\");\n }\n next(err);\n };\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@loglayer/express",
3
+ "description": "Express integration for LogLayer with request-scoped logging, auto request logging, and error handling.",
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "exports": {
9
+ "import": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "types": "./dist/index.d.ts",
19
+ "sideEffects": false,
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/loglayer/loglayer.git",
24
+ "directory": "packages/integrations/express"
25
+ },
26
+ "author": "Theo Gravity <theo@suteki.nu>",
27
+ "keywords": [
28
+ "logging",
29
+ "log",
30
+ "loglayer",
31
+ "express",
32
+ "integration",
33
+ "middleware"
34
+ ],
35
+ "devDependencies": {
36
+ "@types/express": "5.0.6",
37
+ "@types/node": "25.2.3",
38
+ "@types/supertest": "6.0.3",
39
+ "express": "5.2.1",
40
+ "serialize-error": "13.0.1",
41
+ "supertest": "7.2.2",
42
+ "tsdown": "0.20.3",
43
+ "tsx": "4.21.0",
44
+ "typescript": "5.9.3",
45
+ "vitest": "4.0.18",
46
+ "@internal/tsconfig": "2.1.0",
47
+ "@loglayer/transport-simple-pretty-terminal": "3.0.2",
48
+ "loglayer": "9.1.0"
49
+ },
50
+ "peerDependencies": {
51
+ "express": ">=4.0.0",
52
+ "loglayer": "*"
53
+ },
54
+ "bugs": "https://github.com/loglayer/loglayer/issues",
55
+ "engines": {
56
+ "node": ">=20"
57
+ },
58
+ "files": [
59
+ "dist"
60
+ ],
61
+ "homepage": "https://loglayer.dev",
62
+ "scripts": {
63
+ "build": "tsdown src/index.ts",
64
+ "test": "vitest --run",
65
+ "livetest": "tsx src/__tests__/livetest.ts",
66
+ "clean": "rm -rf .turbo node_modules dist",
67
+ "lint": "biome check --no-errors-on-unmatched --write --unsafe src",
68
+ "lint:staged": "biome check --no-errors-on-unmatched --write --unsafe --staged src",
69
+ "verify-types": "tsc --noEmit"
70
+ }
71
+ }