hierarchical-area-logger 0.2.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/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/CONTRIBUTING.md +313 -0
- package/LICENSE.md +21 -0
- package/README.md +120 -0
- package/dist/index.cjs +145 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +43 -0
- package/package.json +60 -0
- package/src/Logger.ts +72 -0
- package/src/index.ts +2 -0
- package/src/types.ts +38 -0
- package/src/utils.ts +64 -0
- package/test/logger.test.ts +136 -0
- package/test/utils.test.ts +453 -0
- package/tsconfig.json +19 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +8 -0
package/.prettierignore
ADDED
package/.prettierrc
ADDED
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
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/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Roman Jankowski
|
|
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,120 @@
|
|
|
1
|
+
# 🌲 Hierarchical Area Logger
|
|
2
|
+
|
|
3
|
+
A lightweight, structured logging utility for TypeScript applications. It allows you to scope logs to specific **Areas**, track request flows via **Event IDs**, and **dump** the entire execution history for debugging or monitoring.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **Scoped Logging:** Group logs by logical "areas" (e.g., `db-layer`, `auth-service`).
|
|
8
|
+
- **Traceability:** Automatic Event ID generation and Parent Event ID mapping for distributed tracing.
|
|
9
|
+
- **Structured Payloads:** Log rich objects and Error instances without losing metadata.
|
|
10
|
+
- **Snapshot Dumping:** Retrieve the entire log state at any time for analysis or reporting.
|
|
11
|
+
- **Lightweight:** Designed to be dependency-lite and predictable.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🛠 Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install hierarchical-area-logger
|
|
19
|
+
# or
|
|
20
|
+
yarn add hierarchical-area-logger
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 💡 Functionality Showcase
|
|
27
|
+
|
|
28
|
+
### 1. Basic Scoped Logging
|
|
29
|
+
|
|
30
|
+
Instead of a flat stream of text, the logger categorizes logs into logical areas.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createLogger } from 'hierarchical-area-logger';
|
|
34
|
+
|
|
35
|
+
const logger = createLogger({
|
|
36
|
+
details: { service: 'payment-gateway' },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const checkout = logger.getArea('checkout-process');
|
|
40
|
+
|
|
41
|
+
checkout.info('User started checkout');
|
|
42
|
+
checkout.warn('Retry attempt 1 for payment');
|
|
43
|
+
checkout.error('Transaction failed', new Error('Timeout'));
|
|
44
|
+
|
|
45
|
+
// View the structured output
|
|
46
|
+
console.log(logger.dump());
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Request Traceability
|
|
50
|
+
|
|
51
|
+
Track a request across your system by linking `eventId` and `parentEventId`.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const logger = createLogger({
|
|
55
|
+
details: { service: 'payment-gateway' }
|
|
56
|
+
path: '/api/v1/user',
|
|
57
|
+
parentEventId: 'incoming-request-id-001'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
console.log(logger.eventId); // Automatically generated unique ID
|
|
61
|
+
console.log(logger.parentEventId); // 'incoming-request-id-001'
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Log Merging & State Management
|
|
66
|
+
|
|
67
|
+
You can append existing log data to a logger instance, which is useful for consolidating logs from multiple micro-tasks.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const mainLogger = createLogger({ details: { service: 'orchestrator' } });
|
|
71
|
+
|
|
72
|
+
const externalLogs = {
|
|
73
|
+
'worker-1': [
|
|
74
|
+
{ type: 'info', message: 'Task complete', timestamp: Date.now() },
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
mainLogger.appendLogData(externalLogs);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 📖 API Reference
|
|
84
|
+
|
|
85
|
+
### `createLogger(options)`
|
|
86
|
+
|
|
87
|
+
Factory function to initialize a new Logger instance.
|
|
88
|
+
|
|
89
|
+
| Option | Type | Description |
|
|
90
|
+
| --------------- | --------- | ------------------------------------------ |
|
|
91
|
+
| `details` | `Details` | Metadata about the service or environment. |
|
|
92
|
+
| `path` | `string` | (Optional) The execution path/route. |
|
|
93
|
+
| `parentEventId` | `string` | (Optional) ID of the triggering event. |
|
|
94
|
+
|
|
95
|
+
### `LoggerInstance` Methods
|
|
96
|
+
|
|
97
|
+
- **`getArea(name: string)`**: Returns a scoped logger for a specific logic block.
|
|
98
|
+
- `.info(msg, payload?)`
|
|
99
|
+
- `.warn(msg, payload?)`
|
|
100
|
+
- `.error(msg, error?)`
|
|
101
|
+
|
|
102
|
+
- **`dump()`**: Returns an object containing all logs indexed by their area names.
|
|
103
|
+
- **`appendLogData(data)`**: Manually injects log entries into the current instance.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 🧪 Development & Testing
|
|
108
|
+
|
|
109
|
+
This project uses **Vitest** for unit testing.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Run tests
|
|
113
|
+
npm test
|
|
114
|
+
|
|
115
|
+
# Run tests with coverage
|
|
116
|
+
npm run coverage
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> **Note:** The logger automatically creates a `root` area log entry labeled "Request received" if a `path` is provided during initialization.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Logger: () => Logger,
|
|
24
|
+
createLogger: () => createLogger
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/Logger.ts
|
|
29
|
+
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
30
|
+
|
|
31
|
+
// src/utils.ts
|
|
32
|
+
var prettyStack = (stack) => {
|
|
33
|
+
if (!stack) return [];
|
|
34
|
+
let toReplace = "";
|
|
35
|
+
const regex = /file:\/\/\/(.*)(\.wrangler|node_modules)\/.*\)/gm;
|
|
36
|
+
const m = regex.exec(stack);
|
|
37
|
+
if (m && m.length > 1) {
|
|
38
|
+
toReplace = m[1];
|
|
39
|
+
}
|
|
40
|
+
return stack.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("Error: ")).map((line) => line.replace(toReplace, "")).map((line) => line.replace("file://", ""));
|
|
41
|
+
};
|
|
42
|
+
var prettyError = (err) => {
|
|
43
|
+
const stack = prettyStack(err.stack);
|
|
44
|
+
const message = err.message;
|
|
45
|
+
return { message, stack };
|
|
46
|
+
};
|
|
47
|
+
var createRootLogEntry = ({
|
|
48
|
+
path,
|
|
49
|
+
method,
|
|
50
|
+
details,
|
|
51
|
+
eventId,
|
|
52
|
+
parentEventId,
|
|
53
|
+
withParentEventId
|
|
54
|
+
}) => {
|
|
55
|
+
const url = new URL(`http://example.com${path ?? "/"}`);
|
|
56
|
+
const rootLogEntry = {
|
|
57
|
+
root: [
|
|
58
|
+
{
|
|
59
|
+
type: "info",
|
|
60
|
+
message: "Request received",
|
|
61
|
+
payload: {
|
|
62
|
+
path: `${url.pathname}${url.search}`,
|
|
63
|
+
method,
|
|
64
|
+
details,
|
|
65
|
+
eventId,
|
|
66
|
+
...parentEventId && { parentEventId }
|
|
67
|
+
},
|
|
68
|
+
timestamp: Date.now()
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
};
|
|
72
|
+
if (withParentEventId && !parentEventId) {
|
|
73
|
+
rootLogEntry.root.push({
|
|
74
|
+
type: "error",
|
|
75
|
+
message: "Parent event ID expected but not found",
|
|
76
|
+
timestamp: Date.now()
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return rootLogEntry;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/Logger.ts
|
|
83
|
+
var Logger = class {
|
|
84
|
+
constructor(options) {
|
|
85
|
+
this.parentEventId = options.parentEventId;
|
|
86
|
+
this.eventId = (0, import_cuid2.init)({ fingerprint: options.details.service })();
|
|
87
|
+
this.log = createRootLogEntry({
|
|
88
|
+
path: options.path || "/",
|
|
89
|
+
method: options.method,
|
|
90
|
+
details: options.details,
|
|
91
|
+
eventId: this.eventId,
|
|
92
|
+
parentEventId: options.parentEventId,
|
|
93
|
+
withParentEventId: options.withParentEventId
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Area function that returns area-specific logger methods
|
|
97
|
+
getArea(name = "dummy") {
|
|
98
|
+
if (!this.log[name]) {
|
|
99
|
+
this.log[name] = [];
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
info: (message, payload) => {
|
|
103
|
+
this.log[name].push({
|
|
104
|
+
type: "info",
|
|
105
|
+
message,
|
|
106
|
+
payload,
|
|
107
|
+
timestamp: Date.now()
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
warn: (message, payload) => {
|
|
111
|
+
this.log[name].push({
|
|
112
|
+
type: "warn",
|
|
113
|
+
message,
|
|
114
|
+
payload,
|
|
115
|
+
timestamp: Date.now()
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
error: (message, payload) => {
|
|
119
|
+
this.log[name].push({
|
|
120
|
+
type: "error",
|
|
121
|
+
message,
|
|
122
|
+
payload: payload instanceof Error ? prettyError(payload) : payload,
|
|
123
|
+
timestamp: Date.now()
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Public methods on main instance
|
|
129
|
+
dump() {
|
|
130
|
+
return this.log;
|
|
131
|
+
}
|
|
132
|
+
appendLogData(logData) {
|
|
133
|
+
delete logData.root;
|
|
134
|
+
this.log = { ...logData, ...this.log };
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var createLogger = (options) => {
|
|
138
|
+
return new Logger(options);
|
|
139
|
+
};
|
|
140
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
141
|
+
0 && (module.exports = {
|
|
142
|
+
Logger,
|
|
143
|
+
createLogger
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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 = 'dummy') {\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
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type Details = {
|
|
2
|
+
service: string;
|
|
3
|
+
} & Record<string, unknown>;
|
|
4
|
+
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace' | 'connect';
|
|
5
|
+
type LogEntry = {
|
|
6
|
+
type: 'info' | 'warn' | 'error';
|
|
7
|
+
message: string;
|
|
8
|
+
payload?: object;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
};
|
|
11
|
+
type LogData = Record<string, LogEntry[]>;
|
|
12
|
+
interface LoggerOptions {
|
|
13
|
+
details: Details;
|
|
14
|
+
path?: string;
|
|
15
|
+
parentEventId?: string;
|
|
16
|
+
withParentEventId?: boolean;
|
|
17
|
+
method?: Method;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare class Logger {
|
|
21
|
+
eventId: string;
|
|
22
|
+
private log;
|
|
23
|
+
parentEventId?: string;
|
|
24
|
+
constructor(options: LoggerOptions);
|
|
25
|
+
getArea(name?: string): {
|
|
26
|
+
info: (message: string, payload?: LogEntry["payload"]) => void;
|
|
27
|
+
warn: (message: string, payload?: LogEntry["payload"]) => void;
|
|
28
|
+
error: (message: string, payload?: LogEntry["payload"] | Error) => void;
|
|
29
|
+
};
|
|
30
|
+
dump(): LogData;
|
|
31
|
+
appendLogData(logData: LogData): void;
|
|
32
|
+
}
|
|
33
|
+
declare const createLogger: (options: LoggerOptions) => Logger;
|
|
34
|
+
|
|
35
|
+
export { type LogData, type LogEntry, Logger, createLogger };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type Details = {
|
|
2
|
+
service: string;
|
|
3
|
+
} & Record<string, unknown>;
|
|
4
|
+
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace' | 'connect';
|
|
5
|
+
type LogEntry = {
|
|
6
|
+
type: 'info' | 'warn' | 'error';
|
|
7
|
+
message: string;
|
|
8
|
+
payload?: object;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
};
|
|
11
|
+
type LogData = Record<string, LogEntry[]>;
|
|
12
|
+
interface LoggerOptions {
|
|
13
|
+
details: Details;
|
|
14
|
+
path?: string;
|
|
15
|
+
parentEventId?: string;
|
|
16
|
+
withParentEventId?: boolean;
|
|
17
|
+
method?: Method;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare class Logger {
|
|
21
|
+
eventId: string;
|
|
22
|
+
private log;
|
|
23
|
+
parentEventId?: string;
|
|
24
|
+
constructor(options: LoggerOptions);
|
|
25
|
+
getArea(name?: string): {
|
|
26
|
+
info: (message: string, payload?: LogEntry["payload"]) => void;
|
|
27
|
+
warn: (message: string, payload?: LogEntry["payload"]) => void;
|
|
28
|
+
error: (message: string, payload?: LogEntry["payload"] | Error) => void;
|
|
29
|
+
};
|
|
30
|
+
dump(): LogData;
|
|
31
|
+
appendLogData(logData: LogData): void;
|
|
32
|
+
}
|
|
33
|
+
declare const createLogger: (options: LoggerOptions) => Logger;
|
|
34
|
+
|
|
35
|
+
export { type LogData, type LogEntry, Logger, createLogger };
|