unnbound-logger-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +312 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +29 -0
- package/dist/src/index.d.ts +38 -0
- package/dist/src/index.js +29 -0
- package/dist/src/types.d.ts +134 -0
- package/dist/src/types.js +5 -0
- package/dist/src/unnbound-logger.d.ts +105 -0
- package/dist/src/unnbound-logger.js +292 -0
- package/dist/src/utils/id-generator.d.ts +21 -0
- package/dist/src/utils/id-generator.js +46 -0
- package/dist/src/utils/logger-utils.d.ts +21 -0
- package/dist/src/utils/logger-utils.js +63 -0
- package/dist/src/utils/trace-context.d.ts +10 -0
- package/dist/src/utils/trace-context.js +23 -0
- package/dist/src/utils/with-trace.d.ts +7 -0
- package/dist/src/utils/with-trace.js +17 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.js +5 -0
- package/dist/unnbound-logger.d.ts +105 -0
- package/dist/unnbound-logger.js +292 -0
- package/dist/utils/id-generator.d.ts +21 -0
- package/dist/utils/id-generator.js +46 -0
- package/dist/utils/logger-utils.d.ts +21 -0
- package/dist/utils/logger-utils.js +63 -0
- package/dist/utils/trace-context.d.ts +10 -0
- package/dist/utils/trace-context.js +23 -0
- package/dist/utils/with-trace.d.ts +7 -0
- package/dist/utils/with-trace.js +17 -0
- package/package.json +90 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for structured logging library
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Available log levels
|
|
6
|
+
*/
|
|
7
|
+
export type LogLevel = "info" | "debug" | "error" | "warn";
|
|
8
|
+
/**
|
|
9
|
+
* Available log types
|
|
10
|
+
*/
|
|
11
|
+
export type LogType = "general" | "httpRequest" | "httpResponse" | "sftpTransaction" | "dbQueryTransaction";
|
|
12
|
+
/**
|
|
13
|
+
* HTTP methods supported for HTTP logging
|
|
14
|
+
*/
|
|
15
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD';
|
|
16
|
+
export interface SerializableError {
|
|
17
|
+
name: string;
|
|
18
|
+
message: string;
|
|
19
|
+
stack?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Log<T extends LogType = 'general'> {
|
|
22
|
+
level: LogLevel;
|
|
23
|
+
type: T;
|
|
24
|
+
message: string;
|
|
25
|
+
traceId: string;
|
|
26
|
+
requestId: string;
|
|
27
|
+
error?: SerializableError;
|
|
28
|
+
}
|
|
29
|
+
export interface LogTransaction<T extends LogType> extends Log<T> {
|
|
30
|
+
duration: number;
|
|
31
|
+
}
|
|
32
|
+
export interface HttpRequestLog extends LogTransaction<'httpRequest'> {
|
|
33
|
+
httpRequest: {
|
|
34
|
+
url: string;
|
|
35
|
+
method: string;
|
|
36
|
+
headers: Record<string, string>;
|
|
37
|
+
ip?: string;
|
|
38
|
+
body?: unknown;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface HttpResponseLog extends LogTransaction<'httpResponse'> {
|
|
42
|
+
httpResponse: {
|
|
43
|
+
url: string;
|
|
44
|
+
method: string;
|
|
45
|
+
headers: Record<string, string>;
|
|
46
|
+
ip?: string;
|
|
47
|
+
status: number;
|
|
48
|
+
body?: unknown;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface SftpTransactionLog extends LogTransaction<'sftpTransaction'> {
|
|
52
|
+
sftp: {
|
|
53
|
+
host: string;
|
|
54
|
+
username: string;
|
|
55
|
+
operation: 'upload' | 'download' | 'list' | 'delete' | 'rename' | 'stat';
|
|
56
|
+
path: string;
|
|
57
|
+
status: 'success' | 'failure';
|
|
58
|
+
bytesTransferred?: number;
|
|
59
|
+
filesListed?: number;
|
|
60
|
+
sourcePath?: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface DbQueryTransactionLog extends LogTransaction<'dbQueryTransaction'> {
|
|
64
|
+
db: {
|
|
65
|
+
instance: string;
|
|
66
|
+
vendor: 'postgres' | 'mysql' | 'mssql' | 'mongodb';
|
|
67
|
+
query?: string;
|
|
68
|
+
status: 'success' | 'failure';
|
|
69
|
+
rowsReturned?: number;
|
|
70
|
+
rowsAffected?: number;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Configuration options for the logger
|
|
75
|
+
*/
|
|
76
|
+
export interface LoggerOptions {
|
|
77
|
+
/** Default log level */
|
|
78
|
+
defaultLevel?: LogLevel;
|
|
79
|
+
/** Optional service name to include in logs */
|
|
80
|
+
serviceName?: string;
|
|
81
|
+
/** Optional environment name to include in logs */
|
|
82
|
+
environment?: string;
|
|
83
|
+
/** Optional trace header key */
|
|
84
|
+
traceHeaderKey?: string;
|
|
85
|
+
/** Routes to ignore in trace middleware (supports glob patterns) */
|
|
86
|
+
ignoreTraceRoutes?: string[];
|
|
87
|
+
/** Routes to ignore in axios trace middleware (supports glob patterns) */
|
|
88
|
+
ignoreAxiosTraceRoutes?: string[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Options for general logs
|
|
92
|
+
*/
|
|
93
|
+
export interface GeneralLogOptions {
|
|
94
|
+
/** Log level override */
|
|
95
|
+
level?: LogLevel;
|
|
96
|
+
/** Custom trace ID */
|
|
97
|
+
traceId?: string;
|
|
98
|
+
/** Custom request ID */
|
|
99
|
+
requestId?: string;
|
|
100
|
+
/** Custom metadata */
|
|
101
|
+
[key: string]: unknown;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Options for HTTP request logs
|
|
105
|
+
*/
|
|
106
|
+
export interface HttpRequestLogOptions extends GeneralLogOptions {
|
|
107
|
+
/** Start time of the request for duration calculation */
|
|
108
|
+
startTime?: number;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Options for HTTP response logs
|
|
112
|
+
*/
|
|
113
|
+
export interface HttpResponseLogOptions extends HttpRequestLogOptions {
|
|
114
|
+
/** Duration of the request in milliseconds */
|
|
115
|
+
duration?: number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Options for SFTP transaction logs
|
|
119
|
+
*/
|
|
120
|
+
export interface SftpTransactionLogOptions extends GeneralLogOptions {
|
|
121
|
+
/** Start time of the transaction for duration calculation */
|
|
122
|
+
startTime?: number;
|
|
123
|
+
/** Duration of the transaction in milliseconds */
|
|
124
|
+
duration?: number;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Options for database query transaction logs
|
|
128
|
+
*/
|
|
129
|
+
export interface DbQueryTransactionLogOptions extends GeneralLogOptions {
|
|
130
|
+
/** Start time of the query for duration calculation */
|
|
131
|
+
startTime?: number;
|
|
132
|
+
/** Duration of the query in milliseconds */
|
|
133
|
+
duration?: number;
|
|
134
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { LogLevel, LoggerOptions, GeneralLogOptions, HttpRequestLogOptions, HttpResponseLogOptions, SftpTransactionLogOptions, DbQueryTransactionLogOptions } from './types';
|
|
2
|
+
import { Request, Response, NextFunction } from 'express';
|
|
3
|
+
import { InternalAxiosRequestConfig } from 'axios';
|
|
4
|
+
/**
|
|
5
|
+
* UnnboundLogger provides typed, structured logging using Pino
|
|
6
|
+
*/
|
|
7
|
+
export declare class UnnboundLogger {
|
|
8
|
+
private logger;
|
|
9
|
+
private defaultLevel;
|
|
10
|
+
private serviceName?;
|
|
11
|
+
private environment?;
|
|
12
|
+
private traceHeaderKey;
|
|
13
|
+
private ignoreTraceRoutes;
|
|
14
|
+
private ignoreAxiosTraceRoutes;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new UnnboundLogger instance
|
|
17
|
+
* @param options - Configuration options for the logger
|
|
18
|
+
*/
|
|
19
|
+
constructor(options?: LoggerOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a path matches any of the ignore patterns
|
|
22
|
+
* @param path - The path to check
|
|
23
|
+
* @param patterns - Array of glob patterns to match against
|
|
24
|
+
* @returns boolean indicating if the path should be ignored
|
|
25
|
+
*/
|
|
26
|
+
private shouldIgnorePath;
|
|
27
|
+
/**
|
|
28
|
+
* Logs a general message
|
|
29
|
+
* @param level - Log level
|
|
30
|
+
* @param message - Log message
|
|
31
|
+
* @param options - Additional logging options
|
|
32
|
+
*/
|
|
33
|
+
log(level: LogLevel, message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
34
|
+
/**
|
|
35
|
+
* Logs an error message
|
|
36
|
+
* @param message - Error message or object
|
|
37
|
+
* @param options - Additional logging options
|
|
38
|
+
*/
|
|
39
|
+
error(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
40
|
+
/**
|
|
41
|
+
* Logs a warning message
|
|
42
|
+
* @param message - Warning message
|
|
43
|
+
* @param options - Additional logging options
|
|
44
|
+
*/
|
|
45
|
+
warn(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
46
|
+
/**
|
|
47
|
+
* Logs an info message
|
|
48
|
+
* @param message - Info message
|
|
49
|
+
* @param options - Additional logging options
|
|
50
|
+
*/
|
|
51
|
+
info(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
52
|
+
/**
|
|
53
|
+
* Logs a debug message
|
|
54
|
+
* @param message - Debug message
|
|
55
|
+
* @param options - Additional logging options
|
|
56
|
+
*/
|
|
57
|
+
debug(message: string | Error | Record<string, unknown>, options?: GeneralLogOptions): void;
|
|
58
|
+
/**
|
|
59
|
+
* Logs an HTTP request
|
|
60
|
+
* @param req - Express request object
|
|
61
|
+
* @param options - Additional logging options
|
|
62
|
+
* @returns The request ID for correlating with the response
|
|
63
|
+
*/
|
|
64
|
+
httpRequest(req: Request, options?: HttpRequestLogOptions): string;
|
|
65
|
+
/**
|
|
66
|
+
* Logs an HTTP response
|
|
67
|
+
* @param res - Express response object
|
|
68
|
+
* @param req - Express request object
|
|
69
|
+
* @param options - Additional logging options
|
|
70
|
+
*/
|
|
71
|
+
httpResponse(res: Response, req: Request, options?: HttpResponseLogOptions): void;
|
|
72
|
+
/**
|
|
73
|
+
* Logs an SFTP transaction
|
|
74
|
+
* @param operation - SFTP operation details
|
|
75
|
+
* @param options - Additional logging options
|
|
76
|
+
*/
|
|
77
|
+
sftpTransaction(operation: {
|
|
78
|
+
host: string;
|
|
79
|
+
username: string;
|
|
80
|
+
operation: 'upload' | 'download' | 'list' | 'delete' | 'rename' | 'stat';
|
|
81
|
+
path: string;
|
|
82
|
+
status: 'success' | 'failure';
|
|
83
|
+
bytesTransferred?: number;
|
|
84
|
+
filesListed?: number;
|
|
85
|
+
sourcePath?: string;
|
|
86
|
+
}, options?: SftpTransactionLogOptions): void;
|
|
87
|
+
/**
|
|
88
|
+
* Logs a database query transaction
|
|
89
|
+
* @param query - Database query details
|
|
90
|
+
* @param options - Additional logging options
|
|
91
|
+
*/
|
|
92
|
+
dbQueryTransaction(query: {
|
|
93
|
+
instance: string;
|
|
94
|
+
vendor: 'postgres' | 'mysql' | 'mssql' | 'mongodb';
|
|
95
|
+
query?: string;
|
|
96
|
+
status: 'success' | 'failure';
|
|
97
|
+
rowsReturned?: number;
|
|
98
|
+
rowsAffected?: number;
|
|
99
|
+
}, options?: DbQueryTransactionLogOptions): void;
|
|
100
|
+
traceMiddleware: (req: Request, res: Response, next: NextFunction) => void;
|
|
101
|
+
axiosTraceMiddleware: {
|
|
102
|
+
onFulfilled: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
|
|
103
|
+
onRejected: (error: any) => any;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UnnboundLogger = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Core logger implementation
|
|
9
|
+
*/
|
|
10
|
+
const pino_1 = __importDefault(require("pino"));
|
|
11
|
+
const id_generator_1 = require("./utils/id-generator");
|
|
12
|
+
const logger_utils_1 = require("./utils/logger-utils");
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const trace_context_1 = require("./utils/trace-context");
|
|
15
|
+
const axios_1 = require("axios");
|
|
16
|
+
/**
|
|
17
|
+
* UnnboundLogger provides typed, structured logging using Pino
|
|
18
|
+
*/
|
|
19
|
+
class UnnboundLogger {
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new UnnboundLogger instance
|
|
22
|
+
* @param options - Configuration options for the logger
|
|
23
|
+
*/
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
// Trace middleware
|
|
26
|
+
this.traceMiddleware = (req, res, next) => {
|
|
27
|
+
// Check if the route should be ignored
|
|
28
|
+
if (this.shouldIgnorePath(req.path, this.ignoreTraceRoutes)) {
|
|
29
|
+
return next();
|
|
30
|
+
}
|
|
31
|
+
const traceId = req.header(this.traceHeaderKey) || (0, uuid_1.v4)();
|
|
32
|
+
res.setHeader(this.traceHeaderKey, traceId);
|
|
33
|
+
trace_context_1.traceContext.run(traceId, () => {
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
// Axios trace middleware
|
|
38
|
+
this.axiosTraceMiddleware = {
|
|
39
|
+
onFulfilled: (config) => {
|
|
40
|
+
// Check if the URL should be ignored
|
|
41
|
+
if (config.url && this.shouldIgnorePath(config.url, this.ignoreAxiosTraceRoutes)) {
|
|
42
|
+
return config;
|
|
43
|
+
}
|
|
44
|
+
const traceId = trace_context_1.traceContext.getTraceId();
|
|
45
|
+
if (traceId) {
|
|
46
|
+
const headers = new axios_1.AxiosHeaders(config.headers);
|
|
47
|
+
headers.set(this.traceHeaderKey, traceId);
|
|
48
|
+
config.headers = headers;
|
|
49
|
+
}
|
|
50
|
+
return config;
|
|
51
|
+
},
|
|
52
|
+
onRejected: (error) => {
|
|
53
|
+
return Promise.reject(error);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
this.defaultLevel = options.defaultLevel || 'info';
|
|
57
|
+
this.serviceName = options.serviceName;
|
|
58
|
+
this.environment = options.environment;
|
|
59
|
+
this.traceHeaderKey = options.traceHeaderKey || 'unnbound-trace-id';
|
|
60
|
+
this.ignoreTraceRoutes = options.ignoreTraceRoutes || [];
|
|
61
|
+
this.ignoreAxiosTraceRoutes = options.ignoreAxiosTraceRoutes || [];
|
|
62
|
+
// Create Pino logger
|
|
63
|
+
this.logger = (0, pino_1.default)({
|
|
64
|
+
level: this.defaultLevel,
|
|
65
|
+
base: {
|
|
66
|
+
...(this.serviceName && { service: this.serviceName }),
|
|
67
|
+
...(this.environment && { environment: this.environment }),
|
|
68
|
+
},
|
|
69
|
+
formatters: {
|
|
70
|
+
level: (label) => {
|
|
71
|
+
return { level: label };
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a path matches any of the ignore patterns
|
|
79
|
+
* @param path - The path to check
|
|
80
|
+
* @param patterns - Array of glob patterns to match against
|
|
81
|
+
* @returns boolean indicating if the path should be ignored
|
|
82
|
+
*/
|
|
83
|
+
shouldIgnorePath(path, patterns) {
|
|
84
|
+
return patterns.some(pattern => {
|
|
85
|
+
// Convert glob pattern to regex
|
|
86
|
+
const regexPattern = pattern
|
|
87
|
+
.replace(/\./g, '\\.') // Escape dots
|
|
88
|
+
.replace(/\*/g, '.*') // Convert * to .*
|
|
89
|
+
.replace(/\?/g, '.'); // Convert ? to .
|
|
90
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
91
|
+
return regex.test(path);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Logs a general message
|
|
96
|
+
* @param level - Log level
|
|
97
|
+
* @param message - Log message
|
|
98
|
+
* @param options - Additional logging options
|
|
99
|
+
*/
|
|
100
|
+
log(level, message, options = {}) {
|
|
101
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, id_generator_1.generateUuid)();
|
|
102
|
+
const requestId = options.requestId || (0, id_generator_1.generateUuid)();
|
|
103
|
+
let logEntry;
|
|
104
|
+
let error;
|
|
105
|
+
if (message instanceof Error) {
|
|
106
|
+
error = {
|
|
107
|
+
name: message.name,
|
|
108
|
+
message: message.message,
|
|
109
|
+
stack: message.stack,
|
|
110
|
+
};
|
|
111
|
+
logEntry = {
|
|
112
|
+
level,
|
|
113
|
+
type: 'general',
|
|
114
|
+
message: message.message,
|
|
115
|
+
traceId,
|
|
116
|
+
requestId,
|
|
117
|
+
error,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
else if (typeof message === 'string') {
|
|
121
|
+
logEntry = {
|
|
122
|
+
level,
|
|
123
|
+
type: 'general',
|
|
124
|
+
message,
|
|
125
|
+
traceId,
|
|
126
|
+
requestId,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// If message is an object, stringify it
|
|
131
|
+
logEntry = {
|
|
132
|
+
level,
|
|
133
|
+
type: 'general',
|
|
134
|
+
message: JSON.stringify(message),
|
|
135
|
+
traceId,
|
|
136
|
+
requestId,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
this.logger[level](logEntry);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Logs an error message
|
|
143
|
+
* @param message - Error message or object
|
|
144
|
+
* @param options - Additional logging options
|
|
145
|
+
*/
|
|
146
|
+
error(message, options = {}) {
|
|
147
|
+
this.log('error', message, options);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Logs a warning message
|
|
151
|
+
* @param message - Warning message
|
|
152
|
+
* @param options - Additional logging options
|
|
153
|
+
*/
|
|
154
|
+
warn(message, options = {}) {
|
|
155
|
+
this.log('warn', message, options);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Logs an info message
|
|
159
|
+
* @param message - Info message
|
|
160
|
+
* @param options - Additional logging options
|
|
161
|
+
*/
|
|
162
|
+
info(message, options = {}) {
|
|
163
|
+
this.log('info', message, options);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Logs a debug message
|
|
167
|
+
* @param message - Debug message
|
|
168
|
+
* @param options - Additional logging options
|
|
169
|
+
*/
|
|
170
|
+
debug(message, options = {}) {
|
|
171
|
+
this.log('debug', message, options);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Logs an HTTP request
|
|
175
|
+
* @param req - Express request object
|
|
176
|
+
* @param options - Additional logging options
|
|
177
|
+
* @returns The request ID for correlating with the response
|
|
178
|
+
*/
|
|
179
|
+
httpRequest(req, options = {}) {
|
|
180
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, id_generator_1.generateUuid)();
|
|
181
|
+
const requestId = options.requestId || (0, id_generator_1.generateUuid)();
|
|
182
|
+
const startTime = options.startTime || Date.now();
|
|
183
|
+
// Store request metadata in res.locals for later use
|
|
184
|
+
if (req.res) {
|
|
185
|
+
req.res.locals.requestId = requestId;
|
|
186
|
+
req.res.locals.startTime = startTime;
|
|
187
|
+
req.res.locals.traceId = traceId;
|
|
188
|
+
}
|
|
189
|
+
const logEntry = {
|
|
190
|
+
level: options.level || this.defaultLevel,
|
|
191
|
+
type: 'httpRequest',
|
|
192
|
+
message: `${req.method} ${req.originalUrl || req.url}`,
|
|
193
|
+
traceId,
|
|
194
|
+
requestId,
|
|
195
|
+
duration: 0, // Will be updated in response
|
|
196
|
+
httpRequest: {
|
|
197
|
+
url: req.originalUrl || req.url,
|
|
198
|
+
method: req.method,
|
|
199
|
+
headers: (0, logger_utils_1.filterHeaders)(req.headers),
|
|
200
|
+
ip: req.ip,
|
|
201
|
+
body: req.body,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
this.logger[options.level || this.defaultLevel](logEntry);
|
|
205
|
+
return requestId;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Logs an HTTP response
|
|
209
|
+
* @param res - Express response object
|
|
210
|
+
* @param req - Express request object
|
|
211
|
+
* @param options - Additional logging options
|
|
212
|
+
*/
|
|
213
|
+
httpResponse(res, req, options = {}) {
|
|
214
|
+
const requestId = res.locals.requestId || options.requestId || (0, id_generator_1.generateUuid)();
|
|
215
|
+
const startTime = res.locals.startTime || options.startTime || Date.now();
|
|
216
|
+
const traceId = res.locals.traceId || options.traceId || trace_context_1.traceContext.getTraceId() || (0, id_generator_1.generateUuid)();
|
|
217
|
+
const duration = options.duration || (Date.now() - startTime);
|
|
218
|
+
// Determine log level based on status code
|
|
219
|
+
let level = options.level || this.defaultLevel;
|
|
220
|
+
if (!options.level) {
|
|
221
|
+
if (res.statusCode >= 500) {
|
|
222
|
+
level = 'error';
|
|
223
|
+
}
|
|
224
|
+
else if (res.statusCode >= 400) {
|
|
225
|
+
level = 'warn';
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
level = 'info';
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const logEntry = {
|
|
232
|
+
level,
|
|
233
|
+
type: 'httpResponse',
|
|
234
|
+
message: `${req.method} ${req.originalUrl || req.url} - ${res.statusCode}`,
|
|
235
|
+
traceId,
|
|
236
|
+
requestId,
|
|
237
|
+
duration,
|
|
238
|
+
httpResponse: {
|
|
239
|
+
url: req.originalUrl || req.url,
|
|
240
|
+
method: req.method,
|
|
241
|
+
headers: (0, logger_utils_1.filterHeaders)(res.getHeaders()),
|
|
242
|
+
ip: req.ip,
|
|
243
|
+
status: res.statusCode,
|
|
244
|
+
body: res.locals.body,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
this.logger[level](logEntry);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Logs an SFTP transaction
|
|
251
|
+
* @param operation - SFTP operation details
|
|
252
|
+
* @param options - Additional logging options
|
|
253
|
+
*/
|
|
254
|
+
sftpTransaction(operation, options = {}) {
|
|
255
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, id_generator_1.generateUuid)();
|
|
256
|
+
const requestId = options.requestId || (0, id_generator_1.generateUuid)();
|
|
257
|
+
const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
|
|
258
|
+
const level = operation.status === 'success' ? 'info' : 'error';
|
|
259
|
+
const logEntry = {
|
|
260
|
+
level,
|
|
261
|
+
type: 'sftpTransaction',
|
|
262
|
+
message: `SFTP ${operation.operation} ${operation.status} - ${operation.path}`,
|
|
263
|
+
traceId,
|
|
264
|
+
requestId,
|
|
265
|
+
duration,
|
|
266
|
+
sftp: operation,
|
|
267
|
+
};
|
|
268
|
+
this.logger[level](logEntry);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Logs a database query transaction
|
|
272
|
+
* @param query - Database query details
|
|
273
|
+
* @param options - Additional logging options
|
|
274
|
+
*/
|
|
275
|
+
dbQueryTransaction(query, options = {}) {
|
|
276
|
+
const traceId = options.traceId || trace_context_1.traceContext.getTraceId() || (0, id_generator_1.generateUuid)();
|
|
277
|
+
const requestId = options.requestId || (0, id_generator_1.generateUuid)();
|
|
278
|
+
const duration = options.duration || (options.startTime ? Date.now() - options.startTime : 0);
|
|
279
|
+
const level = query.status === 'success' ? 'info' : 'error';
|
|
280
|
+
const logEntry = {
|
|
281
|
+
level,
|
|
282
|
+
type: 'dbQueryTransaction',
|
|
283
|
+
message: `DB Query ${query.status} - ${query.vendor}`,
|
|
284
|
+
traceId,
|
|
285
|
+
requestId,
|
|
286
|
+
duration,
|
|
287
|
+
db: query,
|
|
288
|
+
};
|
|
289
|
+
this.logger[level](logEntry);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
exports.UnnboundLogger = UnnboundLogger;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a new UUID v4
|
|
3
|
+
* @returns A UUID v4 string
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateUuid(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Generates the current timestamp in ISO format
|
|
8
|
+
* @returns ISO timestamp string
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateTimestamp(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Gets or creates a trace ID for a workflow
|
|
13
|
+
* @param workflowId - The workflow ID to get a trace ID for
|
|
14
|
+
* @returns A trace ID associated with the workflow
|
|
15
|
+
*/
|
|
16
|
+
export declare function getTraceId(workflowId: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Clears a trace ID from the map
|
|
19
|
+
* @param workflowId - The workflow ID to clear
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearTraceId(workflowId: string): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateUuid = generateUuid;
|
|
4
|
+
exports.generateTimestamp = generateTimestamp;
|
|
5
|
+
exports.getTraceId = getTraceId;
|
|
6
|
+
exports.clearTraceId = clearTraceId;
|
|
7
|
+
/**
|
|
8
|
+
* Utilities for generating unique identifiers
|
|
9
|
+
*/
|
|
10
|
+
const uuid_1 = require("uuid");
|
|
11
|
+
/**
|
|
12
|
+
* Generates a new UUID v4
|
|
13
|
+
* @returns A UUID v4 string
|
|
14
|
+
*/
|
|
15
|
+
function generateUuid() {
|
|
16
|
+
return (0, uuid_1.v4)();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generates the current timestamp in ISO format
|
|
20
|
+
* @returns ISO timestamp string
|
|
21
|
+
*/
|
|
22
|
+
function generateTimestamp() {
|
|
23
|
+
return new Date().toISOString();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Stores trace IDs by workflow ID for consistent tracking
|
|
27
|
+
*/
|
|
28
|
+
const traceIdMap = new Map();
|
|
29
|
+
/**
|
|
30
|
+
* Gets or creates a trace ID for a workflow
|
|
31
|
+
* @param workflowId - The workflow ID to get a trace ID for
|
|
32
|
+
* @returns A trace ID associated with the workflow
|
|
33
|
+
*/
|
|
34
|
+
function getTraceId(workflowId) {
|
|
35
|
+
if (!traceIdMap.has(workflowId)) {
|
|
36
|
+
traceIdMap.set(workflowId, generateUuid());
|
|
37
|
+
}
|
|
38
|
+
return traceIdMap.get(workflowId);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Clears a trace ID from the map
|
|
42
|
+
* @param workflowId - The workflow ID to clear
|
|
43
|
+
*/
|
|
44
|
+
function clearTraceId(workflowId) {
|
|
45
|
+
traceIdMap.delete(workflowId);
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for logging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Filters an object of headers, returning a new object with only the allowed headers.
|
|
6
|
+
* @param headers The original headers object.
|
|
7
|
+
* @returns A new object containing only the headers from the allow-list.
|
|
8
|
+
*/
|
|
9
|
+
export declare function filterHeaders(headers: Record<string, any>): Record<string, string>;
|
|
10
|
+
/**
|
|
11
|
+
* Safely parses JSON strings, returning the original data if parsing fails or if it's not a string.
|
|
12
|
+
* @param data The data to potentially parse as JSON.
|
|
13
|
+
* @returns Parsed JSON object or the original data.
|
|
14
|
+
*/
|
|
15
|
+
export declare function safeJsonParse(data: any): any;
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes IP addresses by removing IPv6 mapping prefix for IPv4 addresses.
|
|
18
|
+
* @param ip The IP address to normalize.
|
|
19
|
+
* @returns Normalized IP address string.
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeIp(ip: string | undefined): string | undefined;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for logging
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.filterHeaders = filterHeaders;
|
|
7
|
+
exports.safeJsonParse = safeJsonParse;
|
|
8
|
+
exports.normalizeIp = normalizeIp;
|
|
9
|
+
// --- Header Allow-Listing ---
|
|
10
|
+
const ALLOWED_HEADERS = new Set([
|
|
11
|
+
'content-type',
|
|
12
|
+
'accept',
|
|
13
|
+
'user-agent',
|
|
14
|
+
'host',
|
|
15
|
+
'x-forwarded-for',
|
|
16
|
+
'x-request-id',
|
|
17
|
+
'content-length',
|
|
18
|
+
'cache-control',
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* Filters an object of headers, returning a new object with only the allowed headers.
|
|
22
|
+
* @param headers The original headers object.
|
|
23
|
+
* @returns A new object containing only the headers from the allow-list.
|
|
24
|
+
*/
|
|
25
|
+
function filterHeaders(headers) {
|
|
26
|
+
const filtered = {};
|
|
27
|
+
for (const key in headers) {
|
|
28
|
+
if (ALLOWED_HEADERS.has(key.toLowerCase())) {
|
|
29
|
+
filtered[key] = String(headers[key]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return filtered;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Safely parses JSON strings, returning the original data if parsing fails or if it's not a string.
|
|
36
|
+
* @param data The data to potentially parse as JSON.
|
|
37
|
+
* @returns Parsed JSON object or the original data.
|
|
38
|
+
*/
|
|
39
|
+
function safeJsonParse(data) {
|
|
40
|
+
if (typeof data === 'string') {
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(data);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Normalizes IP addresses by removing IPv6 mapping prefix for IPv4 addresses.
|
|
52
|
+
* @param ip The IP address to normalize.
|
|
53
|
+
* @returns Normalized IP address string.
|
|
54
|
+
*/
|
|
55
|
+
function normalizeIp(ip) {
|
|
56
|
+
if (!ip)
|
|
57
|
+
return ip;
|
|
58
|
+
// Remove IPv4-mapped IPv6 prefix (::ffff:) to get clean IPv4 address
|
|
59
|
+
if (ip.startsWith('::ffff:')) {
|
|
60
|
+
return ip.substring(7);
|
|
61
|
+
}
|
|
62
|
+
return ip;
|
|
63
|
+
}
|