@wireio/shared 1.0.2 → 1.0.3

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.
Files changed (39) hide show
  1. package/package.json +5 -1
  2. package/src/guards/applyTypeGuardExtras.ts +0 -9
  3. package/src/guards/array.ts +0 -5
  4. package/src/guards/assert.ts +0 -83
  5. package/src/guards/class.ts +0 -56
  6. package/src/guards/guard-tools.ts +0 -78
  7. package/src/guards/index.ts +0 -7
  8. package/src/guards/primitive.ts +0 -77
  9. package/src/guards/types.ts +0 -15
  10. package/src/helpers/Deferred.ts +0 -149
  11. package/src/helpers/index.ts +0 -1
  12. package/src/index.ts +0 -3
  13. package/src/logging/Appender.ts +0 -5
  14. package/src/logging/Formatter.ts +0 -8
  15. package/src/logging/InternalLogger.ts +0 -6
  16. package/src/logging/Level.ts +0 -19
  17. package/src/logging/LogRecord.ts +0 -17
  18. package/src/logging/Logger.ts +0 -222
  19. package/src/logging/LoggingManager.ts +0 -306
  20. package/src/logging/appenders/ConsoleAppender.ts +0 -110
  21. package/src/logging/appenders/DebugAppender.ts +0 -254
  22. package/src/logging/appenders/FileAppender.ts +0 -281
  23. package/src/logging/appenders/aws-firehose/AWSFirehoseAppender.ts +0 -176
  24. package/src/logging/appenders/aws-firehose/AWSFirehoseCredentialManager.ts +0 -132
  25. package/src/logging/appenders/index.ts +0 -3
  26. package/src/logging/context/LogContext.ts +0 -74
  27. package/src/logging/context/LogContextContainer.ts +0 -28
  28. package/src/logging/context/LogContextProvider.ts +0 -43
  29. package/src/logging/context/index.ts +0 -3
  30. package/src/logging/context/providers/node/NodeContextProvider.ts +0 -45
  31. package/src/logging/context/providers/node/index.ts +0 -3
  32. package/src/logging/examples/example-debug-appender.ts +0 -19
  33. package/src/logging/examples/example-file-appender.ts +0 -19
  34. package/src/logging/getLogger.ts +0 -9
  35. package/src/logging/index-node.ts +0 -2
  36. package/src/logging/index.ts +0 -11
  37. package/src/logging/util.ts +0 -6
  38. package/tsconfig.json +0 -9
  39. package/tsconfig.tsbuildinfo +0 -1
