Rework BufferLogAppender buffer sizing logic to be more performant in the face of heavy throughput.
This commit is contained in:
@@ -1,13 +1,44 @@
|
||||
import type { LogAppender } from './log-appender'
|
||||
import { LogLevel, type LogMessage } from './log-message'
|
||||
import { clamp } from './util'
|
||||
|
||||
export interface BufferSizeBounds {
|
||||
target: number
|
||||
max: number
|
||||
}
|
||||
|
||||
export class BufferLogAppender implements LogAppender {
|
||||
public threshold: LogLevel
|
||||
public buffer: LogMessage[]
|
||||
public bufferMax?: number
|
||||
|
||||
constructor(buffer?: LogMessage[], threshold?: LogLevel) {
|
||||
this.buffer = buffer ?? []
|
||||
private _size?: BufferSizeBounds
|
||||
|
||||
public get size() {
|
||||
return this._size === undefined ? undefined : { ...this._size }
|
||||
}
|
||||
|
||||
public set size(s: {target: number, max?: number} | undefined) {
|
||||
if (s === undefined) {
|
||||
this._size = undefined
|
||||
} else {
|
||||
const target = clamp(s.target, { min: 1 })
|
||||
this._size = {
|
||||
target,
|
||||
max: s.max === undefined
|
||||
? clamp(target * 1.2, { min: target + 1 })
|
||||
: clamp(s.max, { min: target + 1 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(threshold?: LogLevel, size?: {target: number, max?: number}) {
|
||||
if (size !== undefined && typeof size === 'object') {
|
||||
this.size = size
|
||||
} else {
|
||||
this._size = { target: 1000, max: 1200 }
|
||||
}
|
||||
|
||||
this.buffer = []
|
||||
this.threshold = threshold ?? LogLevel.ALL
|
||||
}
|
||||
|
||||
@@ -16,15 +47,32 @@ export class BufferLogAppender implements LogAppender {
|
||||
|
||||
this.buffer.push(msg)
|
||||
|
||||
if (this.bufferMax !== undefined) {
|
||||
const max = Math.max(0, this.bufferMax)
|
||||
while (this.buffer.length > max) {
|
||||
this.buffer.shift()
|
||||
if (this._size !== undefined) {
|
||||
|
||||
if (this._size.max <= this._size.target) {
|
||||
// This should be impossible, so if it happens, I want to know.
|
||||
const oldSize = this.size
|
||||
this.size = { target: this._size.target }
|
||||
this.buffer.push({
|
||||
scope: '@jdbernard/js-logging/buffer-log-appender.ts',
|
||||
level: LogLevel.ERROR,
|
||||
msg: {
|
||||
msg: 'BufferLogAppender misconfigured: max size was not greater ' +
|
||||
'than target size. Reconfiguring.',
|
||||
oldSize,
|
||||
newSize: this.size
|
||||
},
|
||||
ts: new Date()
|
||||
})
|
||||
}
|
||||
|
||||
if (this.buffer.length > this._size.max) {
|
||||
this.buffer = this.buffer.slice(-this._size.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public clearBuffer(): void {
|
||||
this.buffer.length = 0
|
||||
this.buffer = []
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -10,3 +10,14 @@ export function omit(
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function clamp(
|
||||
val: number,
|
||||
bounds?: { min?: number, max?: number},
|
||||
allowFloats?: boolean ): number {
|
||||
let clamped = val
|
||||
if (!allowFloats) clamped = Math.floor(clamped)
|
||||
if (bounds?.min !== undefined) clamped = Math.max(bounds?.min, clamped)
|
||||
if (bounds?.max !== undefined) clamped = Math.min(bounds?.max, clamped)
|
||||
return clamped
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user