Skip to content

Commit 8203016

Browse files
feat(logger): Enable log buffering feature (#3641)
Co-authored-by: Andrea Amorosi <[email protected]>
1 parent e03d5ce commit 8203016

File tree

3 files changed

+285
-119
lines changed

3 files changed

+285
-119
lines changed

Diff for: packages/logger/src/Logger.ts

+50-10
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,26 @@ class Logger extends Utility implements LoggerInterface {
174174
*/
175175
protected isBufferEnabled = false;
176176

177+
/**
178+
* Whether the buffer should be flushed when an error is logged
179+
*/
180+
protected flushOnErrorLog = true;
177181
/**
178182
* Log level threshold for the buffer
179183
* Logs with a level lower than this threshold will be buffered
184+
* Default is DEBUG
180185
*/
181-
protected bufferLogThreshold: number = LogLevelThreshold.DEBUG;
186+
protected bufferAtVerbosity: number = LogLevelThreshold.DEBUG;
182187
/**
183188
* Max size of the buffer. Additions to the buffer beyond this size will
184189
* cause older logs to be evicted from the buffer
185190
*/
186-
readonly #maxBufferBytesSize = 1024;
191+
#maxBufferBytesSize = 20480;
187192

188193
/**
189194
* Contains buffered logs, grouped by _X_AMZN_TRACE_ID, each group with a max size of `maxBufferBytesSize`
190195
*/
191-
readonly #buffer: CircularMap<string> = new CircularMap({
192-
maxBytesSize: this.#maxBufferBytesSize,
193-
});
196+
#buffer?: CircularMap<string>;
194197

195198
/**
196199
* Log level used by the current instance of Logger.
@@ -330,6 +333,9 @@ class Logger extends Utility implements LoggerInterface {
330333
* @param extraInput - The extra input to log.
331334
*/
332335
public error(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
336+
if (this.isBufferEnabled && this.flushOnErrorLog) {
337+
this.flushBuffer();
338+
}
333339
this.processLogItem(LogLevelThreshold.ERROR, input, extraInput);
334340
}
335341

@@ -1167,6 +1173,7 @@ class Logger extends Utility implements LoggerInterface {
11671173
environment,
11681174
jsonReplacerFn,
11691175
logRecordOrder,
1176+
logBufferOptions,
11701177
} = options;
11711178

