@evdy-consumer/dailyom-suite-logging 0.0.2-dev.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/README.md +97 -0
- package/package.json +17 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +5 -0
- package/src/index.js.map +1 -0
- package/src/lib/logging.d.ts +31 -0
- package/src/lib/logging.js +154 -0
- package/src/lib/logging.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# DailyOM Logging Library
|
|
2
|
+
|
|
3
|
+
This library was generated with Nx.
|
|
4
|
+
|
|
5
|
+
The logging library provides a unified logging solution for Next.js and backend systems in the DailyOM Suite monorepo. It implements distributed tracing through trace and span IDs, allowing for correlation of logs across service boundaries.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
- **Trace Context Management**: Automatic generation and propagation of trace and span IDs
|
|
9
|
+
- **Hierarchical Spans**: Create child spans for tracking operations within a request
|
|
10
|
+
- **Configurable Output**: Log to console, files, or both
|
|
11
|
+
- **Daily Log Rotation**: Automated log file rotation with size thresholds
|
|
12
|
+
- **Context Preservation**: Maintains trace context across asynchronous operations using AsyncLocalStorage
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
Basic Logging
|
|
17
|
+
```typescript
|
|
18
|
+
import { TracedLogger } from '@dailyom-suite/logging';
|
|
19
|
+
|
|
20
|
+
// Create a logger instance
|
|
21
|
+
const logger = new TracedLogger({
|
|
22
|
+
name: 'my-service',
|
|
23
|
+
level: 'info', // Optional: default is 'info'
|
|
24
|
+
logToConsole: true, // Optional: default is true
|
|
25
|
+
logToFile: true, // Optional: default is true
|
|
26
|
+
fileName: 'app-name.log' // Optional: default uses name + timestamp
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Log messages with context
|
|
30
|
+
logger.info({ userId: '123' }, 'User logged in');
|
|
31
|
+
logger.error({ orderId: '456' }, 'Failed to process order');
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Trace Context and Spans
|
|
35
|
+
```typescript
|
|
36
|
+
// Create a traced operation
|
|
37
|
+
logger.withSpan('database-query', () => {
|
|
38
|
+
// All logs in this function will share the same trace context
|
|
39
|
+
logger.debug({ query: 'SELECT * FROM users' }, 'Executing query');
|
|
40
|
+
// ...
|
|
41
|
+
return result;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// For async operations
|
|
45
|
+
await logger.withSpanAsync('api-request', async () => {
|
|
46
|
+
logger.info({ url: '/api/data' }, 'Making API request');
|
|
47
|
+
const response = await fetch('/api/data');
|
|
48
|
+
logger.info({ status: response.status }, 'Received API response');
|
|
49
|
+
return response.json();
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Manual Trace Context Manipulation
|
|
54
|
+
```typescript
|
|
55
|
+
import {
|
|
56
|
+
createTraceContext,
|
|
57
|
+
createChildSpan,
|
|
58
|
+
traceContextStorage
|
|
59
|
+
} from '@dailyom-suite/logging';
|
|
60
|
+
|
|
61
|
+
// Create a new trace context
|
|
62
|
+
const context = createTraceContext();
|
|
63
|
+
|
|
64
|
+
// Create a child span from parent context
|
|
65
|
+
const childContext = createChildSpan(context);
|
|
66
|
+
|
|
67
|
+
// Run code with a specific trace context
|
|
68
|
+
traceContextStorage.run(context, () => {
|
|
69
|
+
// All logs in this scope will use this context
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
The library looks for the following environment variables:
|
|
75
|
+
|
|
76
|
+
- [LOG_DIR](src/lib/logging.ts): Directory where log files will be stored (defaults to ./logs)
|
|
77
|
+
|
|
78
|
+
## Log File Management
|
|
79
|
+
Log files follow this naming pattern:
|
|
80
|
+
```
|
|
81
|
+
{app-name}.{YYYY-MM-DD}.{HH-MM-SS}.log
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Files rotate:
|
|
85
|
+
|
|
86
|
+
- Every day (24 hours)
|
|
87
|
+
- When they exceed 10MB in size
|
|
88
|
+
|
|
89
|
+
## Building
|
|
90
|
+
Run `nx build logging` to build the library.
|
|
91
|
+
|
|
92
|
+
## Running unit tests
|
|
93
|
+
Run `nx test logging` to execute the unit tests via Jest.
|
|
94
|
+
|
|
95
|
+
## CI
|
|
96
|
+
|
|
97
|
+
PRs that contain changes to logging will run tests and builds to ensure project structure is adhered to
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evdy-consumer/dailyom-suite-logging",
|
|
3
|
+
"version": "0.0.2-dev.0",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"bunyan": "1.8.15",
|
|
9
|
+
"bunyan-rotating-file-stream": "2.0.6",
|
|
10
|
+
"tslib": "2.3.0",
|
|
11
|
+
"uuid": "11.1.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/bunyan": "1.8.11",
|
|
15
|
+
"@types/uuid": "10.0.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/logging';
|
package/src/index.js
ADDED
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/logging/src/index.ts"],"names":[],"mappings":";;;AAAA,wDAA8B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as bunyan from 'bunyan';
|
|
2
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
|
+
export interface TraceContext {
|
|
4
|
+
traceId: string;
|
|
5
|
+
spanId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createTraceContext(): TraceContext;
|
|
8
|
+
export declare function createChildSpan(parentContext: TraceContext): TraceContext;
|
|
9
|
+
export interface LoggerOptions {
|
|
10
|
+
name: string;
|
|
11
|
+
level?: bunyan.LogLevel;
|
|
12
|
+
logToConsole?: boolean;
|
|
13
|
+
logToFile?: boolean;
|
|
14
|
+
fileName?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function createLogger(options: LoggerOptions): bunyan;
|
|
17
|
+
export declare const traceContextStorage: AsyncLocalStorage<TraceContext>;
|
|
18
|
+
export declare function getCurrentTraceContext(): TraceContext;
|
|
19
|
+
export declare class TracedLogger {
|
|
20
|
+
private logger;
|
|
21
|
+
constructor(options: LoggerOptions);
|
|
22
|
+
private getLoggerWithContext;
|
|
23
|
+
trace(data: object, msg: string, ...args: any[]): void;
|
|
24
|
+
debug(data: object, msg: string, ...args: any[]): void;
|
|
25
|
+
info(data: object, msg: string, ...args: any[]): void;
|
|
26
|
+
warn(data: object, msg: string, ...args: any[]): void;
|
|
27
|
+
error(data: object, msg: string, ...args: any[]): void;
|
|
28
|
+
fatal(data: object, msg: string, ...args: any[]): void;
|
|
29
|
+
withSpan<T>(name: string, fn: () => T): T;
|
|
30
|
+
withSpanAsync<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TracedLogger = exports.traceContextStorage = void 0;
|
|
4
|
+
exports.createTraceContext = createTraceContext;
|
|
5
|
+
exports.createChildSpan = createChildSpan;
|
|
6
|
+
exports.createLogger = createLogger;
|
|
7
|
+
exports.getCurrentTraceContext = getCurrentTraceContext;
|
|
8
|
+
const bunyan = require("bunyan");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const uuid_1 = require("uuid");
|
|
12
|
+
const async_hooks_1 = require("async_hooks");
|
|
13
|
+
const RotatingFileStream = require('bunyan-rotating-file-stream');
|
|
14
|
+
const LOG_DIR = process.env["LOG_DIR"] || path.join(process.cwd(), 'logs');
|
|
15
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
16
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
function createTraceContext() {
|
|
19
|
+
return {
|
|
20
|
+
traceId: (0, uuid_1.v4)(),
|
|
21
|
+
spanId: (0, uuid_1.v4)(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createChildSpan(parentContext) {
|
|
25
|
+
return {
|
|
26
|
+
traceId: parentContext.traceId,
|
|
27
|
+
spanId: (0, uuid_1.v4)()
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//Returns formatted date in the format YYYY-MM-DD.
|
|
31
|
+
function getFormattedDate() {
|
|
32
|
+
return new Date().toISOString().split('T')[0];
|
|
33
|
+
}
|
|
34
|
+
// Returns formatted time in the format HH-MM-SS.
|
|
35
|
+
function getFormattedTime() {
|
|
36
|
+
return new Date().toTimeString().split(' ')[0].replace(/:/g, '-');
|
|
37
|
+
}
|
|
38
|
+
// Generate formatted date and time
|
|
39
|
+
const formattedDate = getFormattedDate();
|
|
40
|
+
const formattedTime = getFormattedTime();
|
|
41
|
+
function createLogger(options) {
|
|
42
|
+
const streams = [];
|
|
43
|
+
// mainly for development purposes but can be used in production as well
|
|
44
|
+
if (options.logToConsole !== false) {
|
|
45
|
+
streams.push({
|
|
46
|
+
level: options.level || 'info',
|
|
47
|
+
stream: process.stdout,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (options.logToFile !== false) {
|
|
51
|
+
const fileName = `${options.name}.${formattedDate}.${formattedTime}.log`;
|
|
52
|
+
streams.push({
|
|
53
|
+
type: 'raw',
|
|
54
|
+
level: options.level || 'info',
|
|
55
|
+
stream: new RotatingFileStream({
|
|
56
|
+
path: path.join(LOG_DIR, fileName),
|
|
57
|
+
period: '1d', // daily rotation
|
|
58
|
+
rotateExisting: true, // Give ourselves a clean file when we start up, based on period
|
|
59
|
+
threshold: '10m', // Rotate log files larger than 10 megabytes
|
|
60
|
+
}), // Type mismatch with Bunyan
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return bunyan.createLogger({
|
|
64
|
+
name: options.name,
|
|
65
|
+
streams,
|
|
66
|
+
serializers: bunyan.stdSerializers,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
exports.traceContextStorage = new async_hooks_1.AsyncLocalStorage();
|
|
70
|
+
// Get current trace context or create a new one
|
|
71
|
+
function getCurrentTraceContext() {
|
|
72
|
+
const context = exports.traceContextStorage.getStore();
|
|
73
|
+
if (context) {
|
|
74
|
+
return context;
|
|
75
|
+
}
|
|
76
|
+
return createTraceContext();
|
|
77
|
+
}
|
|
78
|
+
class TracedLogger {
|
|
79
|
+
logger;
|
|
80
|
+
constructor(options) {
|
|
81
|
+
this.logger = createLogger(options);
|
|
82
|
+
}
|
|
83
|
+
getLoggerWithContext() {
|
|
84
|
+
const traceContext = getCurrentTraceContext();
|
|
85
|
+
return this.logger.child({
|
|
86
|
+
traceId: traceContext.traceId,
|
|
87
|
+
spanId: traceContext.spanId
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
trace(data, msg, ...args) {
|
|
91
|
+
this.getLoggerWithContext().trace({ ...data }, msg, ...args);
|
|
92
|
+
}
|
|
93
|
+
debug(data, msg, ...args) {
|
|
94
|
+
this.getLoggerWithContext().debug({ ...data }, msg, ...args);
|
|
95
|
+
}
|
|
96
|
+
info(data, msg, ...args) {
|
|
97
|
+
this.getLoggerWithContext().info({ ...data }, msg, ...args);
|
|
98
|
+
}
|
|
99
|
+
warn(data, msg, ...args) {
|
|
100
|
+
this.getLoggerWithContext().warn({ ...data }, msg, ...args);
|
|
101
|
+
}
|
|
102
|
+
error(data, msg, ...args) {
|
|
103
|
+
this.getLoggerWithContext().error({ ...data }, msg, ...args);
|
|
104
|
+
}
|
|
105
|
+
fatal(data, msg, ...args) {
|
|
106
|
+
this.getLoggerWithContext().fatal({ ...data }, msg, ...args);
|
|
107
|
+
}
|
|
108
|
+
// Create a new span and run function within it
|
|
109
|
+
withSpan(name, fn) {
|
|
110
|
+
const currentContext = getCurrentTraceContext();
|
|
111
|
+
const spanContext = createChildSpan(currentContext);
|
|
112
|
+
const spanLogger = this.logger.child({
|
|
113
|
+
traceId: spanContext.traceId,
|
|
114
|
+
spanId: spanContext.spanId,
|
|
115
|
+
operation: name,
|
|
116
|
+
});
|
|
117
|
+
spanLogger.debug(`Starting span: ${name}`);
|
|
118
|
+
return exports.traceContextStorage.run(spanContext, () => {
|
|
119
|
+
try {
|
|
120
|
+
const result = fn();
|
|
121
|
+
spanLogger.debug(`Completed span: ${name}`);
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
spanLogger.error({ err: error }, `Error in span: ${name}`);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Create a new span and run async function within it
|
|
131
|
+
async withSpanAsync(name, fn) {
|
|
132
|
+
const currentContext = getCurrentTraceContext();
|
|
133
|
+
const spanContext = createChildSpan(currentContext);
|
|
134
|
+
const spanLogger = this.logger.child({
|
|
135
|
+
traceId: spanContext.traceId,
|
|
136
|
+
spanId: spanContext.spanId,
|
|
137
|
+
operation: name,
|
|
138
|
+
});
|
|
139
|
+
spanLogger.debug(`Starting span: ${name}`);
|
|
140
|
+
return exports.traceContextStorage.run(spanContext, async () => {
|
|
141
|
+
try {
|
|
142
|
+
const result = await fn();
|
|
143
|
+
spanLogger.debug(`Completed span: ${name}`);
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
spanLogger.error({ err: error }, `Error in span: ${name}`);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.TracedLogger = TracedLogger;
|
|
154
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../../../../libs/logging/src/lib/logging.ts"],"names":[],"mappings":"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"}
|