@bitblit/ratchet-common 6.0.145-alpha → 6.0.147-alpha

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 (140) hide show
  1. package/package.json +2 -1
  2. package/src/2d/line-2d.ts +6 -0
  3. package/src/2d/matrix-factory.ts +94 -0
  4. package/src/2d/plane-2d-type.ts +6 -0
  5. package/src/2d/plane-2d.ts +7 -0
  6. package/src/2d/point-2d.ts +4 -0
  7. package/src/2d/poly-line-2d.ts +5 -0
  8. package/src/2d/ratchet-2d.spec.ts +205 -0
  9. package/src/2d/ratchet-2d.ts +350 -0
  10. package/src/2d/transformation-matrix.ts +19 -0
  11. package/src/build/build-information.ts +8 -0
  12. package/src/build/ratchet-common-info.ts +19 -0
  13. package/src/histogram/histogram-entry.ts +4 -0
  14. package/src/histogram/histogram.spec.ts +25 -0
  15. package/src/histogram/histogram.ts +61 -0
  16. package/src/jwt/common-jwt-token.ts +17 -0
  17. package/src/jwt/expired-jwt-handling.ts +5 -0
  18. package/src/jwt/jwt-decode-only-ratchet.ts +26 -0
  19. package/src/jwt/jwt-payload-expiration-ratchet.ts +45 -0
  20. package/src/jwt/jwt-token-base.ts +14 -0
  21. package/src/lang/array-ratchet.spec.ts +79 -0
  22. package/src/lang/array-ratchet.ts +141 -0
  23. package/src/lang/base64-ratchet.spec.ts +48 -0
  24. package/src/lang/base64-ratchet.ts +247 -0
  25. package/src/lang/boolean-ratchet.spec.ts +95 -0
  26. package/src/lang/boolean-ratchet.ts +52 -0
  27. package/src/lang/composite-last-success-provider.spec.ts +31 -0
  28. package/src/lang/composite-last-success-provider.ts +30 -0
  29. package/src/lang/currency-ratchet.ts +29 -0
  30. package/src/lang/date-ratchet.spec.ts +27 -0
  31. package/src/lang/date-ratchet.ts +42 -0
  32. package/src/lang/duration-ratchet.spec.ts +47 -0
  33. package/src/lang/duration-ratchet.ts +77 -0
  34. package/src/lang/enum-ratchet.spec.ts +45 -0
  35. package/src/lang/enum-ratchet.ts +41 -0
  36. package/src/lang/error-handling-approach.ts +6 -0
  37. package/src/lang/error-ratchet.spec.ts +25 -0
  38. package/src/lang/error-ratchet.ts +70 -0
  39. package/src/lang/esm-ratchet.ts +81 -0
  40. package/src/lang/expiring-object.spec.ts +56 -0
  41. package/src/lang/expiring-object.ts +84 -0
  42. package/src/lang/geolocation-ratchet.spec.ts +177 -0
  43. package/src/lang/geolocation-ratchet.ts +341 -0
  44. package/src/lang/global-ratchet.spec.ts +17 -0
  45. package/src/lang/global-ratchet.ts +105 -0
  46. package/src/lang/key-value.ts +8 -0
  47. package/src/lang/last-success-provider.ts +4 -0
  48. package/src/lang/map-ratchet.spec.ts +113 -0
  49. package/src/lang/map-ratchet.ts +220 -0
  50. package/src/lang/no.spec.ts +9 -0
  51. package/src/lang/no.ts +7 -0
  52. package/src/lang/number-ratchet.spec.ts +154 -0
  53. package/src/lang/number-ratchet.ts +253 -0
  54. package/src/lang/parsed-url.ts +10 -0
  55. package/src/lang/promise-ratchet.spec.ts +104 -0
  56. package/src/lang/promise-ratchet.ts +196 -0
  57. package/src/lang/range.ts +4 -0
  58. package/src/lang/require-ratchet.spec.ts +85 -0
  59. package/src/lang/require-ratchet.ts +68 -0
  60. package/src/lang/simple-arg-ratchet.spec.ts +13 -0
  61. package/src/lang/simple-arg-ratchet.ts +47 -0
  62. package/src/lang/simple-encryption-ratchet.ts +88 -0
  63. package/src/lang/sort-ratchet.spec.ts +58 -0
  64. package/src/lang/sort-ratchet.ts +50 -0
  65. package/src/lang/stop-watch.spec.ts +53 -0
  66. package/src/lang/stop-watch.ts +202 -0
  67. package/src/lang/string-ratchet.spec.ts +226 -0
  68. package/src/lang/string-ratchet.ts +676 -0
  69. package/src/lang/time-zone-ratchet.spec.ts +51 -0
  70. package/src/lang/time-zone-ratchet.ts +148 -0
  71. package/src/lang/timeout-token.spec.ts +12 -0
  72. package/src/lang/timeout-token.ts +21 -0
  73. package/src/lang/uint-8-array-ratchet.spec.ts +22 -0
  74. package/src/lang/uint-8-array-ratchet.ts +48 -0
  75. package/src/lang/web-stream-ratchet.spec.ts +12 -0
  76. package/src/lang/web-stream-ratchet.ts +96 -0
  77. package/src/logger/classic-single-line-log-message-formatter.ts +19 -0
  78. package/src/logger/log-message-builder.ts +60 -0
  79. package/src/logger/log-message-format-type.ts +11 -0
  80. package/src/logger/log-message-formatter.ts +6 -0
  81. package/src/logger/log-message-processor.ts +6 -0
  82. package/src/logger/log-message.ts +9 -0
  83. package/src/logger/log-snapshot.ts +6 -0
  84. package/src/logger/logger-instance.ts +269 -0
  85. package/src/logger/logger-level-name.ts +11 -0
  86. package/src/logger/logger-meta.ts +7 -0
  87. package/src/logger/logger-options.ts +14 -0
  88. package/src/logger/logger-output-function.ts +10 -0
  89. package/src/logger/logger-ring-buffer.ts +89 -0
  90. package/src/logger/logger-util.spec.ts +11 -0
  91. package/src/logger/logger-util.ts +68 -0
  92. package/src/logger/logger.spec.ts +177 -0
  93. package/src/logger/logger.ts +213 -0
  94. package/src/logger/none-log-message-formatter.ts +10 -0
  95. package/src/logger/single-line-no-level-log-message-formatter.ts +18 -0
  96. package/src/logger/structured-json-log-message-formatter.ts +25 -0
  97. package/src/mail/archive-email-result.ts +8 -0
  98. package/src/mail/email-attachment.ts +23 -0
  99. package/src/mail/mail-sending-provider.ts +21 -0
  100. package/src/mail/mailer-config.ts +30 -0
  101. package/src/mail/mailer-like.ts +38 -0
  102. package/src/mail/mailer-util.ts +65 -0
  103. package/src/mail/mailer.spec.ts +120 -0
  104. package/src/mail/mailer.ts +214 -0
  105. package/src/mail/ready-to-send-email.ts +67 -0
  106. package/src/mail/resolved-ready-to-send-email.ts +17 -0
  107. package/src/mail/send-email-result.ts +16 -0
  108. package/src/mail/test-mail-sending-provider.ts +35 -0
  109. package/src/network/browser-local-ip-provider.spec.ts +23 -0
  110. package/src/network/browser-local-ip-provider.ts +26 -0
  111. package/src/network/fixed-local-ip-provider.ts +9 -0
  112. package/src/network/local-ip-provider.ts +4 -0
  113. package/src/network/network-ratchet.spec.ts +17 -0
  114. package/src/network/network-ratchet.ts +209 -0
  115. package/src/network/remote-file-tracker/backup-result.ts +6 -0
  116. package/src/network/remote-file-tracker/file-transfer-result-type.ts +5 -0
  117. package/src/network/remote-file-tracker/file-transfer-result.ts +9 -0
  118. package/src/network/remote-file-tracker/remote-file-tracker-options.ts +6 -0
  119. package/src/network/remote-file-tracker/remote-file-tracker-push-options.ts +4 -0
  120. package/src/network/remote-file-tracker/remote-file-tracker.ts +117 -0
  121. package/src/network/remote-file-tracker/remote-file-tracking-provider.ts +19 -0
  122. package/src/network/remote-file-tracker/remote-status-data-and-content.ts +6 -0
  123. package/src/network/remote-file-tracker/remote-status-data.ts +7 -0
  124. package/src/network/restful-api-http-error.spec.ts +13 -0
  125. package/src/network/restful-api-http-error.ts +173 -0
  126. package/src/template/ratchet-template-renderer.ts +8 -0
  127. package/src/third-party/google/google-recaptcha-ratchet.spec.ts +27 -0
  128. package/src/third-party/google/google-recaptcha-ratchet.ts +36 -0
  129. package/src/third-party/twilio/twilio-ratchet.ts +92 -0
  130. package/src/third-party/twilio/twilio-verify-ratchet.ts +83 -0
  131. package/src/transform/built-in-transforms.ts +214 -0
  132. package/src/transform/transform-ratchet.spec.ts +134 -0
  133. package/src/transform/transform-ratchet.ts +88 -0
  134. package/src/transform/transform-rule.ts +7 -0
  135. package/src/tx/transaction-configuration.ts +8 -0
  136. package/src/tx/transaction-final-state.ts +7 -0
  137. package/src/tx/transaction-ratchet.spec.ts +150 -0
  138. package/src/tx/transaction-ratchet.ts +98 -0
  139. package/src/tx/transaction-result.ts +10 -0
  140. package/src/tx/transaction-step.ts +5 -0