@@ -1,222 +0,0 @@
1
- import { assert, getValue, isString, isDefined, isFunction, isNumber } from "../guards/index.js"
2
- import { Option } from "prelude-ts"
3
- import { pick } from "lodash"
4
- import { LevelKind, LevelThresholds } from "./Level.js"
5
- import type { LoggingManager } from "./LoggingManager.js"
6
- import type { LogRecord } from "./LogRecord.js"
7
- import { isLogLevelKind } from "./util.js"
8
-
9
- export interface LoggerOptions {
10
- categoryInterpolator: CategoryInterpolator
11
- }
12
-
13
- export type CategoryInterpolator = (
14
- inCategory: string,
15
- options?: LoggerOptions
16
- ) => string
17
-
18
- export const filenameCategoryInterpolator: CategoryInterpolator = (
19
- filename: string
20
- ) => {
21
- const allParts = filename.replaceAll("\\","/").split("/")
22
- const rootIndex = Math.max(
23
- ...["src", "lib"].map((name) => allParts.indexOf(name))
24
- )
25
- const parts =
26
- rootIndex === -1 ? [allParts.pop()] : allParts.slice(rootIndex + 1)
27
- const category = Option.of(parts.join(":"))
28
- .flatMap((cat) =>
29
- Option.of(cat.lastIndexOf(".")).map((index) =>
30
- index === -1 ? cat : cat.slice(0, index)
31
- )
32
- )
33
- .getOrElse("unknown")
34
- return category
35
- }
36
-
37
- export const defaultLoggerOptions: LoggerOptions = {
38
- categoryInterpolator: filenameCategoryInterpolator
39
- }
40
-
41
- export function toLogRecord(
42
- logger: Logger,
43
- levelOrRecord: LevelKind | LogRecord,
44
- args: any[]
45
- ) {
46
- const errRecord = Option.ofNullable(
47
- args.find((arg) => (isString(arg?.message) && !!arg.stack) || arg instanceof Error)
48
- ).match({
49
- Some: (err) => ({
50
- errorMessage: getValue(() => err.message),
51
- errorStack: getValue(() => err.stack)
52
- }),
53
- None: () => ({})
54
- })
55
-
56
- const recordBase = isString(levelOrRecord)
57
- ? ({
58
- ...pick(logger, ["category"]),
59
- timestamp: Date.now(),
60
- message: args[0],
61
- level: levelOrRecord,
62
- args: args.slice(1)
63
- } as LogRecord)
64
- : levelOrRecord
65
- return {
66
- ...recordBase,
67
- ...errRecord,
68
- timestamp: isNumber(recordBase.timestamp) && recordBase.timestamp > 0 ? recordBase.timestamp : Date.now(),
69
- }
70
- }
71
-
72
- export interface LoggerState {
73
- overrideLevel?: LevelKind
74
- }
75
-
76
- export class Logger {
77
- readonly state: LoggerState = {
78
- overrideLevel: null
79
- }
80
-
81
- get overrideLevel(): LevelKind {
82
- return Option.ofNullable(this.state.overrideLevel)
83
- .filter(isLogLevelKind) //Predicate.of<LevelKind>(isString).and(isLogLevelKind))
84
- .getOrNull()
85
- }
86
-
87
- get overrideThreshold() {
88
- return Option.ofNullable(this.overrideLevel)
89
- .map((level) => LevelThresholds[level])
90
- .getOrNull()
91
- }
92
-
93
- setOverrideLevel(inOverrideLevel: LevelKind) {
94
- const overrideLevel = (
95
- !inOverrideLevel ? null : inOverrideLevel.toLocaleLowerCase()
96
- ) as LevelKind
97
-
98
- assert(
99
- !isDefined(overrideLevel) || isLogLevelKind(overrideLevel),
100
- `Invalid override level, must be a log level, all lower case`
101
- )
102
-
103
- Object.assign(this.state, {
104
- overrideLevel
105
- })
106
-
107
- return this
108
- }
109
-
110
- /**
111
- * Base logging function
112
- *
113
- * @param record
114
- */
115
- log(record: LogRecord):void
116
- log(level: LevelKind, message: string, ...args: any[]):void
117
- log(levelOrRecord: LevelKind | LogRecord, ...args: any[]) {
118
- const record = toLogRecord(this, levelOrRecord, args)
119
- this.manager.fire(record)
120
- }
121
-
122
- /**
123
- * Factory for the log
124
- * level functions
125
- *
126
- * @param {LevelKind} level
127
- * @returns {(message: string, ...args: any[]) => void}
128
- * @private
129
- */
130
- private createLevelLogger(level: LevelKind): (message: string, ...args: any[]) => void {
131
- const isEnabled = this.createLevelEnabled(level)
132
- return (message: string, ...args: any[]) => {
133
- if (isEnabled()) {
134
- this.log(level, message, ...args)
135
- }
136
- }
137
- }
138
-
139
- /**
140
- * Factory for is<Level>Enabled
141
- *
142
- * @param {LevelKind} level
143
- * @returns {() => boolean}
144
- * @private
145
- */
146
- private createLevelEnabled(level: LevelKind): () => boolean {
147
- return () => {
148
- const { rootThreshold } = this.manager
149
-
150
- const globalOverrideThreshold = this.manager.determineThresholdOverride(this.category)
151
- const categoryThresholds = [
152
- globalOverrideThreshold,
153
- rootThreshold,
154
- this.overrideThreshold
155
- ].filter(isNumber)
156
-
157
- const categoryThreshold = Math.min(...categoryThresholds)
158
-
159
- const recordThreshold = LevelThresholds[level]
160
-
161
- return recordThreshold >= categoryThreshold
162
- }
163
- }
164
-
165
- readonly trace = this.createLevelLogger("trace")
166
- readonly debug = this.createLevelLogger("debug")
167
- readonly info = this.createLevelLogger("info")
168
- readonly warn = this.createLevelLogger("warn")
169
- readonly error = this.createLevelLogger("error")
170
- readonly fatal = this.createLevelLogger("fatal")
171
-
172
- readonly isTraceEnabled = this.createLevelEnabled("trace")
173
- readonly isDebugEnabled = this.createLevelEnabled("debug")
174
- readonly isInfoEnabled = this.createLevelEnabled("info")
175
- readonly isWarnEnabled = this.createLevelEnabled("warn")
176
- readonly isErrorEnabled = this.createLevelEnabled("error")
177
- readonly isFatalEnabled = this.createLevelEnabled("fatal")
178
-
179
- assert(test: boolean | (() => boolean), message: string, ...args: any[]) {
180
- const isTruthy = isFunction(test) ? test() : test
181
- if (isTruthy) {
182
- return
183
- }
184
-
185
- this.error(message, ...args)
186
- }
187
-
188
- assertFatal(test: boolean | (() => boolean), message: string, exitCode: number = 1) {
189
- const isTruthy = isFunction(test) ? test() : test
190
- if (isTruthy) {
191
- return
192
- }
193
-
194
- this.fatal("FATAL ASSERTION: ", message)
195
- if (typeof process !== "undefined") {
196
- process.exit(exitCode)
197
- } else {
198
- console.error("FATAL ASSERTION: `process` is not defined, probably in a web browser")
199
- }
200
- }
201
-
202
- constructor(
203
- readonly manager: LoggingManager,
204
- readonly category: string,
205
- readonly options: LoggerOptions
206
- ) {}
207
-
208
- static hydrateOptions(options: Partial<LoggerOptions> = {}): LoggerOptions {
209
- return {
210
- ...defaultLoggerOptions,
211
- ...options
212
- }
213
- }
214
-
215
- static interoplateCategory(category: string, options: LoggerOptions) {
216
- options = {
217
- ...defaultLoggerOptions,
218
- ...options
219
- }
220
- return options.categoryInterpolator(category, options)
221
- }
222
- }
@@ -1,306 +0,0 @@
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
- }
@@ -1,110 +0,0 @@
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
- }