11721179
if (persistentLogAttributes && persistentKeys) {
@@ -1193,6 +1200,10 @@ class Logger extends Utility implements LoggerInterface {
11931200
this.setLogIndentation();
11941201
this.#jsonReplacerFn = jsonReplacerFn;
11951202

1203+
if (logBufferOptions !== undefined) {
1204+
this.#setLogBuffering(logBufferOptions);
1205+
}
1206+
11961207
return this;
11971208
}
11981209

@@ -1223,6 +1234,35 @@ class Logger extends Utility implements LoggerInterface {
12231234
persistentKeys && this.appendPersistentKeys(persistentKeys);
12241235
}
12251236

1237+
#setLogBuffering(
1238+
options: NonNullable<ConstructorOptions['logBufferOptions']>
1239+
) {
1240+
if (options.maxBytes !== undefined) {
1241+
this.#maxBufferBytesSize = options.maxBytes;
1242+
}
1243+
1244+
this.#buffer = new CircularMap({
1245+
maxBytesSize: this.#maxBufferBytesSize,
1246+
});
1247+
1248+
if (options.enabled === false) {
1249+
this.isBufferEnabled = false;
1250+
} else {
1251+
this.isBufferEnabled = true;
1252+
}
1253+
1254+
if (options.flushOnErrorLog === false) {
1255+
this.flushOnErrorLog = false;
1256+
} else {
1257+
this.flushOnErrorLog = true;
1258+
}
1259+
const bufferAtLogLevel = options.bufferAtVerbosity?.toUpperCase();
1260+
1261+
if (this.isValidLogLevel(bufferAtLogLevel)) {
1262+
this.bufferAtVerbosity = LogLevelThreshold[bufferAtLogLevel];
1263+
}
1264+
}
1265+
12261266
/**
12271267
* Add a log to the buffer
12281268
* @param xrayTraceId - _X_AMZN_TRACE_ID of the request
@@ -1242,20 +1282,20 @@ class Logger extends Utility implements LoggerInterface {
12421282
this.logIndentation
12431283
);
12441284

1245-
this.#buffer.setItem(xrayTraceId, stringified, logLevel);
1285+
this.#buffer?.setItem(xrayTraceId, stringified, logLevel);
12461286
}
12471287

12481288
/**
12491289
* Flushes all items of the respective _X_AMZN_TRACE_ID within
12501290
* the buffer.
12511291
*/
1252-
protected flushBuffer(): void {
1292+
public flushBuffer(): void {
12531293
const traceId = this.envVarsService.getXrayTraceId();
12541294
if (traceId === undefined) {
12551295
return;
12561296
}
12571297

1258-
const buffer = this.#buffer.get(traceId);
1298+
const buffer = this.#buffer?.get(traceId);
12591299
if (buffer === undefined) {
12601300
return;
12611301
}
@@ -1280,7 +1320,7 @@ class Logger extends Utility implements LoggerInterface {
12801320
);
12811321
}
12821322

1283-
this.#buffer.delete(traceId);
1323+
this.#buffer?.delete(traceId);
12841324
}
12851325
/**
12861326
* Tests if the log meets the criteria to be buffered
@@ -1294,7 +1334,7 @@ class Logger extends Utility implements LoggerInterface {
12941334
return (
12951335
this.isBufferEnabled &&
12961336
traceId !== undefined &&
1297-
logLevel <= this.bufferLogThreshold
1337+
logLevel <= this.bufferAtVerbosity
12981338
);
12991339
}
13001340
}

Diff for: packages/logger/src/types/Logger.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,46 @@ type LogRecordOrderOption = {
173173
logFormatter?: never;
174174
};
175175

176+
/**
177+
* Options for the `logBuffer` constructor option.
178+
*
179+
* Used to configure the log buffer functionality.
180+
*/
181+
type LogBufferOption = {
182+
logBufferOptions?: {
183+
/**
184+
* Whether logs should be buffered
185+
*/
186+
enabled?: boolean;
187+
/**
188+
* Maximum size of the buffer in bytes
189+
* @default `20480`
190+
*/
191+
maxBytes?: number;
192+
/**
193+
* Flush the buffer when an error is logged
194+
* @default `true`
195+
*/
196+
flushOnErrorLog?: boolean;
197+
/**
198+
* The threshold to buffer logs. Logs with a level below
199+
* this threshold will be buffered
200+
* @default `'DEBUG'`
201+
*/
202+
bufferAtVerbosity?: Omit<
203+
LogLevel,
204+
'ERROR' | 'error' | 'CRITICAL' | 'critical' | 'SILENT' | 'silent'
205+
>;
206+
};
207+
};
208+
176209
/**
177210
* Options to configure the Logger.
178211
*/
179212
type ConstructorOptions = BaseConstructorOptions &
180213
(PersistentKeysOption | DeprecatedPersistentKeysOption) &
181-
(LogFormatterOption | LogRecordOrderOption);
214+
(LogFormatterOption | LogRecordOrderOption) &
215+
LogBufferOption;
182216

183217
type LogItemMessage = string | LogAttributesWithMessage;
184218
type LogItemExtraInput = [Error | string] | LogAttributes[];
@@ -194,6 +228,7 @@ type LoggerInterface = {
194228
critical(input: LogItemMessage, ...extraInput: LogItemExtraInput): void;
195229
debug(input: LogItemMessage, ...extraInput: LogItemExtraInput): void;
196230
error(input: LogItemMessage, ...extraInput: LogItemExtraInput): void;
231+
flushBuffer(): void;
197232
getLevelName(): Uppercase<LogLevel>;
198233
getLogEvent(): boolean;
199234
getPersistentLogAttributes(): LogAttributes;

0 commit comments

Comments
 (0)