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 type { LogAppender } from './log-appender'
|
||||||
import { LogLevel, type LogMessage } from './log-message'
|
import { LogLevel, type LogMessage } from './log-message'
|
||||||
|
import { clamp } from './util'
|
||||||
|
|
||||||
|
export interface BufferSizeBounds {
|
||||||
|
target: number
|
||||||
|
max: number
|
||||||
|
}
|
||||||
|
|
||||||
export class BufferLogAppender implements LogAppender {
|
export class BufferLogAppender implements LogAppender {
|
||||||
public threshold: LogLevel
|
public threshold: LogLevel
|
||||||
public buffer: LogMessage[]
|
public buffer: LogMessage[]
|
||||||
public bufferMax?: number
|
|
||||||
|
|
||||||
constructor(buffer?: LogMessage[], threshold?: LogLevel) {
|
private _size?: BufferSizeBounds
|
||||||
this.buffer = buffer ?? []
|
|
||||||
|
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
|
this.threshold = threshold ?? LogLevel.ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,15 +47,32 @@ export class BufferLogAppender implements LogAppender {
|
|||||||
|
|
||||||
this.buffer.push(msg)
|
this.buffer.push(msg)
|
||||||
|
|
||||||
if (this.bufferMax !== undefined) {
|
if (this._size !== undefined) {
|
||||||
const max = Math.max(0, this.bufferMax)
|
|
||||||
while (this.buffer.length > max) {
|
if (this._size.max <= this._size.target) {
|
||||||
this.buffer.shift()
|
// 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 {
|
public clearBuffer(): void {
|
||||||
this.buffer.length = 0
|
this.buffer = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -10,3 +10,14 @@ export function omit(
|
|||||||
}
|
}
|
||||||
return result
|
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