@x-oasis/log 0.1.2 → 0.1.4
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/package.json +12 -2
- package/src/index.ts +39 -0
- package/src/logger.ts +247 -0
- package/src/types.ts +109 -0
- package/src/utils.ts +63 -0
package/package.json
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-oasis/log",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A friendly logging library for browser environments",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"module": "dist/log.esm.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/log.esm.js",
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
8
17
|
"files": [
|
|
9
18
|
"dist",
|
|
10
|
-
"index.ts"
|
|
19
|
+
"index.ts",
|
|
20
|
+
"src"
|
|
11
21
|
],
|
|
12
22
|
"publishConfig": {
|
|
13
23
|
"access": "public"
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Logger } from './logger';
|
|
2
|
+
import { LogLevel } from './types';
|
|
3
|
+
|
|
4
|
+
export { Logger, LogLevel };
|
|
5
|
+
export type {
|
|
6
|
+
LogEntry,
|
|
7
|
+
LoggerOptions,
|
|
8
|
+
LoggerChain,
|
|
9
|
+
OutputHandler,
|
|
10
|
+
} from './types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Default logger instance
|
|
14
|
+
*/
|
|
15
|
+
export const defaultLogger = new Logger();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Convenience methods using the default logger
|
|
19
|
+
*/
|
|
20
|
+
export const log = {
|
|
21
|
+
trace: (message: string, context?: Record<string, unknown>) =>
|
|
22
|
+
defaultLogger.trace(message, context),
|
|
23
|
+
debug: (message: string, context?: Record<string, unknown>) =>
|
|
24
|
+
defaultLogger.debug(message, context),
|
|
25
|
+
info: (message: string, context?: Record<string, unknown>) =>
|
|
26
|
+
defaultLogger.info(message, context),
|
|
27
|
+
warn: (message: string, context?: Record<string, unknown>) =>
|
|
28
|
+
defaultLogger.warn(message, context),
|
|
29
|
+
error: (message: string, context?: Record<string, unknown>) =>
|
|
30
|
+
defaultLogger.error(message, context),
|
|
31
|
+
setLevel: (level: LogLevel | keyof typeof LogLevel) =>
|
|
32
|
+
defaultLogger.setLevel(level),
|
|
33
|
+
withContext: (context: Record<string, unknown>) =>
|
|
34
|
+
defaultLogger.withContext(context),
|
|
35
|
+
withPrefix: (prefix: string) => defaultLogger.withPrefix(prefix),
|
|
36
|
+
chain: () => defaultLogger.chain(),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default Logger;
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LogLevel,
|
|
3
|
+
LogEntry,
|
|
4
|
+
LoggerOptions,
|
|
5
|
+
LoggerChain,
|
|
6
|
+
OutputHandler,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { parseLogLevel, createConsoleHandler } from './utils';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main Logger class
|
|
12
|
+
*/
|
|
13
|
+
export class Logger {
|
|
14
|
+
private level: LogLevel;
|
|
15
|
+
private handler: OutputHandler;
|
|
16
|
+
private enableTimestamp: boolean;
|
|
17
|
+
private defaultContext?: Record<string, unknown>;
|
|
18
|
+
private defaultPrefix?: string;
|
|
19
|
+
|
|
20
|
+
constructor(options: LoggerOptions = {}) {
|
|
21
|
+
this.level = options.level ? parseLogLevel(options.level) : LogLevel.INFO;
|
|
22
|
+
this.handler = options.handler || createConsoleHandler();
|
|
23
|
+
this.enableTimestamp =
|
|
24
|
+
options.enableTimestamp !== undefined ? options.enableTimestamp : true;
|
|
25
|
+
this.defaultContext = options.defaultContext;
|
|
26
|
+
this.defaultPrefix = options.defaultPrefix;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Set the minimum log level
|
|
31
|
+
*/
|
|
32
|
+
setLevel(level: LogLevel | keyof typeof LogLevel): void {
|
|
33
|
+
this.level = parseLogLevel(level);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the current log level
|
|
38
|
+
*/
|
|
39
|
+
getLevel(): LogLevel {
|
|
40
|
+
return this.level;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set a custom output handler
|
|
45
|
+
*/
|
|
46
|
+
setHandler(handler: OutputHandler): void {
|
|
47
|
+
this.handler = handler;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Set default context that will be included in all logs
|
|
52
|
+
*/
|
|
53
|
+
setDefaultContext(context: Record<string, unknown>): void {
|
|
54
|
+
this.defaultContext = context;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Set default prefix for all log messages
|
|
59
|
+
*/
|
|
60
|
+
setDefaultPrefix(prefix: string): void {
|
|
61
|
+
this.defaultPrefix = prefix;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a chainable logger instance
|
|
66
|
+
*/
|
|
67
|
+
chain(): LoggerChain {
|
|
68
|
+
return new LoggerChainBuilder(this);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Log at trace level
|
|
73
|
+
*/
|
|
74
|
+
trace(message: string, context?: Record<string, unknown>): void {
|
|
75
|
+
this.log(LogLevel.TRACE, message, context);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Log at debug level
|
|
80
|
+
*/
|
|
81
|
+
debug(message: string, context?: Record<string, unknown>): void {
|
|
82
|
+
this.log(LogLevel.DEBUG, message, context);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log at info level
|
|
87
|
+
*/
|
|
88
|
+
info(message: string, context?: Record<string, unknown>): void {
|
|
89
|
+
this.log(LogLevel.INFO, message, context);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Log at warn level
|
|
94
|
+
*/
|
|
95
|
+
warn(message: string, context?: Record<string, unknown>): void {
|
|
96
|
+
this.log(LogLevel.WARN, message, context);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Log at error level
|
|
101
|
+
*/
|
|
102
|
+
error(message: string, context?: Record<string, unknown>): void {
|
|
103
|
+
this.log(LogLevel.ERROR, message, context);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Internal log method
|
|
108
|
+
*/
|
|
109
|
+
private log(
|
|
110
|
+
level: LogLevel,
|
|
111
|
+
message: string,
|
|
112
|
+
context?: Record<string, unknown>
|
|
113
|
+
): void {
|
|
114
|
+
if (level < this.level) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const entry: LogEntry = {
|
|
119
|
+
level,
|
|
120
|
+
message,
|
|
121
|
+
timestamp: this.enableTimestamp ? Date.now() : 0,
|
|
122
|
+
prefix: this.defaultPrefix,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Merge default context with provided context
|
|
126
|
+
if (this.defaultContext || context) {
|
|
127
|
+
entry.context = {
|
|
128
|
+
...this.defaultContext,
|
|
129
|
+
...context,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.handler(entry);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a chainable logger with initial context
|
|
138
|
+
*/
|
|
139
|
+
withContext(context: Record<string, unknown>): LoggerChain {
|
|
140
|
+
return new LoggerChainBuilder(this).withContext(context);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create a chainable logger with initial prefix
|
|
145
|
+
*/
|
|
146
|
+
withPrefix(prefix: string): LoggerChain {
|
|
147
|
+
return new LoggerChainBuilder(this).withPrefix(prefix);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Chainable logger builder
|
|
153
|
+
*/
|
|
154
|
+
class LoggerChainBuilder implements LoggerChain {
|
|
155
|
+
private logger: Logger;
|
|
156
|
+
private context?: Record<string, unknown>;
|
|
157
|
+
private metadata?: Record<string, unknown>;
|
|
158
|
+
private errorObj?: Error;
|
|
159
|
+
private prefix?: string;
|
|
160
|
+
|
|
161
|
+
constructor(logger: Logger) {
|
|
162
|
+
this.logger = logger;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
withContext(context: Record<string, unknown>): LoggerChain {
|
|
166
|
+
this.context = {
|
|
167
|
+
...this.context,
|
|
168
|
+
...context,
|
|
169
|
+
};
|
|
170
|
+
return this;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
withMetadata(metadata: Record<string, unknown>): LoggerChain {
|
|
174
|
+
this.metadata = {
|
|
175
|
+
...this.metadata,
|
|
176
|
+
...metadata,
|
|
177
|
+
};
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
withError(error: Error): LoggerChain {
|
|
182
|
+
this.errorObj = error;
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
withPrefix(prefix: string): LoggerChain {
|
|
187
|
+
this.prefix = prefix;
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private createEntry(level: LogLevel, message: string): LogEntry {
|
|
192
|
+
const entry: LogEntry = {
|
|
193
|
+
level,
|
|
194
|
+
message,
|
|
195
|
+
timestamp: this.logger['enableTimestamp'] ? Date.now() : 0,
|
|
196
|
+
prefix: this.prefix || this.logger['defaultPrefix'],
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Merge contexts
|
|
200
|
+
const defaultContext = this.logger['defaultContext'];
|
|
201
|
+
if (defaultContext || this.context) {
|
|
202
|
+
entry.context = {
|
|
203
|
+
...defaultContext,
|
|
204
|
+
...this.context,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (this.metadata) {
|
|
209
|
+
entry.metadata = this.metadata;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (this.errorObj) {
|
|
213
|
+
entry.error = this.errorObj;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return entry;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private log(level: LogLevel, message: string): void {
|
|
220
|
+
if (level < this.logger.getLevel()) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const entry = this.createEntry(level, message);
|
|
225
|
+
this.logger['handler'](entry);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
trace(message: string): void {
|
|
229
|
+
this.log(LogLevel.TRACE, message);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
debug(message: string): void {
|
|
233
|
+
this.log(LogLevel.DEBUG, message);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
info(message: string): void {
|
|
237
|
+
this.log(LogLevel.INFO, message);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
warn(message: string): void {
|
|
241
|
+
this.log(LogLevel.WARN, message);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
error(message: string): void {
|
|
245
|
+
this.log(LogLevel.ERROR, message);
|
|
246
|
+
}
|
|
247
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log levels in order of severity
|
|
3
|
+
*/
|
|
4
|
+
export enum LogLevel {
|
|
5
|
+
TRACE = 0,
|
|
6
|
+
DEBUG = 1,
|
|
7
|
+
INFO = 2,
|
|
8
|
+
WARN = 3,
|
|
9
|
+
ERROR = 4,
|
|
10
|
+
SILENT = 5,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log entry data structure
|
|
15
|
+
*/
|
|
16
|
+
export interface LogEntry {
|
|
17
|
+
level: LogLevel;
|
|
18
|
+
message: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
context?: Record<string, unknown>;
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
error?: Error;
|
|
23
|
+
prefix?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Output handler function type
|
|
28
|
+
*/
|
|
29
|
+
export type OutputHandler = (entry: LogEntry) => void;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Logger configuration options
|
|
33
|
+
*/
|
|
34
|
+
export interface LoggerOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Minimum log level to output (default: LogLevel.INFO)
|
|
37
|
+
*/
|
|
38
|
+
level?: LogLevel | keyof typeof LogLevel;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Custom output handler (default: console)
|
|
42
|
+
*/
|
|
43
|
+
handler?: OutputHandler;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Enable timestamps in log entries (default: true)
|
|
47
|
+
*/
|
|
48
|
+
enableTimestamp?: boolean;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default context that will be included in all logs
|
|
52
|
+
*/
|
|
53
|
+
defaultContext?: Record<string, unknown>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default prefix for all log messages
|
|
57
|
+
*/
|
|
58
|
+
defaultPrefix?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Chainable logger interface
|
|
63
|
+
*/
|
|
64
|
+
export interface LoggerChain {
|
|
65
|
+
/**
|
|
66
|
+
* Add context data that will be included in this log entry
|
|
67
|
+
*/
|
|
68
|
+
withContext(context: Record<string, unknown>): LoggerChain;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Add metadata that will be included in this log entry
|
|
72
|
+
*/
|
|
73
|
+
withMetadata(metadata: Record<string, unknown>): LoggerChain;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Add an error object to this log entry
|
|
77
|
+
*/
|
|
78
|
+
withError(error: Error): LoggerChain;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Add a prefix to this log message
|
|
82
|
+
*/
|
|
83
|
+
withPrefix(prefix: string): LoggerChain;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log at trace level
|
|
87
|
+
*/
|
|
88
|
+
trace(message: string): void;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Log at debug level
|
|
92
|
+
*/
|
|
93
|
+
debug(message: string): void;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Log at info level
|
|
97
|
+
*/
|
|
98
|
+
info(message: string): void;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Log at warn level
|
|
102
|
+
*/
|
|
103
|
+
warn(message: string): void;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Log at error level
|
|
107
|
+
*/
|
|
108
|
+
error(message: string): void;
|
|
109
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LogLevel, LogEntry } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert log level string to LogLevel enum
|
|
5
|
+
*/
|
|
6
|
+
export function parseLogLevel(
|
|
7
|
+
level: LogLevel | keyof typeof LogLevel
|
|
8
|
+
): LogLevel {
|
|
9
|
+
if (typeof level === 'number') {
|
|
10
|
+
return level;
|
|
11
|
+
}
|
|
12
|
+
return LogLevel[level] ?? LogLevel.INFO;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get log level name
|
|
17
|
+
*/
|
|
18
|
+
export function getLogLevelName(level: LogLevel): string {
|
|
19
|
+
return LogLevel[level] ?? 'UNKNOWN';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default console output handler
|
|
24
|
+
*/
|
|
25
|
+
export function createConsoleHandler(): (entry: LogEntry) => void {
|
|
26
|
+
const consoleMethods: Record<number, typeof console.log> = {
|
|
27
|
+
[LogLevel.TRACE]: console.trace || console.debug,
|
|
28
|
+
[LogLevel.DEBUG]: console.debug,
|
|
29
|
+
[LogLevel.INFO]: console.info,
|
|
30
|
+
[LogLevel.WARN]: console.warn,
|
|
31
|
+
[LogLevel.ERROR]: console.error,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (entry) => {
|
|
35
|
+
const method = consoleMethods[entry.level] || console.log;
|
|
36
|
+
const parts: unknown[] = [];
|
|
37
|
+
|
|
38
|
+
// Add prefix if present
|
|
39
|
+
if (entry.prefix) {
|
|
40
|
+
parts.push(entry.prefix);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Add message
|
|
44
|
+
parts.push(entry.message);
|
|
45
|
+
|
|
46
|
+
// Add context if present
|
|
47
|
+
if (entry.context && Object.keys(entry.context).length > 0) {
|
|
48
|
+
parts.push('\nContext:', entry.context);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Add metadata if present
|
|
52
|
+
if (entry.metadata && Object.keys(entry.metadata).length > 0) {
|
|
53
|
+
parts.push('\nMetadata:', entry.metadata);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Add error if present
|
|
57
|
+
if (entry.error) {
|
|
58
|
+
parts.push('\nError:', entry.error);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
method(...parts);
|
|
62
|
+
};
|
|
63
|
+
}
|