feat(handler): implement LocalStorageHandler with rotation
This commit is contained in:
parent
7479931714
commit
6fd8c22ceb
1 changed files with 108 additions and 0 deletions
108
src/handler.ts
108
src/handler.ts
|
|
@ -219,6 +219,114 @@ export class FileHandler extends StreamHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler that persists log records to browser localStorage.
|
||||||
|
*
|
||||||
|
* Records are stored as a JSON array of formatted strings under a
|
||||||
|
* configurable key. Log rotation is supported by entry count and/or
|
||||||
|
* byte size to avoid exceeding storage quotas.
|
||||||
|
*/
|
||||||
|
export interface LocalStorageHandlerOptions {
|
||||||
|
/**
|
||||||
|
* localStorage key to store entries under.
|
||||||
|
* Defaults to 'esm-logging'.
|
||||||
|
*/
|
||||||
|
key?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of entries to retain. Oldest entries are discarded
|
||||||
|
* first. Set to 0 for no entry limit. Defaults to 1000.
|
||||||
|
*/
|
||||||
|
maxEntries?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum size in bytes (as measured by the JSON-serialized string
|
||||||
|
* length). Oldest entries are discarded to stay within this limit.
|
||||||
|
* Set to 0 for no byte limit. Defaults to 0.
|
||||||
|
*/
|
||||||
|
maxBytes?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LocalStorageHandler extends Handler {
|
||||||
|
protected key: string;
|
||||||
|
protected maxEntries: number;
|
||||||
|
protected maxBytes: number;
|
||||||
|
|
||||||
|
constructor(options?: LocalStorageHandlerOptions) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (typeof localStorage === 'undefined') {
|
||||||
|
throw new NotImplementedError(
|
||||||
|
'LocalStorageHandler requires a browser environment with localStorage'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.key = options?.key ?? 'esm-logging';
|
||||||
|
this.maxEntries = options?.maxEntries ?? 1000;
|
||||||
|
this.maxBytes = options?.maxBytes ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(record: LogRecord) {
|
||||||
|
try {
|
||||||
|
const msg = this.format(record);
|
||||||
|
const entries = this.getEntries();
|
||||||
|
entries.push(msg);
|
||||||
|
this._rotate(entries);
|
||||||
|
this._setEntries(entries);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.handleError(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all stored log entries.
|
||||||
|
*/
|
||||||
|
getEntries(): string[] {
|
||||||
|
try {
|
||||||
|
const data = localStorage.getItem(this.key);
|
||||||
|
return data ? JSON.parse(data) : [];
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all stored log entries.
|
||||||
|
*/
|
||||||
|
clearEntries() {
|
||||||
|
localStorage.removeItem(this.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard oldest entries to stay within maxEntries and maxBytes limits.
|
||||||
|
*/
|
||||||
|
protected _rotate(entries: string[]) {
|
||||||
|
if (this.maxEntries > 0) {
|
||||||
|
while (entries.length > this.maxEntries) {
|
||||||
|
entries.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.maxBytes > 0) {
|
||||||
|
while (entries.length > 0) {
|
||||||
|
const serialized = JSON.stringify(entries);
|
||||||
|
if (serialized.length <= this.maxBytes) { break }
|
||||||
|
entries.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _setEntries(entries: string[]) {
|
||||||
|
localStorage.setItem(this.key, JSON.stringify(entries));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is like a StreamHandler using sys.stderr, but always uses
|
* This class is like a StreamHandler using sys.stderr, but always uses
|
||||||
* whatever sys.stderr is currently set to rather than the value of
|
* whatever sys.stderr is currently set to rather than the value of
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue