hierarchical-area-logger 0.2.9 → 0.3.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/dist/index.d.mts +57 -0
- package/dist/index.d.ts +2 -1
- package/dist/{index.js → index.mjs} +17 -19
- package/dist/index.mjs.map +1 -0
- package/package.json +23 -13
- package/.husky/pre-commit +0 -2
- package/.prettierignore +0 -4
- package/.prettierrc +0 -8
- package/CODE_OF_CONDUCT.md +0 -73
- package/CONTRIBUTING.md +0 -313
- package/dist/index.js.map +0 -1
- package/eslint.config.js +0 -43
- package/src/Logger.ts +0 -100
- package/src/index.ts +0 -9
- package/src/types.ts +0 -42
- package/src/utils.ts +0 -93
- package/tsconfig.json +0 -19
- package/tsup.config.ts +0 -11
- package/vitest.config.ts +0 -8
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
type Details = {
|
|
2
|
+
service: string;
|
|
3
|
+
} & Record<string, unknown>;
|
|
4
|
+
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace' | 'connect';
|
|
5
|
+
type LogEntryType = 'info' | 'warn' | 'error' | 'log' | 'debug';
|
|
6
|
+
type LogEntry = {
|
|
7
|
+
type: LogEntryType;
|
|
8
|
+
message: string;
|
|
9
|
+
payload?: object;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
};
|
|
12
|
+
type RootPayload = {
|
|
13
|
+
path?: string;
|
|
14
|
+
method?: Method;
|
|
15
|
+
eventId: string;
|
|
16
|
+
parentEventId?: string;
|
|
17
|
+
details: Details;
|
|
18
|
+
};
|
|
19
|
+
type LogData = Record<string, LogEntry[]>;
|
|
20
|
+
interface LoggerOptions {
|
|
21
|
+
details: Details;
|
|
22
|
+
path?: string;
|
|
23
|
+
parentEventId?: string;
|
|
24
|
+
withParentEventId?: boolean;
|
|
25
|
+
method?: Method;
|
|
26
|
+
overrideEventId?: string;
|
|
27
|
+
defaultArea?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare class Logger {
|
|
31
|
+
eventId: string;
|
|
32
|
+
private log;
|
|
33
|
+
parentEventId?: string;
|
|
34
|
+
private defaultArea;
|
|
35
|
+
constructor(options: LoggerOptions);
|
|
36
|
+
private finalizeRootMessage;
|
|
37
|
+
private addMessage;
|
|
38
|
+
getArea(name?: string): {
|
|
39
|
+
info: (message: string, payload?: LogEntry["payload"]) => void;
|
|
40
|
+
warn: (message: string, payload?: LogEntry["payload"]) => void;
|
|
41
|
+
error: (message: string, payload?: LogEntry["payload"] | Error) => void;
|
|
42
|
+
log: (message: string, payload?: LogEntry["payload"]) => void;
|
|
43
|
+
debug: (message: string, payload?: LogEntry["payload"]) => void;
|
|
44
|
+
};
|
|
45
|
+
dump(): LogData;
|
|
46
|
+
dumpProduction(): LogData;
|
|
47
|
+
appendLogData(logData: LogData): void;
|
|
48
|
+
}
|
|
49
|
+
declare const createLogger: (options: LoggerOptions) => Logger;
|
|
50
|
+
|
|
51
|
+
declare const prettyError: (err: Error) => {
|
|
52
|
+
message: string;
|
|
53
|
+
stack: string[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export { Logger, createLogger, prettyError };
|
|
57
|
+
export type { Details, LogData, LogEntry, LogEntryType, RootPayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -53,4 +53,5 @@ declare const prettyError: (err: Error) => {
|
|
|
53
53
|
stack: string[];
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
export {
|
|
56
|
+
export { Logger, createLogger, prettyError };
|
|
57
|
+
export type { Details, LogData, LogEntry, LogEntryType, RootPayload };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import { init } from "@paralleldrive/cuid2";
|
|
1
|
+
import { init } from '@paralleldrive/cuid2';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
var prettyStack = (stack) => {
|
|
3
|
+
const prettyStack = (stack) => {
|
|
6
4
|
if (!stack) return [];
|
|
7
5
|
let toReplace = "";
|
|
8
6
|
const regex = /file:\/\/\/(.*)(\.wrangler|node_modules)\/.*\)/gm;
|
|
@@ -12,12 +10,12 @@ var prettyStack = (stack) => {
|
|
|
12
10
|
}
|
|
13
11
|
return stack.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("Error: ")).map((line) => line.replace(toReplace, "")).map((line) => line.replace("file://", ""));
|
|
14
12
|
};
|
|
15
|
-
|
|
13
|
+
const prettyError = (err) => {
|
|
16
14
|
const stack = prettyStack(err.stack);
|
|
17
15
|
const message = err.message;
|
|
18
16
|
return { message, stack };
|
|
19
17
|
};
|
|
20
|
-
|
|
18
|
+
const createRootLogEntry = ({
|
|
21
19
|
path,
|
|
22
20
|
method,
|
|
23
21
|
details,
|
|
@@ -51,7 +49,7 @@ var createRootLogEntry = ({
|
|
|
51
49
|
}
|
|
52
50
|
return rootLogEntry;
|
|
53
51
|
};
|
|
54
|
-
|
|
52
|
+
const removeEmptyAreas = (logData) => {
|
|
55
53
|
const newLogData = {};
|
|
56
54
|
for (const [key, value] of Object.entries(logData)) {
|
|
57
55
|
if (value.length > 0) {
|
|
@@ -60,10 +58,10 @@ var removeEmptyAreas = (logData) => {
|
|
|
60
58
|
}
|
|
61
59
|
return newLogData;
|
|
62
60
|
};
|
|
63
|
-
|
|
61
|
+
const excludeDebugLogs = (logEntries) => {
|
|
64
62
|
return logEntries.filter((entry) => entry.type !== "debug");
|
|
65
63
|
};
|
|
66
|
-
|
|
64
|
+
const processProductionLogData = (logData) => {
|
|
67
65
|
const newLogData = {};
|
|
68
66
|
for (const [key, value] of Object.entries(logData)) {
|
|
69
67
|
if (key !== "root") {
|
|
@@ -73,8 +71,11 @@ var processProductionLogData = (logData) => {
|
|
|
73
71
|
return removeEmptyAreas(newLogData);
|
|
74
72
|
};
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
class Logger {
|
|
75
|
+
eventId;
|
|
76
|
+
log;
|
|
77
|
+
parentEventId;
|
|
78
|
+
defaultArea;
|
|
78
79
|
constructor(options) {
|
|
79
80
|
this.parentEventId = options.parentEventId;
|
|
80
81
|
this.eventId = options.overrideEventId || init({ fingerprint: options.details.service })();
|
|
@@ -138,13 +139,10 @@ var Logger = class {
|
|
|
138
139
|
delete logData.root;
|
|
139
140
|
this.log = { ...logData, ...this.log };
|
|
140
141
|
}
|
|
141
|
-
}
|
|
142
|
-
|
|
142
|
+
}
|
|
143
|
+
const createLogger = (options) => {
|
|
143
144
|
return new Logger(options);
|
|
144
145
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
prettyError
|
|
149
|
-
};
|
|
150
|
-
//# sourceMappingURL=index.js.map
|
|
146
|
+
|
|
147
|
+
export { Logger, createLogger, prettyError };
|
|
148
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/Logger.ts"],"sourcesContent":["import {\n CreateRootLogEntryOptions,\n LogData,\n LogEntry,\n RootPayload,\n} 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\nexport const removeEmptyAreas = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (value.length > 0) {\n newLogData[key] = value;\n }\n }\n return newLogData;\n};\n\nexport const excludeDebugLogs = (logEntries: LogEntry[]) => {\n return logEntries.filter((entry) => entry.type !== 'debug');\n};\n\nexport const processProductionLogData = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (key !== 'root') {\n newLogData[key] = excludeDebugLogs(value);\n }\n }\n return removeEmptyAreas(newLogData);\n};\n","import { init } from '@paralleldrive/cuid2';\nimport {\n createRootLogEntry,\n prettyError,\n processProductionLogData,\n} from './utils';\nimport type { LogData, LoggerOptions, LogEntry, LogEntryType } 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 =\n options.overrideEventId ||\n init({ fingerprint: options.details.service })();\n this.defaultArea = options.defaultArea || 'defaultArea';\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 private finalizeRootMessage() {\n this.addMessage('root', 'info', 'Request completed', {\n totalDuration: Date.now() - this.log.root[0].timestamp,\n });\n }\n\n private addMessage(\n name: string,\n type: LogEntryType,\n message: string,\n payload?: LogEntry['payload'] | Error\n ) {\n const finalPayload =\n payload instanceof Error ? prettyError(payload) : payload;\n\n this.log[name]!.push({\n type,\n message,\n payload: finalPayload,\n timestamp: Date.now(),\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.addMessage(name, 'info', message, payload);\n },\n warn: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'warn', message, payload);\n },\n error: (message: string, payload?: LogEntry['payload'] | Error) => {\n this.addMessage(name, 'error', message, payload);\n },\n log: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'log', message, payload);\n },\n debug: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'debug', message, payload);\n },\n };\n }\n\n // Public methods on main instance\n public dump(): LogData {\n this.finalizeRootMessage();\n return this.log;\n }\n\n public dumpProduction(): LogData {\n this.finalizeRootMessage();\n return processProductionLogData(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"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hierarchical-area-logger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
7
13
|
"scripts": {
|
|
8
14
|
"prepare": "husky",
|
|
9
|
-
"build": "
|
|
10
|
-
"dev": "
|
|
15
|
+
"build": "unbuild",
|
|
16
|
+
"dev": "unbuild --stub",
|
|
17
|
+
"prepack": "unbuild",
|
|
11
18
|
"test": "vitest",
|
|
12
19
|
"test:ui": "vitest --ui",
|
|
13
20
|
"coverage": "vitest --coverage",
|
|
@@ -34,18 +41,21 @@
|
|
|
34
41
|
"engines": {
|
|
35
42
|
"node": ">=18.0.0"
|
|
36
43
|
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist"
|
|
46
|
+
],
|
|
37
47
|
"description": "Hierarchical Area Logger",
|
|
38
48
|
"devDependencies": {
|
|
39
|
-
"@eslint/js": "^9.
|
|
40
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
41
|
-
"@typescript-eslint/parser": "^8.
|
|
42
|
-
"@vitest/coverage-v8": "^4.
|
|
43
|
-
"eslint": "^
|
|
49
|
+
"@eslint/js": "^9.39.5",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^8.63.0",
|
|
51
|
+
"@typescript-eslint/parser": "^8.63.0",
|
|
52
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
53
|
+
"eslint": "^10.7.0",
|
|
44
54
|
"husky": "^9.1.7",
|
|
45
|
-
"prettier": "^3.
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"vitest": "^4.
|
|
55
|
+
"prettier": "^3.9.5",
|
|
56
|
+
"typescript": "^6.0.3",
|
|
57
|
+
"unbuild": "^3.6.1",
|
|
58
|
+
"vitest": "^4.1.10"
|
|
49
59
|
},
|
|
50
60
|
"dependencies": {
|
|
51
61
|
"@paralleldrive/cuid2": "^3.0.6"
|
package/.husky/pre-commit
DELETED
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
-
education, socio-economic status, nationality, personal appearance, race,
|
|
10
|
-
religion, or sexual identity and orientation.
|
|
11
|
-
|
|
12
|
-
## Our Standards
|
|
13
|
-
|
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
|
15
|
-
include:
|
|
16
|
-
|
|
17
|
-
- Using welcoming and inclusive language
|
|
18
|
-
- Being respectful of differing viewpoints and experiences
|
|
19
|
-
- Gracefully accepting constructive criticism
|
|
20
|
-
- Focusing on what is best for the community
|
|
21
|
-
- Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior by participants include:
|
|
24
|
-
|
|
25
|
-
- The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
-
advances
|
|
27
|
-
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
-
- Public or private harassment
|
|
29
|
-
- Publishing others' private information, such as a physical or electronic
|
|
30
|
-
address, without explicit permission
|
|
31
|
-
- Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
-
professional setting
|
|
33
|
-
|
|
34
|
-
## Our Responsibilities
|
|
35
|
-
|
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
-
response to any instances of unacceptable behavior.
|
|
39
|
-
|
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
-
threatening, offensive, or harmful.
|
|
45
|
-
|
|
46
|
-
## Scope
|
|
47
|
-
|
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
-
when an individual is representing the project or its community. Examples of
|
|
50
|
-
representing a project or community include using an official project e-mail
|
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
|
53
|
-
further defined and clarified by project maintainers.
|
|
54
|
-
|
|
55
|
-
## Enforcement
|
|
56
|
-
|
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
-
reported by contacting the project team at {{ email }}. All
|
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
|
63
|
-
|
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
-
members of the project's leadership.
|
|
67
|
-
|
|
68
|
-
## Attribution
|
|
69
|
-
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
-
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
72
|
-
|
|
73
|
-
[homepage]: https://www.contributor-covenant.org
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
# 🤝 Contributing to Hierarchical Area Logger
|
|
2
|
-
|
|
3
|
-
Thank you for your interest in contributing to this TypeScript logging library! This guide will help you get started and ensure your contributions align with the project standards.
|
|
4
|
-
|
|
5
|
-
## 📋 Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Development Setup](#development-setup)
|
|
8
|
-
- [Development Workflow](#development-workflow)
|
|
9
|
-
- [Project Structure](#project-structure)
|
|
10
|
-
- [Code Standards](#code-standards)
|
|
11
|
-
- [Testing](#testing)
|
|
12
|
-
- [Pull Request Process](#pull-request-process)
|
|
13
|
-
- [Release Process](#release-process)
|
|
14
|
-
|
|
15
|
-
## 🛠 Development Setup
|
|
16
|
-
|
|
17
|
-
### Prerequisites
|
|
18
|
-
|
|
19
|
-
- **Node.js** (v18 or higher)
|
|
20
|
-
- **npm** or **yarn** package manager
|
|
21
|
-
- **TypeScript** knowledge
|
|
22
|
-
|
|
23
|
-
### Installation
|
|
24
|
-
|
|
25
|
-
1. **Fork and clone the repository**
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
git clone https://github.com/Em3ODMe/hierarchical-area-logger.git
|
|
29
|
-
cd hierarchical-area-logger
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
2. **Install dependencies**
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npm install
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
3. **Verify setup**
|
|
39
|
-
```bash
|
|
40
|
-
npm run lint:check
|
|
41
|
-
npm test
|
|
42
|
-
npm run build
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 🔄 Development Workflow
|
|
46
|
-
|
|
47
|
-
### Available Scripts
|
|
48
|
-
|
|
49
|
-
| Script | Purpose | When to Use |
|
|
50
|
-
| ------------------ | ------------------------ | ------------------ |
|
|
51
|
-
| `npm run dev` | Watch mode development | Active development |
|
|
52
|
-
| `npm run build` | Build the library | Before committing |
|
|
53
|
-
| `npm test` | Run unit tests | After code changes |
|
|
54
|
-
| `npm run test:ui` | Interactive test runner | Debugging tests |
|
|
55
|
-
| `npm run lint` | Check code quality | Before committing |
|
|
56
|
-
| `npm run lint:fix` | Auto-fix lint issues | During development |
|
|
57
|
-
| `npm run coverage` | Generate coverage report | Before PR |
|
|
58
|
-
|
|
59
|
-
### Daily Development
|
|
60
|
-
|
|
61
|
-
1. **Start development server**
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npm run dev
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
2. **Make changes to source files** in `src/` directory
|
|
68
|
-
|
|
69
|
-
3. **Run tests frequently**
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
npm test
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
4. **Check linting**
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
npm run lint:check
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
5. **Build before commit**
|
|
82
|
-
```bash
|
|
83
|
-
npm run build
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## 📁 Project Structure
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
logger/
|
|
90
|
-
├── src/
|
|
91
|
-
│ ├── index.ts # Main entry point and exports
|
|
92
|
-
│ ├── Logger.ts # Core Logger class implementation
|
|
93
|
-
│ ├── types.ts # TypeScript type definitions
|
|
94
|
-
│ └── utils.ts # Utility functions
|
|
95
|
-
├── dist/ # Built output (auto-generated)
|
|
96
|
-
├── test/
|
|
97
|
-
│ └── logger.test.ts # Test suite
|
|
98
|
-
├── coverage/ # Coverage reports (auto-generated)
|
|
99
|
-
├── package.json # Project configuration
|
|
100
|
-
├── tsconfig.json # TypeScript configuration
|
|
101
|
-
├── vitest.config.ts # Test configuration
|
|
102
|
-
├── eslint.config.js # Linting configuration
|
|
103
|
-
└── tsup.config.ts # Build configuration
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Key Files & Responsibilities
|
|
107
|
-
|
|
108
|
-
- **`src/Logger.ts`**: Core Logger class with area-based logging
|
|
109
|
-
- **`src/types.ts`**: TypeScript interfaces and type definitions
|
|
110
|
-
- **`src/utils.ts`**: Helper functions for log creation and error handling
|
|
111
|
-
- **`src/index.ts`**: Public API exports
|
|
112
|
-
|
|
113
|
-
## 📝 Code Standards
|
|
114
|
-
|
|
115
|
-
### TypeScript Configuration
|
|
116
|
-
|
|
117
|
-
- **Target**: ES2020
|
|
118
|
-
- **Module**: ESNext
|
|
119
|
-
- **Strict mode**: Enabled
|
|
120
|
-
- **Output**: Both CommonJS and ESM modules
|
|
121
|
-
|
|
122
|
-
### ESLint Rules
|
|
123
|
-
|
|
124
|
-
Key rules enforced:
|
|
125
|
-
|
|
126
|
-
- No unused variables (with `_` prefix exception)
|
|
127
|
-
- Warn on `any` types
|
|
128
|
-
- Prefer `const` over `let`
|
|
129
|
-
- No `var` declarations
|
|
130
|
-
- No empty functions (warn)
|
|
131
|
-
|
|
132
|
-
### Code Style Guidelines
|
|
133
|
-
|
|
134
|
-
1. **Use TypeScript for all new code**
|
|
135
|
-
2. **Follow existing naming conventions** (camelCase for variables, PascalCase for classes)
|
|
136
|
-
3. **Export only what's necessary** from index.ts
|
|
137
|
-
4. **Add JSDoc comments for public APIs**
|
|
138
|
-
5. **Use meaningful variable and function names**
|
|
139
|
-
|
|
140
|
-
### Import Organization
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
// External dependencies
|
|
144
|
-
import { init } from '@paralleldrive/cuid2';
|
|
145
|
-
|
|
146
|
-
// Internal modules
|
|
147
|
-
import { createRootLogEntry, prettyError } from './utils';
|
|
148
|
-
import { LogData, LoggerOptions, LogEntry } from './types';
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## 🧪 Testing
|
|
152
|
-
|
|
153
|
-
### Test Framework
|
|
154
|
-
|
|
155
|
-
- **Vitest** for unit testing
|
|
156
|
-
- **Coverage** with v8 provider
|
|
157
|
-
- **100% coverage requirement** for new code
|
|
158
|
-
|
|
159
|
-
### Writing Tests
|
|
160
|
-
|
|
161
|
-
1. **Test file location**: `test/` directory
|
|
162
|
-
2. **Naming convention**: `*.test.ts`
|
|
163
|
-
3. **Structure your tests**:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { describe, it, expect } from 'vitest';
|
|
167
|
-
import { createLogger } from '../src/index';
|
|
168
|
-
|
|
169
|
-
describe('Logger functionality', () => {
|
|
170
|
-
it('should create logger with event ID', () => {
|
|
171
|
-
const logger = createLogger({
|
|
172
|
-
details: { service: 'test' },
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
expect(logger.eventId).toBeDefined();
|
|
176
|
-
expect(typeof logger.eventId).toBe('string');
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Test Categories
|
|
182
|
-
|
|
183
|
-
1. **Unit tests**: Individual function behavior
|
|
184
|
-
2. **Integration tests**: Component interaction
|
|
185
|
-
3. **Edge cases**: Error handling, invalid inputs
|
|
186
|
-
4. **Type safety**: TypeScript compilation checks
|
|
187
|
-
|
|
188
|
-
## 🔄 Pull Request Process
|
|
189
|
-
|
|
190
|
-
### Branch Naming
|
|
191
|
-
|
|
192
|
-
Use descriptive branch names:
|
|
193
|
-
|
|
194
|
-
- `feature/area-logging-enhancement`
|
|
195
|
-
- `fix/error-handling-bug`
|
|
196
|
-
- `docs/updated-readme`
|
|
197
|
-
|
|
198
|
-
### Commit Messages
|
|
199
|
-
|
|
200
|
-
Follow conventional commits:
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
type(scope): description
|
|
204
|
-
|
|
205
|
-
feat(logger): add batch logging capability
|
|
206
|
-
fix(types): resolve optional parameter issue
|
|
207
|
-
docs(readme): update installation instructions
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Before Submitting PR
|
|
211
|
-
|
|
212
|
-
1. **Create feature branch** from main
|
|
213
|
-
2. **Make your changes** with atomic commits
|
|
214
|
-
3. **Ensure all tests pass**:
|
|
215
|
-
```bash
|
|
216
|
-
npm test
|
|
217
|
-
npm run test
|
|
218
|
-
```
|
|
219
|
-
4. **Verify linting**:
|
|
220
|
-
```bash
|
|
221
|
-
npm run lint:check
|
|
222
|
-
```
|
|
223
|
-
5. **Build successfully**:
|
|
224
|
-
```bash
|
|
225
|
-
npm run build
|
|
226
|
-
```
|
|
227
|
-
6. **Update documentation** if needed
|
|
228
|
-
|
|
229
|
-
### PR Description Template
|
|
230
|
-
|
|
231
|
-
```markdown
|
|
232
|
-
## Description
|
|
233
|
-
|
|
234
|
-
Brief description of changes made.
|
|
235
|
-
|
|
236
|
-
## Type of Change
|
|
237
|
-
|
|
238
|
-
- [ ] Bug fix
|
|
239
|
-
- [ ] New feature
|
|
240
|
-
- [ ] Breaking change
|
|
241
|
-
- [ ] Documentation update
|
|
242
|
-
|
|
243
|
-
## Testing
|
|
244
|
-
|
|
245
|
-
- [ ] All tests pass
|
|
246
|
-
- [ ] 100% coverage maintained
|
|
247
|
-
- [ ] New tests added for new functionality
|
|
248
|
-
|
|
249
|
-
## Checklist
|
|
250
|
-
|
|
251
|
-
- [ ] Code follows project style guidelines
|
|
252
|
-
- [ ] Self-review completed
|
|
253
|
-
- [ ] Documentation updated if necessary
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## 🚀 Release Process
|
|
257
|
-
|
|
258
|
-
### Version Management
|
|
259
|
-
|
|
260
|
-
- Follow **Semantic Versioning** (SemVer)
|
|
261
|
-
- Update version in `package.json`
|
|
262
|
-
- Create git tag for releases
|
|
263
|
-
|
|
264
|
-
### Pre-release Checks
|
|
265
|
-
|
|
266
|
-
1. **All tests pass**
|
|
267
|
-
2. **100% coverage maintained**
|
|
268
|
-
3. **Linting passes**
|
|
269
|
-
4. **Build succeeds**
|
|
270
|
-
5. **Documentation updated**
|
|
271
|
-
|
|
272
|
-
### Build Verification
|
|
273
|
-
|
|
274
|
-
```bash
|
|
275
|
-
# Clean build
|
|
276
|
-
rm -rf dist/
|
|
277
|
-
npm run build
|
|
278
|
-
|
|
279
|
-
# Verify outputs
|
|
280
|
-
ls -la dist/
|
|
281
|
-
# Should contain: index.js, index.mjs, index.d.ts, source maps
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Publishing
|
|
285
|
-
|
|
286
|
-
1. **Update version** in package.json
|
|
287
|
-
2. **Create git tag**:
|
|
288
|
-
```bash
|
|
289
|
-
git tag v0.1.1
|
|
290
|
-
git push origin v0.1.1
|
|
291
|
-
```
|
|
292
|
-
3. **Publish to npm** (if you have access):
|
|
293
|
-
```bash
|
|
294
|
-
npm publish
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## 🆘 Getting Help
|
|
298
|
-
|
|
299
|
-
- **Check existing issues** for similar problems
|
|
300
|
-
- **Read the README.md** for usage examples
|
|
301
|
-
- **Look at test files** for implementation patterns
|
|
302
|
-
- **Review TypeScript types** in `src/types.ts`
|
|
303
|
-
|
|
304
|
-
## 📚 Additional Resources
|
|
305
|
-
|
|
306
|
-
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
|
|
307
|
-
- [Vitest Documentation](https://vitest.dev/)
|
|
308
|
-
- [ESLint Configuration](https://eslint.org/docs/latest/)
|
|
309
|
-
- [Semantic Versioning](https://semver.org/)
|
|
310
|
-
|
|
311
|
-
---
|
|
312
|
-
|
|
313
|
-
Thank you for contributing to the Hierarchical Area Logger project! Your contributions help make this library better for everyone. 🎉
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Logger.ts","../src/utils.ts"],"sourcesContent":["import { init } from '@paralleldrive/cuid2';\nimport {\n createRootLogEntry,\n prettyError,\n processProductionLogData,\n} from './utils';\nimport type { LogData, LoggerOptions, LogEntry, LogEntryType } 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 =\n options.overrideEventId ||\n init({ fingerprint: options.details.service })();\n this.defaultArea = options.defaultArea || 'defaultArea';\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 private finalizeRootMessage() {\n this.addMessage('root', 'info', 'Request completed', {\n totalDuration: Date.now() - this.log.root[0].timestamp,\n });\n }\n\n private addMessage(\n name: string,\n type: LogEntryType,\n message: string,\n payload?: LogEntry['payload'] | Error\n ) {\n const finalPayload =\n payload instanceof Error ? prettyError(payload) : payload;\n\n this.log[name]!.push({\n type,\n message,\n payload: finalPayload,\n timestamp: Date.now(),\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.addMessage(name, 'info', message, payload);\n },\n warn: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'warn', message, payload);\n },\n error: (message: string, payload?: LogEntry['payload'] | Error) => {\n this.addMessage(name, 'error', message, payload);\n },\n log: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'log', message, payload);\n },\n debug: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'debug', message, payload);\n },\n };\n }\n\n // Public methods on main instance\n public dump(): LogData {\n this.finalizeRootMessage();\n return this.log;\n }\n\n public dumpProduction(): LogData {\n this.finalizeRootMessage();\n return processProductionLogData(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 {\n CreateRootLogEntryOptions,\n LogData,\n LogEntry,\n RootPayload,\n} 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\nexport const removeEmptyAreas = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (value.length > 0) {\n newLogData[key] = value;\n }\n }\n return newLogData;\n};\n\nexport const excludeDebugLogs = (logEntries: LogEntry[]) => {\n return logEntries.filter((entry) => entry.type !== 'debug');\n};\n\nexport const processProductionLogData = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (key !== 'root') {\n newLogData[key] = excludeDebugLogs(value);\n }\n }\n return removeEmptyAreas(newLogData);\n};\n"],"mappings":"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","names":[]}
|
package/eslint.config.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js';
|
|
2
|
-
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
3
|
-
import tsparser from '@typescript-eslint/parser';
|
|
4
|
-
|
|
5
|
-
export default [
|
|
6
|
-
js.configs.recommended,
|
|
7
|
-
{
|
|
8
|
-
files: ['**/*.ts'],
|
|
9
|
-
languageOptions: {
|
|
10
|
-
parser: tsparser,
|
|
11
|
-
ecmaVersion: 2020,
|
|
12
|
-
sourceType: 'module',
|
|
13
|
-
globals: {
|
|
14
|
-
process: 'readonly',
|
|
15
|
-
Buffer: 'readonly',
|
|
16
|
-
__dirname: 'readonly',
|
|
17
|
-
__filename: 'readonly',
|
|
18
|
-
console: 'readonly',
|
|
19
|
-
URL: 'readonly',
|
|
20
|
-
URLSearchParams: 'readonly',
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
plugins: {
|
|
24
|
-
'@typescript-eslint': tseslint,
|
|
25
|
-
},
|
|
26
|
-
rules: {
|
|
27
|
-
...tseslint.configs.recommended.rules,
|
|
28
|
-
'@typescript-eslint/no-unused-vars': [
|
|
29
|
-
'error',
|
|
30
|
-
{ argsIgnorePattern: '^_' },
|
|
31
|
-
],
|
|
32
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
33
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
34
|
-
'@typescript-eslint/no-empty-function': 'warn',
|
|
35
|
-
'prefer-const': 'error',
|
|
36
|
-
'no-var': 'error',
|
|
37
|
-
'no-console': 'off',
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
ignores: ['dist/', 'node_modules/', '*.js'],
|
|
42
|
-
},
|
|
43
|
-
];
|
package/src/Logger.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { init } from '@paralleldrive/cuid2';
|
|
2
|
-
import {
|
|
3
|
-
createRootLogEntry,
|
|
4
|
-
prettyError,
|
|
5
|
-
processProductionLogData,
|
|
6
|
-
} from './utils';
|
|
7
|
-
import type { LogData, LoggerOptions, LogEntry, LogEntryType } from './types';
|
|
8
|
-
|
|
9
|
-
export class Logger {
|
|
10
|
-
public eventId: string;
|
|
11
|
-
private log: LogData;
|
|
12
|
-
public parentEventId?: string;
|
|
13
|
-
private defaultArea: string;
|
|
14
|
-
|
|
15
|
-
constructor(options: LoggerOptions) {
|
|
16
|
-
this.parentEventId = options.parentEventId;
|
|
17
|
-
this.eventId =
|
|
18
|
-
options.overrideEventId ||
|
|
19
|
-
init({ fingerprint: options.details.service })();
|
|
20
|
-
this.defaultArea = options.defaultArea || 'defaultArea';
|
|
21
|
-
|
|
22
|
-
this.log = createRootLogEntry({
|
|
23
|
-
path: options.path || '/',
|
|
24
|
-
method: options.method,
|
|
25
|
-
details: options.details,
|
|
26
|
-
eventId: this.eventId,
|
|
27
|
-
parentEventId: options.parentEventId,
|
|
28
|
-
withParentEventId: options.withParentEventId,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private finalizeRootMessage() {
|
|
33
|
-
this.addMessage('root', 'info', 'Request completed', {
|
|
34
|
-
totalDuration: Date.now() - this.log.root[0].timestamp,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
private addMessage(
|
|
39
|
-
name: string,
|
|
40
|
-
type: LogEntryType,
|
|
41
|
-
message: string,
|
|
42
|
-
payload?: LogEntry['payload'] | Error
|
|
43
|
-
) {
|
|
44
|
-
const finalPayload =
|
|
45
|
-
payload instanceof Error ? prettyError(payload) : payload;
|
|
46
|
-
|
|
47
|
-
this.log[name]!.push({
|
|
48
|
-
type,
|
|
49
|
-
message,
|
|
50
|
-
payload: finalPayload,
|
|
51
|
-
timestamp: Date.now(),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Area function that returns area-specific logger methods
|
|
56
|
-
public getArea(name = this.defaultArea) {
|
|
57
|
-
if (!this.log[name]) {
|
|
58
|
-
this.log[name] = [];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
info: (message: string, payload?: LogEntry['payload']) => {
|
|
63
|
-
this.addMessage(name, 'info', message, payload);
|
|
64
|
-
},
|
|
65
|
-
warn: (message: string, payload?: LogEntry['payload']) => {
|
|
66
|
-
this.addMessage(name, 'warn', message, payload);
|
|
67
|
-
},
|
|
68
|
-
error: (message: string, payload?: LogEntry['payload'] | Error) => {
|
|
69
|
-
this.addMessage(name, 'error', message, payload);
|
|
70
|
-
},
|
|
71
|
-
log: (message: string, payload?: LogEntry['payload']) => {
|
|
72
|
-
this.addMessage(name, 'log', message, payload);
|
|
73
|
-
},
|
|
74
|
-
debug: (message: string, payload?: LogEntry['payload']) => {
|
|
75
|
-
this.addMessage(name, 'debug', message, payload);
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Public methods on main instance
|
|
81
|
-
public dump(): LogData {
|
|
82
|
-
this.finalizeRootMessage();
|
|
83
|
-
return this.log;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public dumpProduction(): LogData {
|
|
87
|
-
this.finalizeRootMessage();
|
|
88
|
-
return processProductionLogData(this.log);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public appendLogData(logData: LogData): void {
|
|
92
|
-
delete logData.root;
|
|
93
|
-
this.log = { ...logData, ...this.log };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Factory function for convenience
|
|
98
|
-
export const createLogger = (options: LoggerOptions): Logger => {
|
|
99
|
-
return new Logger(options);
|
|
100
|
-
};
|
package/src/index.ts
DELETED
package/src/types.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export type Details = { service: string } & Record<string, unknown>;
|
|
2
|
-
export type Method =
|
|
3
|
-
| 'get'
|
|
4
|
-
| 'post'
|
|
5
|
-
| 'put'
|
|
6
|
-
| 'delete'
|
|
7
|
-
| 'patch'
|
|
8
|
-
| 'head'
|
|
9
|
-
| 'options'
|
|
10
|
-
| 'trace'
|
|
11
|
-
| 'connect';
|
|
12
|
-
|
|
13
|
-
export type LogEntryType = 'info' | 'warn' | 'error' | 'log' | 'debug';
|
|
14
|
-
|
|
15
|
-
export type LogEntry = {
|
|
16
|
-
type: LogEntryType;
|
|
17
|
-
message: string;
|
|
18
|
-
payload?: object;
|
|
19
|
-
timestamp: number;
|
|
20
|
-
};
|
|
21
|
-
export type RootPayload = {
|
|
22
|
-
path?: string;
|
|
23
|
-
method?: Method;
|
|
24
|
-
eventId: string;
|
|
25
|
-
parentEventId?: string;
|
|
26
|
-
details: Details;
|
|
27
|
-
};
|
|
28
|
-
export type CreateRootLogEntryOptions = RootPayload & {
|
|
29
|
-
path?: string;
|
|
30
|
-
withParentEventId?: boolean;
|
|
31
|
-
};
|
|
32
|
-
export type LogData = Record<string, LogEntry[]>;
|
|
33
|
-
|
|
34
|
-
export interface LoggerOptions {
|
|
35
|
-
details: Details;
|
|
36
|
-
path?: string;
|
|
37
|
-
parentEventId?: string;
|
|
38
|
-
withParentEventId?: boolean;
|
|
39
|
-
method?: Method;
|
|
40
|
-
overrideEventId?: string;
|
|
41
|
-
defaultArea?: string;
|
|
42
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CreateRootLogEntryOptions,
|
|
3
|
-
LogData,
|
|
4
|
-
LogEntry,
|
|
5
|
-
RootPayload,
|
|
6
|
-
} from './types';
|
|
7
|
-
|
|
8
|
-
export const prettyStack = (stack?: string): string[] => {
|
|
9
|
-
if (!stack) return [];
|
|
10
|
-
let toReplace = '';
|
|
11
|
-
|
|
12
|
-
const regex = /file:\/\/\/(.*)(\.wrangler|node_modules)\/.*\)/gm;
|
|
13
|
-
const m = regex.exec(stack);
|
|
14
|
-
|
|
15
|
-
if (m && m.length > 1) {
|
|
16
|
-
toReplace = m[1];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return stack
|
|
20
|
-
.split('\n')
|
|
21
|
-
.map((line) => line.trim())
|
|
22
|
-
.filter((line) => !line.startsWith('Error: '))
|
|
23
|
-
.map((line) => line.replace(toReplace, ''))
|
|
24
|
-
.map((line) => line.replace('file://', ''));
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const prettyError = (err: Error) => {
|
|
28
|
-
const stack = prettyStack(err.stack);
|
|
29
|
-
const message = err.message;
|
|
30
|
-
return { message, stack };
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const createRootLogEntry = ({
|
|
34
|
-
path,
|
|
35
|
-
method,
|
|
36
|
-
details,
|
|
37
|
-
eventId,
|
|
38
|
-
parentEventId,
|
|
39
|
-
withParentEventId,
|
|
40
|
-
}: CreateRootLogEntryOptions): LogData => {
|
|
41
|
-
const url = new URL(`http://example.com${path ?? '/'}`);
|
|
42
|
-
|
|
43
|
-
const rootLogEntry: LogData = {
|
|
44
|
-
root: [
|
|
45
|
-
{
|
|
46
|
-
type: 'info',
|
|
47
|
-
message: 'Request received',
|
|
48
|
-
payload: {
|
|
49
|
-
path: `${url.pathname}${url.search}`,
|
|
50
|
-
method,
|
|
51
|
-
details,
|
|
52
|
-
eventId,
|
|
53
|
-
...(parentEventId && { parentEventId }),
|
|
54
|
-
} as RootPayload,
|
|
55
|
-
timestamp: Date.now(),
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
if (withParentEventId && !parentEventId) {
|
|
61
|
-
rootLogEntry.root.push({
|
|
62
|
-
type: 'error',
|
|
63
|
-
message: 'Parent event ID expected but not found',
|
|
64
|
-
timestamp: Date.now(),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return rootLogEntry;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const removeEmptyAreas = (logData: LogData) => {
|
|
72
|
-
const newLogData: LogData = {};
|
|
73
|
-
for (const [key, value] of Object.entries(logData)) {
|
|
74
|
-
if (value.length > 0) {
|
|
75
|
-
newLogData[key] = value;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return newLogData;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const excludeDebugLogs = (logEntries: LogEntry[]) => {
|
|
82
|
-
return logEntries.filter((entry) => entry.type !== 'debug');
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export const processProductionLogData = (logData: LogData) => {
|
|
86
|
-
const newLogData: LogData = {};
|
|
87
|
-
for (const [key, value] of Object.entries(logData)) {
|
|
88
|
-
if (key !== 'root') {
|
|
89
|
-
newLogData[key] = excludeDebugLogs(value);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return removeEmptyAreas(newLogData);
|
|
93
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ES2020", "dom"],
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"moduleResolution": "node",
|
|
14
|
-
"allowSyntheticDefaultImports": true,
|
|
15
|
-
"resolveJsonModule": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
19
|
-
}
|
package/tsup.config.ts
DELETED