@wireio/shared 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/lib/guards/applyTypeGuardExtras.d.ts +3 -0
- package/lib/guards/applyTypeGuardExtras.d.ts.map +1 -0
- package/lib/guards/applyTypeGuardExtras.js +5 -0
- package/lib/guards/applyTypeGuardExtras.js.map +1 -0
- package/lib/guards/array.d.ts +2 -0
- package/lib/guards/array.d.ts.map +1 -0
- package/lib/guards/array.js +4 -0
- package/lib/guards/array.js.map +1 -0
- package/lib/guards/assert.d.ts +19 -0
- package/lib/guards/assert.d.ts.map +1 -0
- package/lib/guards/assert.js +50 -0
- package/lib/guards/assert.js.map +1 -0
- package/lib/guards/class.d.ts +27 -0
- package/lib/guards/class.d.ts.map +1 -0
- package/lib/guards/class.js +34 -0
- package/lib/guards/class.js.map +1 -0
- package/lib/guards/guard-tools.d.ts +20 -0
- package/lib/guards/guard-tools.d.ts.map +1 -0
- package/lib/guards/guard-tools.js +50 -0
- package/lib/guards/guard-tools.js.map +1 -0
- package/lib/guards/index.d.ts +8 -0
- package/lib/guards/index.d.ts.map +1 -0
- package/lib/guards/index.js +8 -0
- package/lib/guards/index.js.map +1 -0
- package/lib/guards/primitive.d.ts +26 -0
- package/lib/guards/primitive.d.ts.map +1 -0
- package/lib/guards/primitive.js +47 -0
- package/lib/guards/primitive.js.map +1 -0
- package/lib/guards/types.d.ts +10 -0
- package/lib/guards/types.d.ts.map +1 -0
- package/lib/guards/types.js +2 -0
- package/lib/guards/types.js.map +1 -0
- package/lib/helpers/Deferred.d.ts +31 -0
- package/lib/helpers/Deferred.d.ts.map +1 -0
- package/lib/helpers/Deferred.js +111 -0
- package/lib/helpers/Deferred.js.map +1 -0
- package/lib/helpers/index.d.ts +2 -0
- package/lib/helpers/index.d.ts.map +1 -0
- package/lib/helpers/index.js +2 -0
- package/lib/helpers/index.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -0
- package/lib/logging/Appender.d.ts +5 -0
- package/lib/logging/Appender.d.ts.map +1 -0
- package/lib/logging/Appender.js +2 -0
- package/lib/logging/Appender.js.map +1 -0
- package/lib/logging/Formatter.d.ts +3 -0
- package/lib/logging/Formatter.d.ts.map +1 -0
- package/lib/logging/Formatter.js +2 -0
- package/lib/logging/Formatter.js.map +1 -0
- package/lib/logging/InternalLogger.d.ts +2 -0
- package/lib/logging/InternalLogger.d.ts.map +1 -0
- package/lib/logging/InternalLogger.js +6 -0
- package/lib/logging/InternalLogger.js.map +1 -0
- package/lib/logging/Level.d.ts +14 -0
- package/lib/logging/Level.d.ts.map +1 -0
- package/lib/logging/Level.js +13 -0
- package/lib/logging/Level.js.map +1 -0
- package/lib/logging/LogRecord.d.ts +16 -0
- package/lib/logging/LogRecord.d.ts.map +1 -0
- package/lib/logging/LogRecord.js +2 -0
- package/lib/logging/LogRecord.js.map +1 -0
- package/lib/logging/Logger.d.ts +77 -0
- package/lib/logging/Logger.d.ts.map +1 -0
- package/lib/logging/Logger.js +158 -0
- package/lib/logging/Logger.js.map +1 -0
- package/lib/logging/LoggingManager.d.ts +128 -0
- package/lib/logging/LoggingManager.d.ts.map +1 -0
- package/lib/logging/LoggingManager.js +236 -0
- package/lib/logging/LoggingManager.js.map +1 -0
- package/lib/logging/appenders/ConsoleAppender.d.ts +55 -0
- package/lib/logging/appenders/ConsoleAppender.d.ts.map +1 -0
- package/lib/logging/appenders/ConsoleAppender.js +72 -0
- package/lib/logging/appenders/ConsoleAppender.js.map +1 -0
- package/lib/logging/appenders/DebugAppender.d.ts +53 -0
- package/lib/logging/appenders/DebugAppender.d.ts.map +1 -0
- package/lib/logging/appenders/DebugAppender.js +183 -0
- package/lib/logging/appenders/DebugAppender.js.map +1 -0
- package/lib/logging/appenders/FileAppender.d.ts +65 -0
- package/lib/logging/appenders/FileAppender.d.ts.map +1 -0
- package/lib/logging/appenders/FileAppender.js +212 -0
- package/lib/logging/appenders/FileAppender.js.map +1 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseAppender.d.ts +27 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseAppender.d.ts.map +1 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseAppender.js +135 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseAppender.js.map +1 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.d.ts +27 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.d.ts.map +1 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.js +94 -0
- package/lib/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.js.map +1 -0
- package/lib/logging/appenders/index.d.ts +4 -0
- package/lib/logging/appenders/index.d.ts.map +1 -0
- package/lib/logging/appenders/index.js +4 -0
- package/lib/logging/appenders/index.js.map +1 -0
- package/lib/logging/context/LogContext.d.ts +48 -0
- package/lib/logging/context/LogContext.d.ts.map +1 -0
- package/lib/logging/context/LogContext.js +58 -0
- package/lib/logging/context/LogContext.js.map +1 -0
- package/lib/logging/context/LogContextContainer.d.ts +9 -0
- package/lib/logging/context/LogContextContainer.d.ts.map +1 -0
- package/lib/logging/context/LogContextContainer.js +25 -0
- package/lib/logging/context/LogContextContainer.js.map +1 -0
- package/lib/logging/context/LogContextProvider.d.ts +24 -0
- package/lib/logging/context/LogContextProvider.d.ts.map +1 -0
- package/lib/logging/context/LogContextProvider.js +18 -0
- package/lib/logging/context/LogContextProvider.js.map +1 -0
- package/lib/logging/context/index.d.ts +4 -0
- package/lib/logging/context/index.d.ts.map +1 -0
- package/lib/logging/context/index.js +4 -0
- package/lib/logging/context/index.js.map +1 -0
- package/lib/logging/context/providers/node/NodeContextProvider.d.ts +2 -0
- package/lib/logging/context/providers/node/NodeContextProvider.d.ts.map +1 -0
- package/lib/logging/context/providers/node/NodeContextProvider.js +31 -0
- package/lib/logging/context/providers/node/NodeContextProvider.js.map +1 -0
- package/lib/logging/context/providers/node/index.d.ts +3 -0
- package/lib/logging/context/providers/node/index.d.ts.map +1 -0
- package/lib/logging/context/providers/node/index.js +2 -0
- package/lib/logging/context/providers/node/index.js.map +1 -0
- package/lib/logging/examples/example-debug-appender.d.ts +2 -0
- package/lib/logging/examples/example-debug-appender.d.ts.map +1 -0
- package/lib/logging/examples/example-debug-appender.js +14 -0
- package/lib/logging/examples/example-debug-appender.js.map +1 -0
- package/lib/logging/examples/example-file-appender.d.ts +2 -0
- package/lib/logging/examples/example-file-appender.d.ts.map +1 -0
- package/lib/logging/examples/example-file-appender.js +16 -0
- package/lib/logging/examples/example-file-appender.js.map +1 -0
- package/lib/logging/getLogger.d.ts +3 -0
- package/lib/logging/getLogger.d.ts.map +1 -0
- package/lib/logging/getLogger.js +5 -0
- package/lib/logging/getLogger.js.map +1 -0
- package/lib/logging/index-node.d.ts +3 -0
- package/lib/logging/index-node.d.ts.map +1 -0
- package/lib/logging/index-node.js +3 -0
- package/lib/logging/index-node.js.map +1 -0
- package/lib/logging/index.d.ts +11 -0
- package/lib/logging/index.d.ts.map +1 -0
- package/lib/logging/index.js +11 -0
- package/lib/logging/index.js.map +1 -0
- package/lib/logging/util.d.ts +3 -0
- package/lib/logging/util.d.ts.map +1 -0
- package/lib/logging/util.js +6 -0
- package/lib/logging/util.js.map +1 -0
- package/package.json +31 -0
- package/src/guards/applyTypeGuardExtras.ts +9 -0
- package/src/guards/array.ts +5 -0
- package/src/guards/assert.ts +83 -0
- package/src/guards/class.ts +56 -0
- package/src/guards/guard-tools.ts +78 -0
- package/src/guards/index.ts +7 -0
- package/src/guards/primitive.ts +77 -0
- package/src/guards/types.ts +15 -0
- package/src/helpers/Deferred.ts +149 -0
- package/src/helpers/index.ts +1 -0
- package/src/index.ts +3 -0
- package/src/logging/Appender.ts +5 -0
- package/src/logging/Formatter.ts +8 -0
- package/src/logging/InternalLogger.ts +6 -0
- package/src/logging/Level.ts +19 -0
- package/src/logging/LogRecord.ts +17 -0
- package/src/logging/Logger.ts +222 -0
- package/src/logging/LoggingManager.ts +306 -0
- package/src/logging/appenders/ConsoleAppender.ts +110 -0
- package/src/logging/appenders/DebugAppender.ts +254 -0
- package/src/logging/appenders/FileAppender.ts +281 -0
- package/src/logging/appenders/aws-firehose/AWSFirehoseAppender.ts +176 -0
- package/src/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.ts +132 -0
- package/src/logging/appenders/index.ts +3 -0
- package/src/logging/context/LogContext.ts +74 -0
- package/src/logging/context/LogContextContainer.ts +28 -0
- package/src/logging/context/LogContextProvider.ts +43 -0
- package/src/logging/context/index.ts +3 -0
- package/src/logging/context/providers/node/NodeContextProvider.ts +45 -0
- package/src/logging/context/providers/node/index.ts +3 -0
- package/src/logging/examples/example-debug-appender.ts +19 -0
- package/src/logging/examples/example-file-appender.ts +19 -0
- package/src/logging/getLogger.ts +9 -0
- package/src/logging/index-node.ts +2 -0
- package/src/logging/index.ts +11 -0
- package/src/logging/util.ts +6 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { isNumber, isObject, isString } from "../guards/index.js"
|
|
2
|
+
import { Option } from "prelude-ts"
|
|
3
|
+
import { flatten, isEmpty, min, negate } from "lodash"
|
|
4
|
+
import type { Appender } from "./Appender.js"
|
|
5
|
+
import { ConsoleAppender } from "./appenders/ConsoleAppender.js"
|
|
6
|
+
import { Level, LevelKind, LevelThresholds } from "./Level.js"
|
|
7
|
+
import { Logger, LoggerOptions } from "./Logger.js"
|
|
8
|
+
import type { LogRecord } from "./LogRecord.js"
|
|
9
|
+
import { LogContext, LogContextContainer } from "./context/index.js"
|
|
10
|
+
import { flow, get, nth } from "lodash/fp.js"
|
|
11
|
+
|
|
12
|
+
export type CategoryMatch = RegExp | string
|
|
13
|
+
|
|
14
|
+
export type ThresholdOverride = [match: CategoryMatch, level: LevelKind]
|
|
15
|
+
|
|
16
|
+
export interface LoggingManagerState<Record extends LogRecord> {
|
|
17
|
+
rootLevel: LevelKind
|
|
18
|
+
appenders: Array<Appender<Record>>
|
|
19
|
+
thresholdOverrides: Array<ThresholdOverride>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type LoggingManagerOptions<Record extends LogRecord> = Partial<
|
|
23
|
+
LoggingManagerState<Record>
|
|
24
|
+
>
|
|
25
|
+
|
|
26
|
+
function parseThresholdOverridePatterns(
|
|
27
|
+
value: string,
|
|
28
|
+
level: LevelKind = "debug"
|
|
29
|
+
): ThresholdOverride[] {
|
|
30
|
+
return value
|
|
31
|
+
.split(",")
|
|
32
|
+
.map((s) => [new RegExp(s), level] as ThresholdOverride)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const kEnvThresholdOverrides = Option.ofNullable(typeof process !== "undefined" && process.env.DEBUG_PATTERNS)
|
|
36
|
+
.filter(negate(isEmpty))
|
|
37
|
+
.map(parseThresholdOverridePatterns)
|
|
38
|
+
.getOrElse([])
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Logging manager
|
|
42
|
+
*/
|
|
43
|
+
export class LoggingManager<Record extends LogRecord = any> {
|
|
44
|
+
private readonly loggers = new Map<string, Logger>()
|
|
45
|
+
|
|
46
|
+
private readonly state: LoggingManagerState<Record> = {
|
|
47
|
+
appenders: [],
|
|
48
|
+
rootLevel: Level.info,
|
|
49
|
+
thresholdOverrides: kEnvThresholdOverrides
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get rootLevel() {
|
|
53
|
+
return this.state.rootLevel
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
set rootLevel(newRootLevel: LevelKind) {
|
|
57
|
+
this.state.rootLevel = newRootLevel
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get rootThreshold() {
|
|
61
|
+
return LevelThresholds[this.rootLevel]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get the current handler
|
|
66
|
+
*
|
|
67
|
+
* @returns {Appender<Record>}
|
|
68
|
+
*/
|
|
69
|
+
get appenders(): Array<Appender<Record>> {
|
|
70
|
+
return Option.ofNullable(this.state.appenders)
|
|
71
|
+
.filter((appenders) => appenders.length > 0)
|
|
72
|
+
.getOrCall(() => {
|
|
73
|
+
this.state.appenders.push(new ConsoleAppender())
|
|
74
|
+
return this.state.appenders
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Global threshold overrides
|
|
80
|
+
*/
|
|
81
|
+
get thresholdOverrides() {
|
|
82
|
+
return this.state.thresholdOverrides
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Update the overrides
|
|
87
|
+
*
|
|
88
|
+
* @param newOverrides
|
|
89
|
+
*/
|
|
90
|
+
set thresholdOverrides(newOverrides:ThresholdOverride[]) {
|
|
91
|
+
this.state.thresholdOverrides = newOverrides
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Set global appenders
|
|
96
|
+
*
|
|
97
|
+
* @param {Array<Appender<Record>>} newAppenders
|
|
98
|
+
*/
|
|
99
|
+
setAppenders(...newAppenders: Array<Appender<Record> | Appender<Record>[]>) {
|
|
100
|
+
// WE MUTATE DO TO THE LIKELIHOOD OF SOMEONE HOLDING A REF TO THE ARRAY,
|
|
101
|
+
// CONVERT TO OBSERVABLE AT SOME POINT
|
|
102
|
+
const persistentAppenders = this.state.appenders
|
|
103
|
+
persistentAppenders.length = 0
|
|
104
|
+
persistentAppenders.push(...flatten(newAppenders))
|
|
105
|
+
|
|
106
|
+
return this
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Add one or more appenders to existing appender set
|
|
111
|
+
*
|
|
112
|
+
* @param {Appender<Record> | Appender<Record>[]} newAppenders
|
|
113
|
+
* @returns {this<Record>}
|
|
114
|
+
*/
|
|
115
|
+
addAppenders(...newAppenders: Array<Appender<Record> | Appender<Record>[]>): this {
|
|
116
|
+
this.state.appenders.push(...flatten(newAppenders))
|
|
117
|
+
return this
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Clear threshold overrides
|
|
122
|
+
*
|
|
123
|
+
* @returns {this<Record>}
|
|
124
|
+
*/
|
|
125
|
+
clearThresholdOverrides(): this {
|
|
126
|
+
this.state.thresholdOverrides.length = 0
|
|
127
|
+
return this
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
setThresholdOverrides(...overrides: Array<ThresholdOverride>) {
|
|
131
|
+
this.state.thresholdOverrides.length = 0
|
|
132
|
+
this.state.thresholdOverrides.push(...overrides)
|
|
133
|
+
return this
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
addThresholdOverrides(...overrides: Array<ThresholdOverride>) {
|
|
137
|
+
this.state.thresholdOverrides.push(...overrides)
|
|
138
|
+
return this
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get applicable current contexts
|
|
143
|
+
*
|
|
144
|
+
* @param {string} category
|
|
145
|
+
* @returns {LogContext[]}
|
|
146
|
+
*/
|
|
147
|
+
getApplicableCurrentContexts(category: string): LogContext[] {
|
|
148
|
+
return LogContextContainer.currentContext().filter(
|
|
149
|
+
({ pattern }) => !pattern || pattern.test(category)
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check for any matching threshold overrides
|
|
155
|
+
*
|
|
156
|
+
* @param category
|
|
157
|
+
*/
|
|
158
|
+
determineThresholdOverride(category: string): number {
|
|
159
|
+
const contexts = this.getApplicableCurrentContexts(category),
|
|
160
|
+
|
|
161
|
+
// FIND CONFIGURED OVERRIDE LEVEL
|
|
162
|
+
overrideThreshold = Option.ofNullable(
|
|
163
|
+
this.thresholdOverrides.find(([match]) =>
|
|
164
|
+
isString(match) ? match === category : (match as RegExp).test(category)
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
.map(nth(1))
|
|
168
|
+
.map((level) => LevelThresholds[level as Level])
|
|
169
|
+
.getOrNull(),
|
|
170
|
+
// FIND `LogContext` OVERRIDE LEVEL
|
|
171
|
+
contextThresholds = contexts
|
|
172
|
+
.filter(flow(get("thresholdLevel"), isString))
|
|
173
|
+
.map(({ thresholdLevel }) => LevelThresholds[thresholdLevel]),
|
|
174
|
+
// IF ANY OVERRIDES, GET THE MOST VERBOSE LEVEL
|
|
175
|
+
override = Option.ofNullable(
|
|
176
|
+
[...contextThresholds, overrideThreshold].filter(isNumber)
|
|
177
|
+
)
|
|
178
|
+
.filter(negate(isEmpty))
|
|
179
|
+
.map(min)
|
|
180
|
+
.getOrNull()
|
|
181
|
+
|
|
182
|
+
return override as number
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Set the root logging level
|
|
187
|
+
*
|
|
188
|
+
* @param {LevelKind} newLevel
|
|
189
|
+
* @returns {this<Record>}
|
|
190
|
+
*/
|
|
191
|
+
setRootLevel(newLevel: LevelKind): this {
|
|
192
|
+
this.state.rootLevel = newLevel
|
|
193
|
+
return this
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Fire a log event, eventually
|
|
198
|
+
* invert this by making `Logger` an
|
|
199
|
+
* `EventEmitter3` and having the `LoggingManager`
|
|
200
|
+
* subscribe to `record` event
|
|
201
|
+
*
|
|
202
|
+
* @param {LogRecord<Record>} record
|
|
203
|
+
* @internal
|
|
204
|
+
*/
|
|
205
|
+
fire(record: LogRecord<Record>) {
|
|
206
|
+
const { category } = record,
|
|
207
|
+
contexts = this.getApplicableCurrentContexts(category),
|
|
208
|
+
contextAppenders = contexts.flatMap(get("appenders")),
|
|
209
|
+
appenders = [...this.appenders, ...contextAppenders]
|
|
210
|
+
|
|
211
|
+
appenders.forEach((appender) => appender.append(record as Record))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get a logger from cache, if the category
|
|
216
|
+
* does not have an existing logger, then create one.
|
|
217
|
+
*
|
|
218
|
+
* @param {string} categoryOrFilename
|
|
219
|
+
* @param {Partial<LoggerOptions>} inOptions
|
|
220
|
+
* @returns {Logger}
|
|
221
|
+
*/
|
|
222
|
+
getLogger(
|
|
223
|
+
categoryOrFilename: string,
|
|
224
|
+
inOptions: Partial<LoggerOptions> = {}
|
|
225
|
+
): Logger {
|
|
226
|
+
const options = Logger.hydrateOptions(inOptions)
|
|
227
|
+
const category = Logger.interoplateCategory(categoryOrFilename, options)
|
|
228
|
+
|
|
229
|
+
return Option.ofNullable(category)
|
|
230
|
+
.map((category) => this.loggers.get(category))
|
|
231
|
+
.getOrCall(() => {
|
|
232
|
+
const logger = new Logger(this, category, options)
|
|
233
|
+
this.loggers.set(category, logger)
|
|
234
|
+
return logger
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Configure the logging manager,
|
|
240
|
+
* this function is additive, so simply calling
|
|
241
|
+
* `configure` with a single option `rootLevel`,
|
|
242
|
+
* will not affect other options like `appenders` *
|
|
243
|
+
*
|
|
244
|
+
* @param {LoggingManagerOptions<any>} options
|
|
245
|
+
* @returns {this<Record>}
|
|
246
|
+
*/
|
|
247
|
+
configure(options: LoggingManagerOptions<any>): this {
|
|
248
|
+
if (Level[options?.rootLevel]) {
|
|
249
|
+
this.setRootLevel(options.rootLevel)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (options?.appenders) {
|
|
253
|
+
this.setAppenders(options.appenders)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (options?.thresholdOverrides) {
|
|
257
|
+
this.addThresholdOverrides(...options.thresholdOverrides)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return this
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private constructor() {
|
|
264
|
+
this.configure({})
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Singleton instance
|
|
269
|
+
*
|
|
270
|
+
* @type {LoggingManager}
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
private static manager: LoggingManager
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get logging manager and optionally provided
|
|
277
|
+
* configuration options
|
|
278
|
+
*
|
|
279
|
+
* @param {LoggingManagerOptions<Record>} options
|
|
280
|
+
* @returns {LoggingManager<Record>}
|
|
281
|
+
*/
|
|
282
|
+
static get<Record extends LogRecord = any>(
|
|
283
|
+
options: LoggingManagerOptions<Record> = null
|
|
284
|
+
): LoggingManager<Record> {
|
|
285
|
+
if (!this.manager) {
|
|
286
|
+
this.manager = new LoggingManager<Record>()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (options) {
|
|
290
|
+
this.manager.configure(options)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return this.manager
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function getLoggingManager(): LoggingManager {
|
|
298
|
+
return LoggingManager.get()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (Option.try_(() => process.env.NODE_ENV === "development").getOrElse(false)) {
|
|
302
|
+
[typeof window !== "undefined" && window, typeof global !== "undefined" && global].filter(isObject)
|
|
303
|
+
.map(target => Object.assign(target, {
|
|
304
|
+
loggingManager: getLoggingManager()
|
|
305
|
+
}))
|
|
306
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { LogRecord } from "../LogRecord"
|
|
2
|
+
import type { Appender } from "../Appender"
|
|
3
|
+
import { Option } from "prelude-ts"
|
|
4
|
+
import type { LevelKind } from "../Level"
|
|
5
|
+
import type { Formatter } from "../Formatter"
|
|
6
|
+
|
|
7
|
+
const consoleLogBindings = new Map<LevelKind, (...args: any[]) => any>()
|
|
8
|
+
|
|
9
|
+
function getBoundConsoleFn(level: LevelKind) {
|
|
10
|
+
return (console[level] ?? console.log).bind(console)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get a cached console bound log function
|
|
15
|
+
*
|
|
16
|
+
* @param {LevelKind} level
|
|
17
|
+
* @returns {(...args: any[]) => any}
|
|
18
|
+
*/
|
|
19
|
+
export function getConsoleLogBinding(level: LevelKind) {
|
|
20
|
+
if (!consoleLogBindings.has(level)) {
|
|
21
|
+
consoleLogBindings.set(level, getBoundConsoleFn(level))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return consoleLogBindings.get(level)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* ConsoleAppender Configuration
|
|
29
|
+
*/
|
|
30
|
+
export interface ConsoleAppenderConfig<Record extends LogRecord = any> {
|
|
31
|
+
cacheEnabled: boolean
|
|
32
|
+
prettyPrint: boolean
|
|
33
|
+
formatter?: Formatter<string | Array<any>>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Partial of config, used for shortening instead of Partial<...>
|
|
38
|
+
*/
|
|
39
|
+
export type ConsoleAppenderOptions<Record extends LogRecord> = Partial<
|
|
40
|
+
ConsoleAppenderConfig<Record>
|
|
41
|
+
>
|
|
42
|
+
|
|
43
|
+
export const consoleFormatter: Formatter<Array<any>> = ({
|
|
44
|
+
level,
|
|
45
|
+
message,
|
|
46
|
+
data,
|
|
47
|
+
args,
|
|
48
|
+
category,
|
|
49
|
+
timestamp
|
|
50
|
+
}) => [
|
|
51
|
+
`[${category}] (${level}) ${message}`,
|
|
52
|
+
...(Array.isArray(args) ? args : [args])
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default console config
|
|
57
|
+
* @type {ConsoleAppenderConfig}
|
|
58
|
+
*/
|
|
59
|
+
export const kDefaultConsoleAppenderConfig: ConsoleAppenderConfig = {
|
|
60
|
+
cacheEnabled: true,
|
|
61
|
+
prettyPrint: true,
|
|
62
|
+
formatter: consoleFormatter
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Console appender, the simple default appender used
|
|
67
|
+
* everywhere OOB
|
|
68
|
+
*/
|
|
69
|
+
export class ConsoleAppender<Record extends LogRecord>
|
|
70
|
+
implements Appender<Record>
|
|
71
|
+
{
|
|
72
|
+
readonly config: ConsoleAppenderConfig
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle log records, transform, push to ES
|
|
76
|
+
*
|
|
77
|
+
* @param record
|
|
78
|
+
*/
|
|
79
|
+
append(record: Record): void {
|
|
80
|
+
const { level, message, data, args, category, timestamp } = record
|
|
81
|
+
const { formatter = consoleFormatter } = this.config
|
|
82
|
+
Option.ofNullable(formatter(record)).map((result) => {
|
|
83
|
+
const args = Array.isArray(result) ? result : [result]
|
|
84
|
+
this.write(level, ...args)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Write args to console
|
|
90
|
+
*
|
|
91
|
+
* @param level
|
|
92
|
+
* @param args
|
|
93
|
+
*/
|
|
94
|
+
protected write(level: LevelKind, ...args: any[]) {
|
|
95
|
+
Option.ofNullable(console[level])
|
|
96
|
+
.orCall(() => Option.ofNullable(console.log))
|
|
97
|
+
.map((fn: Function) => fn.apply(console, args))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
*
|
|
102
|
+
* @param {Partial<ConsoleAppenderOptions<Record>>} options
|
|
103
|
+
*/
|
|
104
|
+
constructor(options: Partial<ConsoleAppenderOptions<Record>> = {}) {
|
|
105
|
+
this.config = {
|
|
106
|
+
...kDefaultConsoleAppenderConfig,
|
|
107
|
+
...options
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import type { LogRecord } from "../LogRecord"
|
|
2
|
+
import type { Appender } from "../Appender"
|
|
3
|
+
import type { LevelKind } from "../Level"
|
|
4
|
+
import Debug from "debug"
|
|
5
|
+
import {
|
|
6
|
+
ConsoleAppender, ConsoleAppenderConfig, kDefaultConsoleAppenderConfig
|
|
7
|
+
} from "./ConsoleAppender.js"
|
|
8
|
+
import type { Formatter } from "../Formatter"
|
|
9
|
+
import { isEmpty, negate } from "lodash"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// let chalk: any = null
|
|
13
|
+
// if (
|
|
14
|
+
// typeof process !== "undefined" &&
|
|
15
|
+
// (process as any).type !== "renderer" &&
|
|
16
|
+
// (process as any).browser !== true
|
|
17
|
+
// ) {
|
|
18
|
+
// chalk = require("chalk")
|
|
19
|
+
// }
|
|
20
|
+
|
|
21
|
+
const useColors = false
|
|
22
|
+
|
|
23
|
+
const makeColorFn = (fn: (chalk: any, s: string) => string) => {
|
|
24
|
+
// if (!useColors) {
|
|
25
|
+
// return (s: string) => s
|
|
26
|
+
// }
|
|
27
|
+
//
|
|
28
|
+
// return (s: string) => fn(chalk, s)
|
|
29
|
+
return (s: string) => s
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const colorFns: Record<LevelKind, (s: string) => string> = {
|
|
33
|
+
debug: makeColorFn((c, s) => c.green(s)),
|
|
34
|
+
error: makeColorFn((c, s) => c.red(s)),
|
|
35
|
+
fatal: makeColorFn((c, s) => c.bgRed.black(s)),
|
|
36
|
+
info: makeColorFn((c, s) => c.blue(s)),
|
|
37
|
+
trace: makeColorFn((c, s) => c.gray(s)),
|
|
38
|
+
warn: makeColorFn((c, s) => c.yellow(s))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* DebugAppender Configuration
|
|
43
|
+
*/
|
|
44
|
+
export interface DebugAppenderConfig extends ConsoleAppenderConfig {
|
|
45
|
+
hideDate: boolean
|
|
46
|
+
timeOnly: boolean
|
|
47
|
+
useConsole: boolean
|
|
48
|
+
useStdout: boolean
|
|
49
|
+
categoryPrefix: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Partial of config, used for shortening instead of Partial<...>
|
|
54
|
+
*/
|
|
55
|
+
export type DebugAppenderOptions = Partial<DebugAppenderConfig>
|
|
56
|
+
|
|
57
|
+
const debuggers = new Map<string, Debug.Debugger>()
|
|
58
|
+
|
|
59
|
+
//const debugAppPrefix = "app"
|
|
60
|
+
|
|
61
|
+
function getDebug({categoryPrefix}: DebugAppenderConfig, cat: string) {
|
|
62
|
+
let debug = debuggers.get(cat)
|
|
63
|
+
if (!debug) {
|
|
64
|
+
debug = Debug([categoryPrefix, cat].filter(negate(isEmpty)).join(":"))
|
|
65
|
+
debuggers.set(cat, debug)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return debug
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// const timeFormatter = new Intl.DateTimeFormat('en-US', {
|
|
72
|
+
// timeStyle: "short"
|
|
73
|
+
// })
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* Get ISO date if `hideDate !== true`
|
|
78
|
+
*
|
|
79
|
+
* @param {DebugFormatterContext}
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
function getDate({ debugConfig: config }: DebugFormatterContext) {
|
|
83
|
+
if (config.hideDate) {
|
|
84
|
+
return ""
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const date = new Date()
|
|
88
|
+
return config.timeOnly
|
|
89
|
+
? date.toLocaleTimeString("default", {
|
|
90
|
+
hour12: false
|
|
91
|
+
})
|
|
92
|
+
: date.toISOString()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* Formats args for output, directly based on Debug.formatArgs
|
|
98
|
+
*
|
|
99
|
+
* @param {DebugFormatterContext} context
|
|
100
|
+
* @param {any[]} args
|
|
101
|
+
*/
|
|
102
|
+
function formatArgs(
|
|
103
|
+
context: DebugFormatterContext,
|
|
104
|
+
record: LogRecord,
|
|
105
|
+
args: any[]
|
|
106
|
+
) {
|
|
107
|
+
const { debug } = context
|
|
108
|
+
const { namespace: name } = debug as any
|
|
109
|
+
|
|
110
|
+
const prefix = colorFns[record.level](
|
|
111
|
+
[
|
|
112
|
+
getDate(context),
|
|
113
|
+
Debug.humanize(debug.diff),
|
|
114
|
+
`(` + record.level.toUpperCase() + `)`,
|
|
115
|
+
`[${name}]`
|
|
116
|
+
]
|
|
117
|
+
.filter(negate(isEmpty))
|
|
118
|
+
.join(" ")
|
|
119
|
+
)
|
|
120
|
+
const msg = [prefix, args[0]].filter(negate(isEmpty)).join(" ")
|
|
121
|
+
|
|
122
|
+
args[0] = msg
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Context for using `debugFormatter`
|
|
127
|
+
*/
|
|
128
|
+
export type DebugFormatterContext = {
|
|
129
|
+
debugConfig: DebugAppenderConfig
|
|
130
|
+
debug: Debug.Debugger
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Uses `debug` package for logging, very useful
|
|
135
|
+
*
|
|
136
|
+
* @param {LogRecord} record to format
|
|
137
|
+
* @param {DebugFormatterContext} context for this formatter
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
140
|
+
export const debugFormatter: Formatter<Array<any>, DebugFormatterContext> = (
|
|
141
|
+
record,
|
|
142
|
+
{ debug, debugConfig: config }
|
|
143
|
+
): any[] => {
|
|
144
|
+
const { level, message, data, args: argsIn, category, timestamp } = record
|
|
145
|
+
const args = [message, ...argsIn]
|
|
146
|
+
args[0] = Debug.coerce(args[0])
|
|
147
|
+
|
|
148
|
+
if (typeof args[0] !== "string") {
|
|
149
|
+
// Anything else let's inspect with %O
|
|
150
|
+
args.unshift("%O")
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Apply any `formatters` transformations
|
|
154
|
+
let index = 0
|
|
155
|
+
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
|
|
156
|
+
// If we encounter an escaped % then don't increase the array index
|
|
157
|
+
if (match === "%%") {
|
|
158
|
+
return "%"
|
|
159
|
+
}
|
|
160
|
+
index++
|
|
161
|
+
const formatter = Debug.formatters[format]
|
|
162
|
+
if (typeof formatter === "function") {
|
|
163
|
+
const val = args[index]
|
|
164
|
+
match = formatter.call(debug, val)
|
|
165
|
+
|
|
166
|
+
// Now we need to remove `args[index]` since it's inlined in the `format`
|
|
167
|
+
args.splice(index, 1)
|
|
168
|
+
index--
|
|
169
|
+
}
|
|
170
|
+
return match
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
// Apply env-specific formatting (colors, etc.)
|
|
174
|
+
formatArgs({ debug, debugConfig: config }, record, args)
|
|
175
|
+
|
|
176
|
+
return args
|
|
177
|
+
}
|
|
178
|
+
// [
|
|
179
|
+
// `[${category}] (${level}) ${message}`,
|
|
180
|
+
// ...(Array.isArray(args) ? args : [args])
|
|
181
|
+
// ]
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Default console config
|
|
185
|
+
* @type {DebugAppenderConfig}
|
|
186
|
+
*/
|
|
187
|
+
const defaultConfig: DebugAppenderConfig = {
|
|
188
|
+
hideDate: false,
|
|
189
|
+
timeOnly: true,
|
|
190
|
+
useConsole: false,
|
|
191
|
+
useStdout: true,
|
|
192
|
+
categoryPrefix: null,
|
|
193
|
+
...kDefaultConsoleAppenderConfig,
|
|
194
|
+
formatter: debugFormatter
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Debug appender, the simple default appender used
|
|
198
|
+
* everywhere OOB
|
|
199
|
+
*/
|
|
200
|
+
export class DebugAppender<Record extends LogRecord>
|
|
201
|
+
extends ConsoleAppender<Record>
|
|
202
|
+
implements Appender<Record>
|
|
203
|
+
{
|
|
204
|
+
readonly debugConfig: DebugAppenderConfig
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Handle log records, transform, push to ES
|
|
209
|
+
*
|
|
210
|
+
* @param record
|
|
211
|
+
*/
|
|
212
|
+
append(record: Record): void {
|
|
213
|
+
const { level, message, args: argsIn, category } = record
|
|
214
|
+
|
|
215
|
+
// if (!this.levels.includes(level)) {
|
|
216
|
+
// super.append(record)
|
|
217
|
+
// return
|
|
218
|
+
// }
|
|
219
|
+
|
|
220
|
+
const debug = getDebug(this.debugConfig, category) as any
|
|
221
|
+
let prevTime = debug.prevTime
|
|
222
|
+
// Set `diff` timestamp
|
|
223
|
+
const curr = Number(new Date())
|
|
224
|
+
const ms = curr - (prevTime || curr)
|
|
225
|
+
debug.diff = ms
|
|
226
|
+
debug.prev = prevTime
|
|
227
|
+
debug.curr = curr
|
|
228
|
+
debug.prevTime = curr
|
|
229
|
+
const logFn = debug.log || Debug.log
|
|
230
|
+
const args = debugFormatter!(record, { debug, debugConfig: this.debugConfig })
|
|
231
|
+
|
|
232
|
+
if (this.debugConfig.useConsole) {
|
|
233
|
+
super.write(level, ...args)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.debugConfig.useStdout) {
|
|
237
|
+
logFn.apply(debug, args)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
*
|
|
243
|
+
* @param {Partial<DebugAppenderOptions>} options
|
|
244
|
+
*/
|
|
245
|
+
constructor(options: Partial<Omit<DebugAppenderOptions, "formatter">> = {}) {
|
|
246
|
+
super({
|
|
247
|
+
...defaultConfig,
|
|
248
|
+
...options,
|
|
249
|
+
formatter: debugFormatter
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
this.debugConfig = this.config as DebugAppenderConfig
|
|
253
|
+
}
|
|
254
|
+
}
|