hierarchical-area-logger 0.2.0 → 0.2.1
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/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Logger.ts +3 -1
- package/src/index.ts +1 -1
- package/src/types.ts +1 -0
- package/test/logger.test.ts +0 -136
- package/test/utils.test.ts +0 -453
package/dist/index.cjs
CHANGED
|
@@ -84,6 +84,7 @@ var Logger = class {
|
|
|
84
84
|
constructor(options) {
|
|
85
85
|
this.parentEventId = options.parentEventId;
|
|
86
86
|
this.eventId = (0, import_cuid2.init)({ fingerprint: options.details.service })();
|
|
87
|
+
this.defaultArea = options.defaultArea || "unnamed";
|
|
87
88
|
this.log = createRootLogEntry({
|
|
88
89
|
path: options.path || "/",
|
|
89
90
|
method: options.method,
|
|
@@ -94,7 +95,7 @@ var Logger = class {
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
// Area function that returns area-specific logger methods
|
|
97
|
-
getArea(name =
|
|
98
|
+
getArea(name = this.defaultArea) {
|
|
98
99
|
if (!this.log[name]) {
|
|
99
100
|
this.log[name] = [];
|
|
100
101
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Logger.ts","../src/utils.ts"],"sourcesContent":["export { Logger, createLogger } from './Logger';\nexport { LogData, LogEntry } from './types';\n","import { init } from '@paralleldrive/cuid2';\nimport { createRootLogEntry, prettyError } from './utils';\nimport { LogData, LoggerOptions, LogEntry } from './types';\n\nexport class Logger {\n public eventId: string;\n private log: LogData;\n public parentEventId?: string;\n\n constructor(options: LoggerOptions) {\n this.parentEventId = options.parentEventId;\n this.eventId = init({ fingerprint: options.details.service })();\n\n this.log = createRootLogEntry({\n path: options.path || '/',\n method: options.method,\n details: options.details,\n eventId: this.eventId,\n parentEventId: options.parentEventId,\n withParentEventId: options.withParentEventId,\n });\n }\n\n // Area function that returns area-specific logger methods\n public getArea(name =
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Logger.ts","../src/utils.ts"],"sourcesContent":["export { Logger, createLogger } from './Logger';\nexport { LogData, LogEntry, Details, RootPayload } from './types';\n","import { init } from '@paralleldrive/cuid2';\nimport { createRootLogEntry, prettyError } from './utils';\nimport { LogData, LoggerOptions, LogEntry } from './types';\n\nexport class Logger {\n public eventId: string;\n private log: LogData;\n public parentEventId?: string;\n private defaultArea: string;\n\n constructor(options: LoggerOptions) {\n this.parentEventId = options.parentEventId;\n this.eventId = init({ fingerprint: options.details.service })();\n this.defaultArea = options.defaultArea || 'unnamed';\n\n this.log = createRootLogEntry({\n path: options.path || '/',\n method: options.method,\n details: options.details,\n eventId: this.eventId,\n parentEventId: options.parentEventId,\n withParentEventId: options.withParentEventId,\n });\n }\n\n // Area function that returns area-specific logger methods\n public getArea(name = this.defaultArea) {\n if (!this.log[name]) {\n this.log[name] = [];\n }\n\n return {\n info: (message: string, payload?: LogEntry['payload']) => {\n this.log[name]!.push({\n type: 'info',\n message,\n payload,\n timestamp: Date.now(),\n });\n },\n warn: (message: string, payload?: LogEntry['payload']) => {\n this.log[name]!.push({\n type: 'warn',\n message,\n payload,\n timestamp: Date.now(),\n });\n },\n error: (message: string, payload?: LogEntry['payload'] | Error) => {\n this.log[name]!.push({\n type: 'error',\n message,\n payload: payload instanceof Error ? prettyError(payload) : payload,\n timestamp: Date.now(),\n });\n },\n };\n }\n\n // Public methods on main instance\n public dump(): LogData {\n return this.log;\n }\n\n public appendLogData(logData: LogData): void {\n delete logData.root;\n this.log = { ...logData, ...this.log };\n }\n}\n\n// Factory function for convenience\nexport const createLogger = (options: LoggerOptions): Logger => {\n return new Logger(options);\n};\n","import { CreateRootLogEntryOptions, LogData, RootPayload } from './types';\n\nexport const prettyStack = (stack?: string): string[] => {\n if (!stack) return [];\n let toReplace = '';\n\n const regex = /file:\\/\\/\\/(.*)(\\.wrangler|node_modules)\\/.*\\)/gm;\n const m = regex.exec(stack);\n\n if (m && m.length > 1) {\n toReplace = m[1];\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => !line.startsWith('Error: '))\n .map((line) => line.replace(toReplace, ''))\n .map((line) => line.replace('file://', ''));\n};\n\nexport const prettyError = (err: Error) => {\n const stack = prettyStack(err.stack);\n const message = err.message;\n return { message, stack };\n};\n\nexport const createRootLogEntry = ({\n path,\n method,\n details,\n eventId,\n parentEventId,\n withParentEventId,\n}: CreateRootLogEntryOptions): LogData => {\n const url = new URL(`http://example.com${path ?? '/'}`);\n\n const rootLogEntry: LogData = {\n root: [\n {\n type: 'info',\n message: 'Request received',\n payload: {\n path: `${url.pathname}${url.search}`,\n method,\n details,\n eventId,\n ...(parentEventId && { parentEventId }),\n } as RootPayload,\n timestamp: Date.now(),\n },\n ],\n };\n\n if (withParentEventId && !parentEventId) {\n rootLogEntry.root.push({\n type: 'error',\n message: 'Parent event ID expected but not found',\n timestamp: Date.now(),\n });\n }\n\n return rootLogEntry;\n};\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -8,6 +8,13 @@ type LogEntry = {
|
|
|
8
8
|
payload?: object;
|
|
9
9
|
timestamp: number;
|
|
10
10
|
};
|
|
11
|
+
type RootPayload = {
|
|
12
|
+
path?: string;
|
|
13
|
+
method?: Method;
|
|
14
|
+
eventId: string;
|
|
15
|
+
parentEventId?: string;
|
|
16
|
+
details: Details;
|
|
17
|
+
};
|
|
11
18
|
type LogData = Record<string, LogEntry[]>;
|
|
12
19
|
interface LoggerOptions {
|
|
13
20
|
details: Details;
|
|
@@ -15,12 +22,14 @@ interface LoggerOptions {
|
|
|
15
22
|
parentEventId?: string;
|
|
16
23
|
withParentEventId?: boolean;
|
|
17
24
|
method?: Method;
|
|
25
|
+
defaultArea?: string;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
declare class Logger {
|
|
21
29
|
eventId: string;
|
|
22
30
|
private log;
|
|
23
31
|
parentEventId?: string;
|
|
32
|
+
private defaultArea;
|
|
24
33
|
constructor(options: LoggerOptions);
|
|
25
34
|
getArea(name?: string): {
|
|
26
35
|
info: (message: string, payload?: LogEntry["payload"]) => void;
|
|
@@ -32,4 +41,4 @@ declare class Logger {
|
|
|
32
41
|
}
|
|
33
42
|
declare const createLogger: (options: LoggerOptions) => Logger;
|
|
34
43
|
|
|
35
|
-
export { type LogData, type LogEntry, Logger, createLogger };
|
|
44
|
+
export { type Details, type LogData, type LogEntry, Logger, type RootPayload, createLogger };
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ type LogEntry = {
|
|
|
8
8
|
payload?: object;
|
|
9
9
|
timestamp: number;
|
|
10
10
|
};
|
|
11
|
+
type RootPayload = {
|
|
12
|
+
path?: string;
|
|
13
|
+
method?: Method;
|
|
14
|
+
eventId: string;
|
|
15
|
+
parentEventId?: string;
|
|
16
|
+
details: Details;
|
|
17
|
+
};
|
|
11
18
|
type LogData = Record<string, LogEntry[]>;
|
|
12
19
|
interface LoggerOptions {
|
|
13
20
|
details: Details;
|
|
@@ -15,12 +22,14 @@ interface LoggerOptions {
|
|
|
15
22
|
parentEventId?: string;
|
|
16
23
|
withParentEventId?: boolean;
|
|
17
24
|
method?: Method;
|
|
25
|
+
defaultArea?: string;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
declare class Logger {
|
|
21
29
|
eventId: string;
|
|
22
30
|
private log;
|
|
23
31
|
parentEventId?: string;
|
|
32
|
+
private defaultArea;
|
|
24
33
|
constructor(options: LoggerOptions);
|
|
25
34
|
getArea(name?: string): {
|
|
26
35
|
info: (message: string, payload?: LogEntry["payload"]) => void;
|
|
@@ -32,4 +41,4 @@ declare class Logger {
|
|
|
32
41
|
}
|
|
33
42
|
declare const createLogger: (options: LoggerOptions) => Logger;
|
|
34
43
|
|
|
35
|
-
export { type LogData, type LogEntry, Logger, createLogger };
|
|
44
|
+
export { type Details, type LogData, type LogEntry, Logger, type RootPayload, createLogger };
|
package/dist/index.js
CHANGED
|
@@ -57,6 +57,7 @@ var Logger = class {
|
|
|
57
57
|
constructor(options) {
|
|
58
58
|
this.parentEventId = options.parentEventId;
|
|
59
59
|
this.eventId = init({ fingerprint: options.details.service })();
|
|
60
|
+
this.defaultArea = options.defaultArea || "unnamed";
|
|
60
61
|
this.log = createRootLogEntry({
|
|
61
62
|
path: options.path || "/",
|
|
62
63
|
method: options.method,
|
|
@@ -67,7 +68,7 @@ var Logger = class {
|
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
70
|
// Area function that returns area-specific logger methods
|
|
70
|
-
getArea(name =
|
|
71
|
+
getArea(name = this.defaultArea) {
|
|
71
72
|
if (!this.log[name]) {
|
|
72
73
|
this.log[name] = [];
|
|
73
74
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Logger.ts","../src/utils.ts"],"sourcesContent":["import { init } from '@paralleldrive/cuid2';\nimport { createRootLogEntry, prettyError } from './utils';\nimport { LogData, LoggerOptions, LogEntry } from './types';\n\nexport class Logger {\n public eventId: string;\n private log: LogData;\n public parentEventId?: string;\n\n constructor(options: LoggerOptions) {\n this.parentEventId = options.parentEventId;\n this.eventId = init({ fingerprint: options.details.service })();\n\n this.log = createRootLogEntry({\n path: options.path || '/',\n method: options.method,\n details: options.details,\n eventId: this.eventId,\n parentEventId: options.parentEventId,\n withParentEventId: options.withParentEventId,\n });\n }\n\n // Area function that returns area-specific logger methods\n public getArea(name =
|
|
1
|
+
{"version":3,"sources":["../src/Logger.ts","../src/utils.ts"],"sourcesContent":["import { init } from '@paralleldrive/cuid2';\nimport { createRootLogEntry, prettyError } from './utils';\nimport { LogData, LoggerOptions, LogEntry } from './types';\n\nexport class Logger {\n public eventId: string;\n private log: LogData;\n public parentEventId?: string;\n private defaultArea: string;\n\n constructor(options: LoggerOptions) {\n this.parentEventId = options.parentEventId;\n this.eventId = init({ fingerprint: options.details.service })();\n this.defaultArea = options.defaultArea || 'unnamed';\n\n this.log = createRootLogEntry({\n path: options.path || '/',\n method: options.method,\n details: options.details,\n eventId: this.eventId,\n parentEventId: options.parentEventId,\n withParentEventId: options.withParentEventId,\n });\n }\n\n // Area function that returns area-specific logger methods\n public getArea(name = this.defaultArea) {\n if (!this.log[name]) {\n this.log[name] = [];\n }\n\n return {\n info: (message: string, payload?: LogEntry['payload']) => {\n this.log[name]!.push({\n type: 'info',\n message,\n payload,\n timestamp: Date.now(),\n });\n },\n warn: (message: string, payload?: LogEntry['payload']) => {\n this.log[name]!.push({\n type: 'warn',\n message,\n payload,\n timestamp: Date.now(),\n });\n },\n error: (message: string, payload?: LogEntry['payload'] | Error) => {\n this.log[name]!.push({\n type: 'error',\n message,\n payload: payload instanceof Error ? prettyError(payload) : payload,\n timestamp: Date.now(),\n });\n },\n };\n }\n\n // Public methods on main instance\n public dump(): LogData {\n return this.log;\n }\n\n public appendLogData(logData: LogData): void {\n delete logData.root;\n this.log = { ...logData, ...this.log };\n }\n}\n\n// Factory function for convenience\nexport const createLogger = (options: LoggerOptions): Logger => {\n return new Logger(options);\n};\n","import { CreateRootLogEntryOptions, LogData, RootPayload } from './types';\n\nexport const prettyStack = (stack?: string): string[] => {\n if (!stack) return [];\n let toReplace = '';\n\n const regex = /file:\\/\\/\\/(.*)(\\.wrangler|node_modules)\\/.*\\)/gm;\n const m = regex.exec(stack);\n\n if (m && m.length > 1) {\n toReplace = m[1];\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => !line.startsWith('Error: '))\n .map((line) => line.replace(toReplace, ''))\n .map((line) => line.replace('file://', ''));\n};\n\nexport const prettyError = (err: Error) => {\n const stack = prettyStack(err.stack);\n const message = err.message;\n return { message, stack };\n};\n\nexport const createRootLogEntry = ({\n path,\n method,\n details,\n eventId,\n parentEventId,\n withParentEventId,\n}: CreateRootLogEntryOptions): LogData => {\n const url = new URL(`http://example.com${path ?? '/'}`);\n\n const rootLogEntry: LogData = {\n root: [\n {\n type: 'info',\n message: 'Request received',\n payload: {\n path: `${url.pathname}${url.search}`,\n method,\n details,\n eventId,\n ...(parentEventId && { parentEventId }),\n } as RootPayload,\n timestamp: Date.now(),\n },\n ],\n };\n\n if (withParentEventId && !parentEventId) {\n rootLogEntry.root.push({\n type: 'error',\n message: 'Parent event ID expected but not found',\n timestamp: Date.now(),\n });\n }\n\n return rootLogEntry;\n};\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/Logger.ts
CHANGED
|
@@ -6,10 +6,12 @@ export class Logger {
|
|
|
6
6
|
public eventId: string;
|
|
7
7
|
private log: LogData;
|
|
8
8
|
public parentEventId?: string;
|
|
9
|
+
private defaultArea: string;
|
|
9
10
|
|
|
10
11
|
constructor(options: LoggerOptions) {
|
|
11
12
|
this.parentEventId = options.parentEventId;
|
|
12
13
|
this.eventId = init({ fingerprint: options.details.service })();
|
|
14
|
+
this.defaultArea = options.defaultArea || 'unnamed';
|
|
13
15
|
|
|
14
16
|
this.log = createRootLogEntry({
|
|
15
17
|
path: options.path || '/',
|
|
@@ -22,7 +24,7 @@ export class Logger {
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
// Area function that returns area-specific logger methods
|
|
25
|
-
public getArea(name =
|
|
27
|
+
public getArea(name = this.defaultArea) {
|
|
26
28
|
if (!this.log[name]) {
|
|
27
29
|
this.log[name] = [];
|
|
28
30
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Logger, createLogger } from './Logger';
|
|
2
|
-
export { LogData, LogEntry } from './types';
|
|
2
|
+
export { LogData, LogEntry, Details, RootPayload } from './types';
|
package/src/types.ts
CHANGED
package/test/logger.test.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { createLogger, Logger } from '../src/Logger';
|
|
3
|
-
import { Details } from '../src/types';
|
|
4
|
-
|
|
5
|
-
describe('Logger', () => {
|
|
6
|
-
const mockdetails: Details = { service: 'test-service' };
|
|
7
|
-
|
|
8
|
-
it('should create a logger with details', () => {
|
|
9
|
-
const logger = createLogger({ details: mockdetails });
|
|
10
|
-
expect(logger).toBeInstanceOf(Logger);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should create a logger with custom options', () => {
|
|
14
|
-
const logger = createLogger({
|
|
15
|
-
details: mockdetails,
|
|
16
|
-
path: 'test-path',
|
|
17
|
-
parentEventId: 'parent-123',
|
|
18
|
-
});
|
|
19
|
-
expect(logger).toBeInstanceOf(Logger);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should create area logger and log messages', () => {
|
|
23
|
-
const logger = createLogger({ details: mockdetails });
|
|
24
|
-
const areaLogger = logger.getArea('test-area');
|
|
25
|
-
|
|
26
|
-
areaLogger.info('test info message');
|
|
27
|
-
areaLogger.warn('test warn message');
|
|
28
|
-
areaLogger.error('test error message');
|
|
29
|
-
|
|
30
|
-
const logs = logger.dump();
|
|
31
|
-
expect(logs['test-area']).toHaveLength(3);
|
|
32
|
-
expect(logs['test-area'][0].message).toBe('test info message');
|
|
33
|
-
expect(logs['test-area'][1].type).toBe('warn');
|
|
34
|
-
expect(logs['test-area'][2].type).toBe('error');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should generate event IDs correctly', () => {
|
|
38
|
-
const logger = createLogger({ details: mockdetails });
|
|
39
|
-
|
|
40
|
-
expect(logger.eventId).toBeDefined();
|
|
41
|
-
expect(typeof logger.eventId).toBe('string');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should handle parent event ID', () => {
|
|
45
|
-
const logger = createLogger({
|
|
46
|
-
details: mockdetails,
|
|
47
|
-
parentEventId: 'parent-123',
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
expect(logger.parentEventId).toBe('parent-123');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should append log data', () => {
|
|
54
|
-
const logger = createLogger({ details: mockdetails });
|
|
55
|
-
const logDataToAdd = {
|
|
56
|
-
area1: [
|
|
57
|
-
{
|
|
58
|
-
type: 'info' as const,
|
|
59
|
-
message: 'existing log',
|
|
60
|
-
timestamp: Date.now(),
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
logger.appendLogData(logDataToAdd);
|
|
66
|
-
const logs = logger.dump();
|
|
67
|
-
|
|
68
|
-
expect(logs.area1).toBeDefined();
|
|
69
|
-
expect(logs.area1[0].message).toBe('existing log');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should create root log entry', () => {
|
|
73
|
-
const logger = createLogger({ details: mockdetails, path: 'test' });
|
|
74
|
-
const logs = logger.dump();
|
|
75
|
-
|
|
76
|
-
expect(logs.root).toBeDefined();
|
|
77
|
-
expect(logs.root).toHaveLength(1);
|
|
78
|
-
expect(logs.root[0].message).toBe('Request received');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should handle errors in error logging', () => {
|
|
82
|
-
const logger = createLogger({ details: mockdetails });
|
|
83
|
-
const areaLogger = logger.getArea('test-area');
|
|
84
|
-
|
|
85
|
-
const testError = new Error('Test error');
|
|
86
|
-
areaLogger.error('error occurred', testError);
|
|
87
|
-
|
|
88
|
-
const logs = logger.dump();
|
|
89
|
-
expect(logs['test-area'][0].payload).toHaveProperty(
|
|
90
|
-
'message',
|
|
91
|
-
'Test error'
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should use default area name when no name provided', () => {
|
|
96
|
-
const logger = createLogger({ details: mockdetails });
|
|
97
|
-
const areaLogger = logger.getArea();
|
|
98
|
-
|
|
99
|
-
areaLogger.info('test message');
|
|
100
|
-
|
|
101
|
-
const logs = logger.dump();
|
|
102
|
-
expect(logs.dummy).toBeDefined();
|
|
103
|
-
expect(logs.dummy).toHaveLength(1);
|
|
104
|
-
expect(logs.dummy[0].message).toBe('test message');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should handle withParentEventId true without parentEventId', () => {
|
|
108
|
-
const logger = createLogger({
|
|
109
|
-
details: mockdetails,
|
|
110
|
-
withParentEventId: true,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const logs = logger.dump();
|
|
114
|
-
expect(logs.root).toHaveLength(2);
|
|
115
|
-
expect(logs.root[1].type).toBe('error');
|
|
116
|
-
expect(logs.root[1].message).toBe('Parent event ID expected but not found');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('createLogger', () => {
|
|
121
|
-
const mockdetails: Details = { service: 'test-service' };
|
|
122
|
-
|
|
123
|
-
it('should create a logger instance', () => {
|
|
124
|
-
const logger = createLogger({ details: mockdetails });
|
|
125
|
-
expect(logger).toBeInstanceOf(Logger);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should create a logger with options', () => {
|
|
129
|
-
const logger = createLogger({
|
|
130
|
-
details: mockdetails,
|
|
131
|
-
path: 'test-path',
|
|
132
|
-
parentEventId: 'parent-123',
|
|
133
|
-
});
|
|
134
|
-
expect(logger).toBeInstanceOf(Logger);
|
|
135
|
-
});
|
|
136
|
-
});
|
package/test/utils.test.ts
DELETED
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { prettyStack, prettyError, createRootLogEntry } from '../src/utils';
|
|
3
|
-
import { Details, Method, RootPayload } from '../src/types';
|
|
4
|
-
|
|
5
|
-
describe('prettyStack', () => {
|
|
6
|
-
it('should return empty array for undefined input', () => {
|
|
7
|
-
const result = prettyStack(undefined);
|
|
8
|
-
expect(result).toEqual([]);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should return empty array for null input', () => {
|
|
12
|
-
const result = prettyStack(null as unknown as string);
|
|
13
|
-
expect(result).toEqual([]);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should return empty array for empty string input', () => {
|
|
17
|
-
const result = prettyStack('');
|
|
18
|
-
expect(result).toEqual([]);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should filter out lines starting with "Error: "', () => {
|
|
22
|
-
const stack = `Error: Test error
|
|
23
|
-
at Object.test (/path/to/file.js:1:1)
|
|
24
|
-
at Object.test2 (/path/to/file.js:2:2)`;
|
|
25
|
-
|
|
26
|
-
const result = prettyStack(stack);
|
|
27
|
-
expect(result.join('\n')).not.toContain('Error: Test error');
|
|
28
|
-
expect(result).toContain('at Object.test (/path/to/file.js:1:1)');
|
|
29
|
-
expect(result).toContain('at Object.test2 (/path/to/file.js:2:2)');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should trim whitespace from each line', () => {
|
|
33
|
-
const stack = ` at Object.test (/path/to/file.js:1:1)
|
|
34
|
-
at Object.test2 (/path/to/file.js:2:2)`;
|
|
35
|
-
|
|
36
|
-
const result = prettyStack(stack);
|
|
37
|
-
expect(result).toContain('at Object.test (/path/to/file.js:1:1)');
|
|
38
|
-
expect(result).toContain('at Object.test2 (/path/to/file.js:2:2)');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should remove file:// prefix from lines', () => {
|
|
42
|
-
const stack = `at Object.test (file:///path/to/file.js:1:1)
|
|
43
|
-
at Object.test2 (file:///another/path.js:2:2)`;
|
|
44
|
-
|
|
45
|
-
const result = prettyStack(stack);
|
|
46
|
-
|
|
47
|
-
expect(result).toEqual(
|
|
48
|
-
expect.arrayContaining([
|
|
49
|
-
'at Object.test (/path/to/file.js:1:1)',
|
|
50
|
-
'at Object.test2 (/another/path.js:2:2)',
|
|
51
|
-
])
|
|
52
|
-
);
|
|
53
|
-
expect(result.join('\n')).not.toContain('file://');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should replace .wrangler paths in stack traces', () => {
|
|
57
|
-
const stack = `at Object.test (file:///some/path/.wrangler/test/file.js:1:1)
|
|
58
|
-
at Object.test2 (file:///another/path/file.js:2:2)`;
|
|
59
|
-
|
|
60
|
-
const result = prettyStack(stack);
|
|
61
|
-
// Based on actual behavior, it keeps the .wrangler prefix
|
|
62
|
-
expect(result).toEqual(
|
|
63
|
-
expect.arrayContaining([
|
|
64
|
-
'at Object.test (/.wrangler/test/file.js:1:1)',
|
|
65
|
-
'at Object.test2 (/another/path/file.js:2:2)',
|
|
66
|
-
])
|
|
67
|
-
);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should replace node_modules paths in stack traces', () => {
|
|
71
|
-
const stack = `at Object.test (file:///some/path/node_modules/module/file.js:1:1)
|
|
72
|
-
at Object.test2 (file:///another/path/file.js:2:2)`;
|
|
73
|
-
|
|
74
|
-
const result = prettyStack(stack);
|
|
75
|
-
// Based on actual behavior, it keeps the /node_modules prefix
|
|
76
|
-
expect(result).toEqual(
|
|
77
|
-
expect.arrayContaining([
|
|
78
|
-
'at Object.test (/node_modules/module/file.js:1:1)',
|
|
79
|
-
'at Object.test2 (/another/path/file.js:2:2)',
|
|
80
|
-
])
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should handle complex stack traces with mixed paths', () => {
|
|
85
|
-
const stack = `Error: Complex error
|
|
86
|
-
at Object.test1 (file:///project/.wrangler/test.js:1:1)
|
|
87
|
-
at Object.test2 (file:///project/node_modules/module/index.js:2:2)
|
|
88
|
-
at Object.test3 (file:///normal/path/file.js:3:3)`;
|
|
89
|
-
|
|
90
|
-
const result = prettyStack(stack);
|
|
91
|
-
|
|
92
|
-
expect(result).toEqual(
|
|
93
|
-
expect.arrayContaining([
|
|
94
|
-
'at Object.test1 (/.wrangler/test.js:1:1)',
|
|
95
|
-
'at Object.test2 (/node_modules/module/index.js:2:2)',
|
|
96
|
-
'at Object.test3 (/normal/path/file.js:3:3)',
|
|
97
|
-
])
|
|
98
|
-
);
|
|
99
|
-
expect(result.join('\n')).not.toContain('file://');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should handle stack traces without matching regex pattern', () => {
|
|
103
|
-
const stack = `at Object.test (file:///simple/path/file.js:1:1)
|
|
104
|
-
at Object.test2 (file:///another/path/file.js:2:2)`;
|
|
105
|
-
|
|
106
|
-
const result = prettyStack(stack);
|
|
107
|
-
expect(result).toEqual(
|
|
108
|
-
expect.arrayContaining([
|
|
109
|
-
'at Object.test (/simple/path/file.js:1:1)',
|
|
110
|
-
'at Object.test2 (/another/path/file.js:2:2)',
|
|
111
|
-
])
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should preserve order of stack lines', () => {
|
|
116
|
-
const stack = `Error: Test error
|
|
117
|
-
at Object.first (/path/first.js:1:1)
|
|
118
|
-
at Object.second (/path/second.js:2:2)
|
|
119
|
-
at Object.third (/path/third.js:3:3)`;
|
|
120
|
-
|
|
121
|
-
const result = prettyStack(stack);
|
|
122
|
-
expect(result[0]).toContain('at Object.first (/path/first.js:1:1)');
|
|
123
|
-
expect(result[1]).toContain('at Object.second (/path/second.js:2:2)');
|
|
124
|
-
expect(result[2]).toContain('at Object.third (/path/third.js:3:3)');
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe('prettyError', () => {
|
|
129
|
-
it('should extract message and stack from standard Error', () => {
|
|
130
|
-
const errorMessage = 'Test error message';
|
|
131
|
-
const stackMessage =
|
|
132
|
-
'Error: Test error message\n at Object.test (/path/to/file.js:1:1)';
|
|
133
|
-
|
|
134
|
-
const error = new Error(errorMessage);
|
|
135
|
-
error.stack = stackMessage;
|
|
136
|
-
|
|
137
|
-
const result = prettyError(error);
|
|
138
|
-
|
|
139
|
-
expect(result).toHaveProperty('message', errorMessage);
|
|
140
|
-
expect(result).toHaveProperty('stack');
|
|
141
|
-
expect(Array.isArray(result.stack)).toBe(true);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should handle Error without stack', () => {
|
|
145
|
-
const error = new Error('Test error');
|
|
146
|
-
delete (error as Error & { stack?: string }).stack;
|
|
147
|
-
|
|
148
|
-
const result = prettyError(error);
|
|
149
|
-
|
|
150
|
-
expect(result.message).toBe('Test error');
|
|
151
|
-
expect(result.stack).toEqual([]);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should handle Error with empty message', () => {
|
|
155
|
-
const error = new Error('');
|
|
156
|
-
error.stack = 'Error: \n at Object.test (/path/to/file.js:1:1)';
|
|
157
|
-
|
|
158
|
-
const result = prettyError(error);
|
|
159
|
-
|
|
160
|
-
expect(result.message).toBe('');
|
|
161
|
-
expect(result.stack).toBeDefined();
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should handle custom Error classes', () => {
|
|
165
|
-
class CustomError extends Error {
|
|
166
|
-
constructor(message: string) {
|
|
167
|
-
super(message);
|
|
168
|
-
this.name = 'CustomError';
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const error = new CustomError('Custom error message');
|
|
173
|
-
error.stack =
|
|
174
|
-
'CustomError: Custom error message\n at Object.test (/path/to/file.js:1:1)';
|
|
175
|
-
|
|
176
|
-
const result = prettyError(error);
|
|
177
|
-
|
|
178
|
-
expect(result.message).toBe('Custom error message');
|
|
179
|
-
expect(result.stack).toBeDefined();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should process the stack through prettyStack', () => {
|
|
183
|
-
const error = new Error('Test error');
|
|
184
|
-
error.stack = `Error: Test error
|
|
185
|
-
at Object.test (file:///path/.wrangler/file.js:1:1)`;
|
|
186
|
-
|
|
187
|
-
const result = prettyError(error);
|
|
188
|
-
|
|
189
|
-
const stackString = result.stack.join('\n');
|
|
190
|
-
expect(stackString).not.toContain('file://');
|
|
191
|
-
expect(stackString).toContain('file.js:1:1');
|
|
192
|
-
expect(stackString).not.toContain('Error: Test error');
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe('createRootLogEntry', () => {
|
|
197
|
-
const mockDetails: Details = { service: 'test-service', version: '1.0.0' };
|
|
198
|
-
const mockEventId = 'test-event-123';
|
|
199
|
-
|
|
200
|
-
it('should create basic root log entry with required fields', () => {
|
|
201
|
-
const options = {
|
|
202
|
-
path: '/api/test',
|
|
203
|
-
method: 'get' as Method,
|
|
204
|
-
details: mockDetails,
|
|
205
|
-
eventId: mockEventId,
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const result = createRootLogEntry(options);
|
|
209
|
-
|
|
210
|
-
expect(result).toHaveProperty('root');
|
|
211
|
-
expect(Array.isArray(result.root)).toBe(true);
|
|
212
|
-
expect(result.root).toHaveLength(1);
|
|
213
|
-
|
|
214
|
-
const entry = result.root[0];
|
|
215
|
-
expect(entry.type).toBe('info');
|
|
216
|
-
expect(entry.message).toBe('Request received');
|
|
217
|
-
expect(entry.payload).toBeDefined();
|
|
218
|
-
expect(entry.timestamp).toBeDefined();
|
|
219
|
-
expect(typeof entry.timestamp).toBe('number');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('should handle path correctly', () => {
|
|
223
|
-
const options = {
|
|
224
|
-
path: '/api/users/123',
|
|
225
|
-
method: 'get' as Method,
|
|
226
|
-
details: mockDetails,
|
|
227
|
-
eventId: mockEventId,
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const result = createRootLogEntry(options);
|
|
231
|
-
const payload = result.root[0].payload as RootPayload;
|
|
232
|
-
|
|
233
|
-
expect(payload.path).toBe('/api/users/123');
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('should handle method correctly', () => {
|
|
237
|
-
const options = {
|
|
238
|
-
path: '/api/test',
|
|
239
|
-
method: 'post' as Method,
|
|
240
|
-
details: mockDetails,
|
|
241
|
-
eventId: mockEventId,
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
const result = createRootLogEntry(options);
|
|
245
|
-
const payload = result.root[0].payload as RootPayload;
|
|
246
|
-
|
|
247
|
-
expect(payload.path).toBe('/api/test');
|
|
248
|
-
expect(payload.method).toBe('post');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it('should include parentEventId when provided', () => {
|
|
252
|
-
const parentEventId = 'parent-event-456';
|
|
253
|
-
const options = {
|
|
254
|
-
path: '/api/test',
|
|
255
|
-
method: 'put' as Method,
|
|
256
|
-
details: mockDetails,
|
|
257
|
-
eventId: mockEventId,
|
|
258
|
-
parentEventId,
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const result = createRootLogEntry(options);
|
|
262
|
-
const payload = result.root[0].payload as RootPayload;
|
|
263
|
-
|
|
264
|
-
expect(payload.parentEventId).toBe(parentEventId);
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it('should not include parentEventId when not provided', () => {
|
|
268
|
-
const options = {
|
|
269
|
-
path: '/api/test',
|
|
270
|
-
method: 'delete' as Method,
|
|
271
|
-
details: mockDetails,
|
|
272
|
-
eventId: mockEventId,
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const result = createRootLogEntry(options);
|
|
276
|
-
const payload = result.root[0].payload as RootPayload;
|
|
277
|
-
|
|
278
|
-
expect(payload.parentEventId).toBeUndefined();
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it('should add error log when withParentEventId is true but no parentEventId provided', () => {
|
|
282
|
-
const options = {
|
|
283
|
-
path: '/api/test',
|
|
284
|
-
method: 'patch' as Method,
|
|
285
|
-
details: mockDetails,
|
|
286
|
-
eventId: mockEventId,
|
|
287
|
-
withParentEventId: true,
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const result = createRootLogEntry(options);
|
|
291
|
-
|
|
292
|
-
expect(result.root).toHaveLength(2);
|
|
293
|
-
|
|
294
|
-
const infoEntry = result.root[0];
|
|
295
|
-
const errorEntry = result.root[1];
|
|
296
|
-
|
|
297
|
-
expect(infoEntry.type).toBe('info');
|
|
298
|
-
expect(infoEntry.message).toBe('Request received');
|
|
299
|
-
|
|
300
|
-
expect(errorEntry.type).toBe('error');
|
|
301
|
-
expect(errorEntry.message).toBe('Parent event ID expected but not found');
|
|
302
|
-
expect(errorEntry.payload).toBeUndefined();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it('should not add error log when withParentEventId is true and parentEventId is provided', () => {
|
|
306
|
-
const options = {
|
|
307
|
-
path: '/api/test',
|
|
308
|
-
method: 'head' as Method,
|
|
309
|
-
details: mockDetails,
|
|
310
|
-
eventId: mockEventId,
|
|
311
|
-
parentEventId: 'parent-123',
|
|
312
|
-
withParentEventId: true,
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
const result = createRootLogEntry(options);
|
|
316
|
-
|
|
317
|
-
expect(result.root).toHaveLength(1);
|
|
318
|
-
expect(result.root[0].type).toBe('info');
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('should not add error log when withParentEventId is false', () => {
|
|
322
|
-
const options = {
|
|
323
|
-
path: '/api/test',
|
|
324
|
-
method: 'options' as Method,
|
|
325
|
-
details: mockDetails,
|
|
326
|
-
eventId: mockEventId,
|
|
327
|
-
withParentEventId: false,
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
const result = createRootLogEntry(options);
|
|
331
|
-
|
|
332
|
-
expect(result.root).toHaveLength(1);
|
|
333
|
-
expect(result.root[0].type).toBe('info');
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it('should handle all HTTP methods', () => {
|
|
337
|
-
const methods: Method[] = [
|
|
338
|
-
'get',
|
|
339
|
-
'post',
|
|
340
|
-
'put',
|
|
341
|
-
'delete',
|
|
342
|
-
'patch',
|
|
343
|
-
'head',
|
|
344
|
-
'options',
|
|
345
|
-
'trace',
|
|
346
|
-
'connect',
|
|
347
|
-
];
|
|
348
|
-
|
|
349
|
-
methods.forEach((method) => {
|
|
350
|
-
const options = {
|
|
351
|
-
path: '/api/test',
|
|
352
|
-
method,
|
|
353
|
-
details: mockDetails,
|
|
354
|
-
eventId: mockEventId,
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const result = createRootLogEntry(options);
|
|
358
|
-
const payload = result.root[0].payload as RootPayload;
|
|
359
|
-
|
|
360
|
-
expect(payload.method).toBe(method);
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
it('should preserve complex details object', () => {
|
|
365
|
-
const complexDetails: Details = {
|
|
366
|
-
service: 'api-gateway',
|
|
367
|
-
version: '2.1.0',
|
|
368
|
-
environment: 'production',
|
|
369
|
-
region: 'us-east-1',
|
|
370
|
-
userId: 12345,
|
|
371
|
-
metadata: { feature: 'logging', enabled: true },
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
const options = {
|
|
375
|
-
path: '/api/test',
|
|
376
|
-
method: 'get' as Method,
|
|
377
|
-
details: complexDetails,
|
|
378
|
-
eventId: mockEventId,
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
const result = createRootLogEntry(options);
|
|
382
|
-
const payload = result.root[0].payload as RootPayload;
|
|
383
|
-
|
|
384
|
-
expect(payload.details).toEqual(complexDetails);
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
it('should generate reasonable timestamps', () => {
|
|
388
|
-
const beforeTime = Date.now();
|
|
389
|
-
|
|
390
|
-
const options = {
|
|
391
|
-
path: '/api/test',
|
|
392
|
-
method: 'get' as Method,
|
|
393
|
-
details: mockDetails,
|
|
394
|
-
eventId: mockEventId,
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
const result = createRootLogEntry(options);
|
|
398
|
-
const afterTime = Date.now();
|
|
399
|
-
|
|
400
|
-
const timestamp = result.root[0].timestamp;
|
|
401
|
-
|
|
402
|
-
expect(timestamp).toBeGreaterThanOrEqual(beforeTime);
|
|
403
|
-
expect(timestamp).toBeLessThanOrEqual(afterTime);
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it('should handle different paths', () => {
|
|
407
|
-
const options = {
|
|
408
|
-
path: '/api/users',
|
|
409
|
-
method: 'get' as Method,
|
|
410
|
-
details: mockDetails,
|
|
411
|
-
eventId: mockEventId,
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
const result = createRootLogEntry(options);
|
|
415
|
-
const payload = result.root[0].payload as RootPayload;
|
|
416
|
-
|
|
417
|
-
expect(payload.path).toBe('/api/users');
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it('should handle paths with different segments', () => {
|
|
421
|
-
const options = {
|
|
422
|
-
path: '/users?page=2&limit=10',
|
|
423
|
-
method: 'get' as Method,
|
|
424
|
-
details: mockDetails,
|
|
425
|
-
eventId: mockEventId,
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const result = createRootLogEntry(options);
|
|
429
|
-
const payload = result.root[0].payload as RootPayload;
|
|
430
|
-
|
|
431
|
-
// Based on actual behavior, the full path including query params is preserved
|
|
432
|
-
expect(payload.path).toBe('/users?page=2&limit=10');
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
it('should maintain correct payload structure type', () => {
|
|
436
|
-
const options = {
|
|
437
|
-
path: '/api/test',
|
|
438
|
-
method: 'get' as Method,
|
|
439
|
-
details: mockDetails,
|
|
440
|
-
eventId: mockEventId,
|
|
441
|
-
parentEventId: 'parent-123',
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
const result = createRootLogEntry(options);
|
|
445
|
-
const payload = result.root[0].payload as RootPayload;
|
|
446
|
-
|
|
447
|
-
expect(payload).toHaveProperty('path');
|
|
448
|
-
expect(payload).toHaveProperty('method');
|
|
449
|
-
expect(payload).toHaveProperty('details');
|
|
450
|
-
expect(payload).toHaveProperty('eventId');
|
|
451
|
-
expect(payload).toHaveProperty('parentEventId');
|
|
452
|
-
});
|
|
453
|
-
});
|