@@ -0,0 +1,269 @@
1
+ import { LogMessage } from './log-message.js';
2
+ import { LoggerOptions } from './logger-options.js';
3
+ import { LoggerRingBuffer } from './logger-ring-buffer.js';
4
+ import { LoggerLevelName } from './logger-level-name.js';
5
+ import { LoggerUtil } from './logger-util.js';
6
+ import { LogMessageFormatter } from './log-message-formatter.js';
7
+ import { LogMessageFormatType } from './log-message-format-type.js';
8
+ import { ClassicSingleLineLogMessageFormatter } from './classic-single-line-log-message-formatter.js';
9
+ import { NoneLogMessageFormatter } from './none-log-message-formatter.js';
10
+ import { StructuredJsonLogMessageFormatter } from './structured-json-log-message-formatter.js';
11
+ import { LogMessageBuilder } from './log-message-builder.js';
12
+ import { LogMessageProcessor } from './log-message-processor.js';
13
+ import { StringRatchet } from '../lang/string-ratchet.js';
14
+ import { LoggerMeta } from './logger-meta.js';
15
+ import { SingleLineNoLevelLogMessageFormatter } from './single-line-no-level-log-message-formatter.js';
16
+
17
+ export class LoggerInstance {
18
+ private _guid: number = Math.floor(Math.random() * 1_000_000);
19
+ private _loggerMeta: LoggerMeta;
20
+
21
+ private _ringBuffer: LoggerRingBuffer;
22
+ private _formatter: LogMessageFormatter;
23
+ private _level: LoggerLevelName;
24
+ private _handlerFunctionMap: Map<LoggerLevelName, (...any) => void>;
25
+ private _options: LoggerOptions;
26
+
27
+ constructor(
28
+ private loggerInstanceName = 'default',
29
+ inOptions: LoggerOptions,
30
+ ) {
31
+ this.options = inOptions; // MUST use the setter here
32
+ }
33
+
34
+ public levelIsEnabled(level: LoggerLevelName): boolean {
35
+ return LoggerUtil.levelIsEnabled(level, this._level);
36
+ }
37
+
38
+ public addPreProcessor(proc: LogMessageProcessor): LogMessageProcessor[] {
39
+ if (proc) {
40
+ this._options.preProcessors = this._options.preProcessors || [];
41
+ this._options.preProcessors.push(proc);
42
+ }
43
+ return Object.assign([], this._options.preProcessors);
44
+ }
45
+
46
+ public get ringBuffer(): LoggerRingBuffer {
47
+ return this._ringBuffer;
48
+ }
49
+
50
+ public dumpConfigurationIntoLog(): void {
51
+ this.error('ERROR enabled');
52
+ this.warn('WARN enabled');
53
+ this.info('INFO enabled');
54
+ this.verbose('VERBOSE enabled');
55
+ this.debug('DEBUG enabled');
56
+ this.silly('SILLY enabled');
57
+ }
58
+
59
+ public dumpOptionsIntoLog(): void {
60
+ this.info('Guid: %s Options: %j', this._guid, this.options);
61
+ if (this?.options?.preProcessors?.length) {
62
+ const labels: string[] = this.options.preProcessors.map((p) => StringRatchet.trimToNull(p.label()) || 'Unlabelled');
63
+ this.info('Preprocessors: %j', labels);
64
+ }
65
+ }
66
+
67
+ public get guid(): number {
68
+ return this._guid;
69
+ }
70
+
71
+ // This will always clear the buffer
72
+ public changeRingBufferSize(newSize: number): void {
73
+ this._ringBuffer = null;
74
+ if (newSize) {
75
+ this._ringBuffer = new LoggerRingBuffer(newSize);
76
+ this._options.ringBufferSize = newSize;
77
+ }
78
+ }
79
+
80
+ public updateTracePrefix(newValue: string): void {
81
+ this._options.trace = newValue;
82
+ }
83
+
84
+ public get options(): LoggerOptions {
85
+ return Object.assign({}, this._options);
86
+ }
87
+
88
+ public set options(newOpts: LoggerOptions) {
89
+ this._options = Object.assign({}, newOpts);
90
+ if (this._options.ringBufferSize) {
91
+ this._ringBuffer = new LoggerRingBuffer(this._options.ringBufferSize);
92
+ }
93
+ // Setup the formatter
94
+ switch (this._options.formatType) {
95
+ case LogMessageFormatType.None:
96
+ this._formatter = new NoneLogMessageFormatter();
97
+ break;
98
+ case LogMessageFormatType.StructuredJson:
99
+ this._formatter = new StructuredJsonLogMessageFormatter();
100
+ break;
101
+ case LogMessageFormatType.SingleLineNoLevel:
102
+ this._formatter = new SingleLineNoLevelLogMessageFormatter();
103
+ break;
104
+ default:
105
+ this._formatter = new ClassicSingleLineLogMessageFormatter();
106
+ break;
107
+ }
108
+ this._level = this._options.initialLevel;
109
+ this._handlerFunctionMap = LoggerUtil.handlerFunctionMap(this._options.outputFunction);
110
+
111
+ const oldId: string = this._loggerMeta ? this._loggerMeta.loggerInstanceId : null;
112
+ this._loggerMeta = {
113
+ options: this._options,
114
+ loggerInstanceName: this.loggerInstanceName,
115
+ loggerInstanceId: oldId || StringRatchet.createRandomHexString(8),
116
+ };
117
+ }
118
+
119
+ public get level(): LoggerLevelName {
120
+ return this._level;
121
+ }
122
+
123
+ public set level(newLevel: LoggerLevelName) {
124
+ if (!newLevel) {
125
+ throw new Error('Cannot set level to null/undefined');
126
+ }
127
+ this._level = newLevel;
128
+ }
129
+
130
+ public consoleLogPassThru(level: LoggerLevelName, ...input: any[]): void {
131
+ if (LoggerUtil.levelIsEnabled(level, this._level)) {
132
+ let passThruPrefix: string = this._options.trace || '';
133
+ passThruPrefix += '[' + level + '] ';
134
+ input.unshift(passThruPrefix);
135
+ const fn: (...any) => void = this._handlerFunctionMap.get(level) || LoggerUtil.defaultHandlerFunction;
136
+ fn(...input);
137
+ }
138
+ }
139
+
140
+ public createLogMessage(level: LoggerLevelName, params: Record<string, string>, format: string, ...input: any[]): LogMessage {
141
+ const rval: LogMessage = {
142
+ lvl: level,
143
+ timestamp: Date.now(),
144
+ messageSource: format,
145
+ subsVars: input,
146
+ params: params,
147
+ };
148
+ return rval;
149
+ }
150
+
151
+ public formatMessage(msg: LogMessage): string {
152
+ const rval: string = msg ? this._formatter.formatMessage(msg, this._loggerMeta) : null;
153
+ return rval;
154
+ }
155
+
156
+ public formatMessages(msgs: LogMessage[]): string[] {
157
+ const rval: string[] = (msgs || []).map((m) => this.formatMessage(m)).filter((m) => !!m);
158
+ return rval;
159
+ }
160
+
161
+ public recordMessageBuilder(msgBuild: LogMessageBuilder): string {
162
+ return this.recordMessage(msgBuild.toMessage());
163
+ }
164
+
165
+ public recordMessage(inMsg: LogMessage): string {
166
+ let rval: string = null;
167
+ if (LoggerUtil.levelIsEnabled(inMsg.lvl, this._level)) {
168
+ let msg: LogMessage = Object.assign({}, inMsg);
169
+ // If there are any preprocessors, run them
170
+ if (this._options.preProcessors?.length) {
171
+ for (const proc of this._options.preProcessors) {
172
+ msg = proc.process(msg);
173
+ }
174
+ }
175
+ // Now, generate the actual string to log
176
+ rval = this.formatMessage(msg);
177
+ if (rval) {
178
+ const fn: (...any) => void = this._handlerFunctionMap.get(msg.lvl) || LoggerUtil.defaultHandlerFunction;
179
+ fn(rval);
180
+ if (this._ringBuffer) {
181
+ this._ringBuffer.addToRingBuffer(msg);
182
+ }
183
+ }
184
+ } else {
185
+ // Do nothing, not enabled
186
+ }
187
+ return rval;
188
+ }
189
+
190
+ public error(format: string, ...input: any[]): string {
191
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.error, {}, format, ...input);
192
+ return this.recordMessage(msg);
193
+ }
194
+
195
+ public errorP(...input: any[]): void {
196
+ this.consoleLogPassThru(LoggerLevelName.error, ...input);
197
+ }
198
+
199
+ public warn(format: string, ...input: any[]): string {
200
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.warn, {}, format, ...input);
201
+ return this.recordMessage(msg);
202
+ }
203
+
204
+ public warnP(...input: any[]): void {
205
+ this.consoleLogPassThru(LoggerLevelName.warn, ...input);
206
+ }
207
+
208
+ public info(format: string, ...input: any[]): string {
209
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.info, {}, format, ...input);
210
+ return this.recordMessage(msg);
211
+ }
212
+
213
+ public infoP(...input: any[]): void {
214
+ this.consoleLogPassThru(LoggerLevelName.info, ...input);
215
+ }
216
+
217
+ public verbose(format: string, ...input: any[]): string {
218
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.verbose, {}, format, ...input);
219
+ return this.recordMessage(msg);
220
+ }
221
+
222
+ public verboseP(...input: any[]): void {
223
+ this.consoleLogPassThru(LoggerLevelName.verbose, ...input);
224
+ }
225
+
226
+ public debug(format: string, ...input: any[]): string {
227
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.debug, {}, format, ...input);
228
+ return this.recordMessage(msg);
229
+ }
230
+
231
+ public debugP(...input: any[]): void {
232
+ // This is here because old versions of Node do not support console.debug
233
+ this.consoleLogPassThru(LoggerLevelName.debug, ...input);
234
+ }
235
+
236
+ public silly(format: string, ...input: any[]): string {
237
+ const msg: LogMessage = this.createLogMessage(LoggerLevelName.silly, {}, format, ...input);
238
+ return this.recordMessage(msg);
239
+ }
240
+
241
+ public sillyP(...input: any[]): void {
242
+ this.consoleLogPassThru(LoggerLevelName.silly, ...input);
243
+ }
244
+
245
+ public logByLevel(level: LoggerLevelName, format: string, ...input: any[]): void {
246
+ const msg: LogMessage = this.createLogMessage(level, {}, format, ...input);
247
+ this.recordMessage(msg);
248
+ }
249
+
250
+ public importMessages(msgs: LogMessage[], prefixIn = '', addTimestamp = true): void {
251
+ const prefix: string = prefixIn || '';
252
+ if (msgs && msgs.length > 0) {
253
+ this.silly('Received import data : %d msgs', msgs.length);
254
+
255
+ // Pump messages
256
+ msgs.forEach((m) => {
257
+ if (m.messageSource) {
258
+ let mOut: string = prefix;
259
+ if (addTimestamp) {
260
+ const ts: string = String(new Date()).substring(15, 24);
261
+ mOut += ' (' + ts + ') : ';
262
+ mOut += m.messageSource;
263
+ }
264
+ this.logByLevel(m.lvl, mOut);
265
+ }
266
+ });
267
+ }
268
+ }
269
+ }
@@ -0,0 +1,11 @@
1
+ // NOTE: This is a psuedo-enum to fix some issues with Typescript enums. See: https://exploringjs.com/tackling-ts/ch_enum-alternatives.html for details
2
+
3
+ export const LoggerLevelName = {
4
+ error: 'error',
5
+ warn: 'warn',
6
+ info: 'info',
7
+ verbose: 'verbose',
8
+ debug: 'debug',
9
+ silly: 'silly',
10
+ } as const;
11
+ export type LoggerLevelName = (typeof LoggerLevelName)[keyof typeof LoggerLevelName];
@@ -0,0 +1,7 @@
1
+ import { LoggerOptions } from './logger-options.js';
2
+
3
+ export interface LoggerMeta {
4
+ options: LoggerOptions;
5
+ loggerInstanceName: string;
6
+ loggerInstanceId: string;
7
+ }
@@ -0,0 +1,14 @@
1
+ import { LogMessageFormatType } from './log-message-format-type.js';
2
+ import { LoggerLevelName } from './logger-level-name.js';
3
+ import { LogMessageProcessor } from './log-message-processor.js';
4
+ import { LoggerOutputFunction } from './logger-output-function.js';
5
+
6
+ export interface LoggerOptions {
7
+ initialLevel?: LoggerLevelName;
8
+ formatType?: LogMessageFormatType;
9
+ trace?: string;
10
+ globalVars?: Record<string, string | number | boolean>;
11
+ outputFunction?: LoggerOutputFunction;
12
+ ringBufferSize?: number;
13
+ preProcessors?: LogMessageProcessor[];
14
+ }
@@ -0,0 +1,10 @@
1
+ // NOTE: This is a psuedo-enum to fix some issues with Typescript enums. See: https://exploringjs.com/tackling-ts/ch_enum-alternatives.html for details
2
+
3
+ export const LoggerOutputFunction = {
4
+ Console: 'Console',
5
+ ConsoleNoDebug: 'ConsoleNoDebug',
6
+ StdOut: 'StdOut',
7
+ Disabled: 'Disabled',
8
+ };
9
+
10
+ export type LoggerOutputFunction = (typeof LoggerOutputFunction)[keyof typeof LoggerOutputFunction];
@@ -0,0 +1,89 @@
1
+ import { LogMessage } from './log-message.js';
2
+ import { LogSnapshot } from './log-snapshot.js';
3
+ import { LoggerLevelName } from './logger-level-name.js';
4
+
5
+ export class LoggerRingBuffer {
6
+ private _lastLogMessage: LogMessage = { messageSource: 'No message yet', timestamp: new Date().getTime(), lvl: LoggerLevelName.info };
7
+
8
+ private _buffer: LogMessage[] = [];
9
+ private _bufferIdx = 0;
10
+ private _lastSnapshotIdx = 0;
11
+ private _bufferSize: number;
12
+
13
+ constructor(size: number) {
14
+ if (!size) {
15
+ throw new Error('Cannot create ring buffer of size 0');
16
+ }
17
+ this._bufferSize = size;
18
+ }
19
+
20
+ public get currentIndex(): number {
21
+ return this._bufferIdx;
22
+ }
23
+
24
+ public get lastSnapshotIdx(): number {
25
+ return this._lastSnapshotIdx;
26
+ }
27
+
28
+ public set bufferSize(newSize: number) {
29
+ if (!newSize) {
30
+ throw new Error('Cannot create ring buffer of size 0');
31
+ }
32
+ this._bufferSize = newSize;
33
+ this.clearRingBuffer();
34
+ }
35
+
36
+ public getMessages(inStartFrom: number = null, clear = false, reverseSort = false): LogMessage[] {
37
+ let rval: LogMessage[] = null;
38
+ if (this._bufferIdx < this._bufferSize) {
39
+ const start: number = inStartFrom == null ? 0 : inStartFrom;
40
+ rval = this._buffer.slice(start, this._bufferIdx); // Use slice to get a copy (should use below too)
41
+ } else {
42
+ rval = [];
43
+
44
+ const firstIdx = this._bufferIdx - this._bufferSize;
45
+ const startFrom = inStartFrom ? Math.max(inStartFrom, firstIdx) : firstIdx;
46
+
47
+ for (let i = startFrom; i < this._bufferIdx; i++) {
48
+ rval.push(this._buffer[i % this._bufferSize]);
49
+ }
50
+ }
51
+
52
+ if (clear) {
53
+ this.clearRingBuffer();
54
+ }
55
+
56
+ if (reverseSort) {
57
+ rval = rval.reverse();
58
+ }
59
+
60
+ return rval;
61
+ }
62
+
63
+ public takeSnapshot(): LogSnapshot {
64
+ const trailingEdge = Math.max(0, this._bufferIdx - this._bufferSize);
65
+ const rval: LogSnapshot = {
66
+ messages: this.getMessages(this._lastSnapshotIdx),
67
+ logMessagesTruncated: Math.max(0, trailingEdge - this._lastSnapshotIdx),
68
+ } as LogSnapshot;
69
+
70
+ this._lastSnapshotIdx = this._bufferIdx;
71
+ return rval;
72
+ }
73
+
74
+ public getLastLogMessage(): LogMessage {
75
+ return Object.assign({}, this._lastLogMessage);
76
+ }
77
+
78
+ private clearRingBuffer() {
79
+ this._buffer = [];
80
+ this._bufferIdx = 0;
81
+ this._lastSnapshotIdx = 0;
82
+ }
83
+
84
+ public addToRingBuffer(newMsg: LogMessage): void {
85
+ this._lastLogMessage = newMsg;
86
+ this._buffer[this._bufferIdx % this._bufferSize] = newMsg;
87
+ this._bufferIdx++; // advance
88
+ }
89
+ }
@@ -0,0 +1,11 @@
1
+ import { LoggerUtil } from './logger-util.js';
2
+ import { LoggerLevelName } from './logger-level-name.js';
3
+ import { describe, expect, test } from 'vitest';
4
+
5
+ describe('#checkLevel', function () {
6
+ test('should check that level logging works', function () {
7
+ expect(LoggerUtil.levelIsEnabled(LoggerLevelName.info, LoggerLevelName.warn)).toEqual(false);
8
+ expect(LoggerUtil.levelIsEnabled(LoggerLevelName.warn, LoggerLevelName.info)).toEqual(true);
9
+ expect(LoggerUtil.levelIsEnabled(LoggerLevelName.warn, LoggerLevelName.warn)).toEqual(true);
10
+ });
11
+ });
@@ -0,0 +1,68 @@
1
+ import { LoggerLevelName } from './logger-level-name.js';
2
+ import { LoggerOutputFunction } from './logger-output-function.js';
3
+
4
+ export class LoggerUtil {
5
+ private static LOG_LEVELS_IN_ORDER: LoggerLevelName[] = [
6
+ LoggerLevelName.error,
7
+ LoggerLevelName.warn,
8
+ LoggerLevelName.info,
9
+ LoggerLevelName.verbose,
10
+ LoggerLevelName.debug,
11
+ LoggerLevelName.silly,
12
+ ];
13
+
14
+ public static handlerFunctionMap(outputFn: LoggerOutputFunction = LoggerOutputFunction.Console): Map<LoggerLevelName, (...any) => void> {
15
+ const output: Map<LoggerLevelName, (...any) => void> = new Map<LoggerLevelName, (...any) => void>();
16
+ if (outputFn === LoggerOutputFunction.Disabled) {
17
+ // Disables ALL logger functionality
18
+ const disabled: (...any) => void = (_chunk, _cb) => {
19
+ /*do nothing*/
20
+ };
21
+ output.set(LoggerLevelName.error, disabled);
22
+ output.set(LoggerLevelName.warn, disabled);
23
+ output.set(LoggerLevelName.info, disabled);
24
+ output.set(LoggerLevelName.verbose, disabled);
25
+ output.set(LoggerLevelName.debug, disabled);
26
+ output.set(LoggerLevelName.silly, disabled);
27
+ } else if (outputFn === LoggerOutputFunction.StdOut) {
28
+ if (!process?.stdout?.write) {
29
+ throw new Error('Cannot use standard out - process.stdout.write not found');
30
+ }
31
+ // Have to do this because process.stdout.write refers to 'this'
32
+ // See: https://github.com/nodejs/node-v0.x-archive/issues/7980
33
+ const myStdOut: (...any) => void = (chunk, cb) => process.stdout.write(chunk, 'utf-8', cb);
34
+ output.set(LoggerLevelName.error, myStdOut);
35
+ output.set(LoggerLevelName.warn, myStdOut);
36
+ output.set(LoggerLevelName.info, myStdOut);
37
+ output.set(LoggerLevelName.verbose, myStdOut);
38
+ output.set(LoggerLevelName.debug, myStdOut);
39
+ output.set(LoggerLevelName.silly, myStdOut);
40
+ } else {
41
+ output.set(LoggerLevelName.error, console.error);
42
+ output.set(LoggerLevelName.warn, console.warn);
43
+ output.set(LoggerLevelName.info, console.info);
44
+ output.set(LoggerLevelName.verbose, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
45
+ output.set(LoggerLevelName.debug, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
46
+ output.set(LoggerLevelName.silly, outputFn === LoggerOutputFunction.ConsoleNoDebug ? console.log : console.debug);
47
+ }
48
+ return output;
49
+ }
50
+
51
+ public static defaultHandlerFunction(): (...any) => void {
52
+ return console.info;
53
+ }
54
+
55
+ public static levelIsEnabled(targetLevel: LoggerLevelName, currentEnabled: LoggerLevelName): boolean {
56
+ const idxTarget: number = LoggerUtil.loggerLevelIndex(targetLevel);
57
+ const lvl: number = LoggerUtil.loggerLevelIndex(currentEnabled);
58
+ return idxTarget > -1 && lvl > -1 && lvl >= idxTarget;
59
+ }
60
+
61
+ public static loggerLevelIndex(targetLevel: LoggerLevelName): number {
62
+ return LoggerUtil.LOG_LEVELS_IN_ORDER.indexOf(targetLevel);
63
+ }
64
+
65
+ public static indexToLevel(idx: number): LoggerLevelName {
66
+ return idx >= 0 && idx < LoggerUtil.LOG_LEVELS_IN_ORDER.length ? LoggerUtil.LOG_LEVELS_IN_ORDER[idx] : null;
67
+ }
68
+ }
@@ -0,0 +1,177 @@
1
+ import { Logger } from './logger.js';
2
+ import { LogSnapshot } from './log-snapshot.js';
3
+ import { LogMessage } from './log-message.js';
4
+ import { LoggerLevelName } from './logger-level-name.js';
5
+ import { LogMessageProcessor } from './log-message-processor.js';
6
+ import { StringRatchet } from '../lang/string-ratchet.js';
7
+ import { LogMessageBuilder } from './log-message-builder.js';
8
+ import { LogMessageFormatType } from './log-message-format-type.js';
9
+ import { LoggerOutputFunction } from './logger-output-function.js';
10
+ import { describe, expect, test } from 'vitest';
11
+
12
+ describe('#setLevel', function () {
13
+ test('should change the level to debug then info then debug', function () {
14
+ Logger.dumpConfigurationIntoLog();
15
+ //console.log("Start Level : "+Logger.getLevel());
16
+ expect(Logger.getLevel()).toEqual(LoggerLevelName.info);
17
+ // Should start at default level
18
+ Logger.setLevel(LoggerLevelName.debug);
19
+ expect(Logger.getLevel()).toEqual(LoggerLevelName.debug);
20
+ Logger.setLevel(LoggerLevelName.info);
21
+ expect(Logger.getLevel()).toEqual(LoggerLevelName.info);
22
+ //Logger.debug("This should NOT get written, as I am at info level");
23
+ //Logger.info("This should get written, as I am at info level");
24
+ //Logger.logByLevel('info', "Write at info level");
25
+ //Logger.info("Write also at info level");
26
+ Logger.setLevel(LoggerLevelName.debug);
27
+ expect(Logger.getLevel()).toEqual(LoggerLevelName.debug);
28
+ });
29
+ });
30
+
31
+ describe('#takeSnapshot', function () {
32
+ test('should advance the pointer correctly after a snapshot', function () {
33
+ Logger.changeRingBufferSize(5);
34
+ expect(Logger.getRingBuffer().currentIndex).toEqual(0);
35
+
36
+ Logger.info('m1');
37
+ Logger.info('m2');
38
+ Logger.info('m3');
39
+
40
+ const snap1: LogSnapshot = Logger.takeSnapshot();
41
+ Logger.info('m4');
42
+ Logger.info('m5');
43
+ const snap2: LogSnapshot = Logger.takeSnapshot();
44
+
45
+ Logger.info('m6');
46
+ Logger.info('m7');
47
+ Logger.info('m8');
48
+
49
+ const snap3: LogSnapshot = Logger.takeSnapshot();
50
+
51
+ expect(snap1.messages.length).toEqual(3);
52
+ expect(snap2.messages.length).toEqual(2);
53
+ expect(snap3.messages.length).toEqual(3);
54
+
55
+ expect(Logger.getRingBuffer().currentIndex).toEqual(8);
56
+ });
57
+ });
58
+
59
+ describe('#testTracePrefix', function () {
60
+ test('should apply a trace prefix correctly', function () {
61
+ Logger.updateTracePrefix('::TRACE::');
62
+ Logger.changeRingBufferSize(3);
63
+ Logger.info('m1');
64
+ Logger.info('m2');
65
+ const snap1: LogSnapshot = Logger.takeSnapshot();
66
+ const snap1String: string[] = Logger.formatMessages(snap1.messages);
67
+
68
+ expect(snap1String.length).toBeGreaterThan(0);
69
+ snap1String.forEach((m) => {
70
+ expect(m.indexOf('::TRACE::')).toBeGreaterThan(-1);
71
+ });
72
+
73
+ Logger.updateTracePrefix(null);
74
+ Logger.info('m1');
75
+ Logger.info('m2');
76
+ const snap2: LogSnapshot = Logger.takeSnapshot();
77
+
78
+ expect(snap2.messages.length).toBeGreaterThan(0);
79
+ snap2.messages.forEach((m) => {
80
+ expect(m.messageSource.indexOf('::TRACE::')).toEqual(-1);
81
+ });
82
+ });
83
+ });
84
+
85
+ describe('#testLastMessage', function () {
86
+ test('should return the last message', function () {
87
+ Logger.info('m1');
88
+ Logger.info('m2');
89
+
90
+ const last: LogMessage = Logger.getLastLogMessage();
91
+ expect(last).toBeTruthy();
92
+ expect(last.lvl).toEqual(LoggerLevelName.info);
93
+ expect(last.messageSource.endsWith('m2')).toBeTruthy();
94
+ });
95
+ });
96
+
97
+ describe('#testPassThruFunctions', function () {
98
+ test('should pass through values', function () {
99
+ Logger.setLevel(LoggerLevelName.debug);
100
+
101
+ Logger.error('Test %s', 'tVal');
102
+ Logger.errorP('TestP %s', 'tVal');
103
+ Logger.errorP('TestP 2', 27, { some: 'Object' });
104
+
105
+ Logger.warn('Test %s', 'tVal');
106
+ Logger.warnP('TestP %s', 'tVal');
107
+
108
+ Logger.info('Test %s', 'tVal');
109
+ Logger.infoP('TestP %s', 'tVal');
110
+
111
+ Logger.debug('Test %s', 'tVal');
112
+ Logger.debugP('TestP %s', 'tVal');
113
+
114
+ // These shouldnt run
115
+ Logger.verbose('Test %s', 'tVal');
116
+ Logger.verboseP('TestP %s', 'tVal');
117
+
118
+ Logger.silly('Test %s', 'tVal');
119
+ Logger.sillyP('TestP %s', 'tVal');
120
+
121
+ Logger.setLevel(LoggerLevelName.debug);
122
+ });
123
+ });
124
+
125
+ describe('#testFormatter', function () {
126
+ test('should format values', function () {
127
+ const msg: LogMessage = {
128
+ lvl: LoggerLevelName.info,
129
+ timestamp: Date.now(),
130
+ messageSource: 'Test %d %d',
131
+ subsVars: [1, 2],
132
+ params: {},
133
+ };
134
+ Logger.info('Test %d %d', 3, 4);
135
+ const msgS: string = Logger.formatMessages([msg])[0];
136
+ expect(msgS).toEqual('[info] Test 1 2');
137
+ });
138
+ });
139
+
140
+ describe('#testPreProcessor', function () {
141
+ test('should perform a preprocess', function () {
142
+ const preProc: LogMessageProcessor = {
143
+ process(msg: LogMessage): LogMessage {
144
+ msg.messageSource = 'Preprocess';
145
+ return msg;
146
+ },
147
+ };
148
+
149
+ const output: string = Logger.getLogger(StringRatchet.createRandomHexString(4), { preProcessors: [preProc] }).info(
150
+ 'This is a test %s',
151
+ 'bob',
152
+ );
153
+ expect(output).toEqual('[info] Preprocess bob');
154
+ });
155
+ });
156
+
157
+ describe('#testBuilder', function () {
158
+ test('should use a builder', function () {
159
+ const output: string = Logger.getLogger(StringRatchet.createRandomHexString(4)).recordMessageBuilder(
160
+ new LogMessageBuilder(LoggerLevelName.warn, 'This is a test %s').subVars(['bob']),
161
+ );
162
+ expect(output).toEqual('[warn] This is a test bob');
163
+ });
164
+ });
165
+
166
+ describe('#testStructured', function () {
167
+ test('should use a structured logger', function () {
168
+ const output: string = Logger.getLogger(StringRatchet.createRandomHexString(4), {
169
+ formatType: LogMessageFormatType.StructuredJson,
170
+ outputFunction: LoggerOutputFunction.StdOut,
171
+ }).recordMessageBuilder(new LogMessageBuilder(LoggerLevelName.warn, 'This is a test %s').subVars(['bob']).p('a', 27));
172
+ const parsed: any = JSON.parse(output);
173
+ expect(parsed.msg).toEqual('This is a test bob');
174
+ expect(parsed.logLevel).toEqual('warn');
175
+ expect(parsed.a).toEqual(27);
176
+ });
177
+ });