add ILogger and ILogExport interface, to give export correct return type

also move logging related types to own file
This commit is contained in:
Bruno Windels 2021-11-17 11:38:17 +01:00
parent 1b13f32d94
commit 695996d6e2
17 changed files with 119 additions and 84 deletions

View file

@ -17,10 +17,10 @@ limitations under the License.
import {LogItem} from "./LogItem"; import {LogItem} from "./LogItem";
import {LogLevel, LogFilter} from "./LogFilter"; import {LogLevel, LogFilter} from "./LogFilter";
import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogItem"; import type {ILogger, ILogExport, FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./types";
import type {Platform} from "../platform/web/Platform.js"; import type {Platform} from "../platform/web/Platform.js";
export abstract class BaseLogger { export abstract class BaseLogger implements ILogger {
protected _openItems: Set<ILogItem> = new Set(); protected _openItems: Set<ILogItem> = new Set();
protected _platform: Platform; protected _platform: Platform;
@ -141,7 +141,7 @@ export abstract class BaseLogger {
abstract _persistItem(item: ILogItem, filter?: LogFilter, forced?: boolean): void; abstract _persistItem(item: ILogItem, filter?: LogFilter, forced?: boolean): void;
abstract export(): void; abstract export(): Promise<ILogExport | undefined>;
// expose log level without needing // expose log level without needing
get level(): typeof LogLevel { get level(): typeof LogLevel {

View file

@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {BaseLogger} from "./BaseLogger"; import {BaseLogger} from "./BaseLogger";
import type {ILogItem, LogItemValues} from "./LogItem"; import type {ILogItem, LogItemValues, ILogExport} from "./types";
export class ConsoleLogger extends BaseLogger { export class ConsoleLogger extends BaseLogger {
_persistItem(item: ILogItem): void { _persistItem(item: ILogItem): void {
printToConsole(item); printToConsole(item);
} }
export(): void { async export(): Promise<ILogExport | undefined> {
throw new Error("Cannot export from ConsoleLogger"); return undefined;
} }
} }

View file

@ -26,7 +26,7 @@ import {BaseLogger} from "./BaseLogger";
import type {Interval} from "../platform/web/dom/Clock"; import type {Interval} from "../platform/web/dom/Clock";
import type {Platform} from "../platform/web/Platform.js"; import type {Platform} from "../platform/web/Platform.js";
import type {BlobHandle} from "../platform/web/dom/BlobHandle.js"; import type {BlobHandle} from "../platform/web/dom/BlobHandle.js";
import type {ILogItem} from "./LogItem"; import type {ILogItem, ILogExport} from "./types";
import type {LogFilter} from "./LogFilter"; import type {LogFilter} from "./LogFilter";
type QueuedItem = { type QueuedItem = {
@ -131,7 +131,7 @@ export class IDBLogger extends BaseLogger {
} }
} }
async export(): Promise<IDBLogExport> { async export(): Promise<ILogExport> {
const db = await this._openDB(); const db = await this._openDB();
try { try {
const txn = db.transaction(["logs"], "readonly"); const txn = db.transaction(["logs"], "readonly");
@ -171,7 +171,7 @@ export class IDBLogger extends BaseLogger {
} }
} }
class IDBLogExport { class IDBLogExport implements ILogExport {
private readonly _items: QueuedItem[]; private readonly _items: QueuedItem[];
private readonly _logger: IDBLogger; private readonly _logger: IDBLogger;
private readonly _platform: Platform; private readonly _platform: Platform;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import type {ILogItem, ISerializedItem} from "./LogItem"; import type {ILogItem, ISerializedItem} from "./types";
export enum LogLevel { export enum LogLevel {
All = 1, All = 1,

View file

@ -17,58 +17,7 @@ limitations under the License.
import {LogLevel, LogFilter} from "./LogFilter"; import {LogLevel, LogFilter} from "./LogFilter";
import type {BaseLogger} from "./BaseLogger"; import type {BaseLogger} from "./BaseLogger";
import type {ISerializedItem, ILogItem, LogItemValues, LabelOrValues, FilterCreator, LogCallback} from "./types";
export interface ISerializedItem {
s: number;
d?: number;
v: LogItemValues;
l: LogLevel;
e?: {
stack?: string;
name: string;
message: string;
};
f?: boolean;
c?: Array<ISerializedItem>;
};
export interface ILogItem {
logger: any;
level: typeof LogLevel;
duration?: number;
end?: number;
start?: number;
logLevel: LogLevel;
children?: Array<ILogItem>;
values: LogItemValues;
error?: Error;
wrap<T>(labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T;
log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void;
set(key: string | object, value: unknown): void;
run<T>(callback: LogCallback<T>): T;
runDetached(labelOrValues: LabelOrValues, callback: LogCallback<unknown>, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem;
wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback<unknown>, logLevel?: LogLevel, filterCreator?: FilterCreator): void;
refDetached(logItem: ILogItem, logLevel?: LogLevel): void;
ensureRefId(): void;
catch(err: Error): Error;
finish(): void;
child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem;
serialize(filter: LogFilter, parentStartTime: number | undefined, forced: boolean): ISerializedItem | undefined;
}
export type LogItemValues = {
l?: string;
t?: string;
id?: unknown;
status?: string | number;
refId?: number;
ref?: number;
[key: string]: any
}
export type LabelOrValues = string | LogItemValues;
export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter);
export type LogCallback<T> = (item: ILogItem) => T;
export class LogItem implements ILogItem { export class LogItem implements ILogItem {
public readonly start: number; public readonly start: number;

View file

@ -14,20 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {LogLevel} from "./LogFilter"; import {LogLevel} from "./LogFilter";
import type {ILogItem, LabelOrValues, LogCallback, LogItemValues} from "./LogItem"; import type {ILogger, ILogExport, ILogItem, LabelOrValues, LogCallback, LogItemValues} from "./types";
function noop (): void {} function noop (): void {}
export class NullLogger { export class NullLogger implements ILogger {
public readonly item: ILogItem = new NullLogItem(this); public readonly item: ILogItem = new NullLogItem(this);
log(): void {} log(): void {}
run<T>(_, callback: LogCallback<T>): T | Promise<T> { run<T>(_, callback: LogCallback<T>): T {
return callback(this.item); return callback(this.item);
} }
wrapOrRun<T>(item: ILogItem, _, callback: LogCallback<T>): T | Promise<T> { wrapOrRun<T>(item: ILogItem | undefined, _, callback: LogCallback<T>): T {
if (item) { if (item) {
return item.wrap(_, callback); return item.wrap(_, callback);
} else { } else {
@ -35,12 +35,13 @@ export class NullLogger {
} }
} }
runDetached(_, callback) { runDetached(_, callback): ILogItem {
new Promise(r => r(callback(this.item))).then(noop, noop); new Promise(r => r(callback(this.item))).then(noop, noop);
return this.item;
} }
async export(): Promise<null> { async export(): Promise<ILogExport | undefined> {
return null; return undefined;
} }
get level(): typeof LogLevel { get level(): typeof LogLevel {

87
src/logging/types.ts Normal file
View file

@ -0,0 +1,87 @@
/*
Copyright 2020 Bruno Windels <bruno@windels.cloud>
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {LogLevel, LogFilter} from "./LogFilter";
import type {BaseLogger} from "./BaseLogger";
import type {BlobHandle} from "../platform/web/dom/BlobHandle.js";
export interface ISerializedItem {
s: number;
d?: number;
v: LogItemValues;
l: LogLevel;
e?: {
stack?: string;
name: string;
message: string;
};
f?: boolean;
c?: Array<ISerializedItem>;
};
export interface ILogItem {
logger: any;
level: typeof LogLevel;
duration?: number;
end?: number;
start?: number;
logLevel: LogLevel;
children?: Array<ILogItem>;
values: LogItemValues;
error?: Error;
wrap<T>(labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T;
log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void;
set(key: string | object, value: unknown): void;
run<T>(callback: LogCallback<T>): T;
runDetached(labelOrValues: LabelOrValues, callback: LogCallback<unknown>, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem;
wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback<unknown>, logLevel?: LogLevel, filterCreator?: FilterCreator): void;
refDetached(logItem: ILogItem, logLevel?: LogLevel): void;
ensureRefId(): void;
catch(err: Error): Error;
finish(): void;
child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem;
serialize(filter: LogFilter, parentStartTime: number | undefined, forced: boolean): ISerializedItem | undefined;
}
export interface ILogger {
log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void;
wrapOrRun<T>(item: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T;
runDetached<T>(labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem;
run<T>(labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T;
export(): Promise<ILogExport | undefined>;
get level(): typeof LogLevel;
}
export interface ILogExport {
get count(): number;
removeFromStore(): Promise<void>;
asBlob(): BlobHandle;
}
export type LogItemValues = {
l?: string;
t?: string;
id?: unknown;
status?: string | number;
refId?: number;
ref?: number;
[key: string]: any
}
export type LabelOrValues = string | LogItemValues;
export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter);
export type LogCallback<T> = (item: ILogItem) => T;

View file

@ -2,7 +2,7 @@
// if you know you always have a log item, better to use the methods on the log item than these utility functions. // if you know you always have a log item, better to use the methods on the log item than these utility functions.
import {Instance as NullLoggerInstance} from "./NullLogger"; import {Instance as NullLoggerInstance} from "./NullLogger";
import type {FilterCreator, ILogItem, LabelOrValues, LogCallback} from "./LogItem"; import type {FilterCreator, ILogItem, LabelOrValues, LogCallback} from "./types";
import {LogLevel} from "./LogFilter"; import {LogLevel} from "./LogFilter";
export function wrapOrRunNullLogger<T>(logItem: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise<T> { export function wrapOrRunNullLogger<T>(logItem: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback<T>, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise<T> {

View file

@ -26,7 +26,7 @@ import type {OlmWorker} from "../OlmWorker";
import type {Transaction} from "../../storage/idb/Transaction"; import type {Transaction} from "../../storage/idb/Transaction";
import type {TimelineEvent} from "../../storage/types"; import type {TimelineEvent} from "../../storage/types";
import type {DecryptionResult} from "../DecryptionResult"; import type {DecryptionResult} from "../DecryptionResult";
import type {ILogItem} from "../../../logging/LogItem"; import type {ILogItem} from "../../../logging/types";
export class Decryption { export class Decryption {
private keyLoader: KeyLoader; private keyLoader: KeyLoader;

View file

@ -16,7 +16,7 @@ limitations under the License.
import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils"; import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils";
import {StorageError} from "../common"; import {StorageError} from "../common";
import {ILogItem} from "../../../logging/LogItem"; import {ILogItem} from "../../../logging/types";
import {IDBKey} from "./Transaction"; import {IDBKey} from "./Transaction";
// this is the part of the Transaction class API that is used here and in the Store subclass, // this is the part of the Transaction class API that is used here and in the Store subclass,

View file

@ -18,7 +18,7 @@ import {IDOMStorage} from "./types";
import {Transaction} from "./Transaction"; import {Transaction} from "./Transaction";
import { STORE_NAMES, StoreNames, StorageError } from "../common"; import { STORE_NAMES, StoreNames, StorageError } from "../common";
import { reqAsPromise } from "./utils"; import { reqAsPromise } from "./utils";
import { BaseLogger } from "../../../logging/BaseLogger"; import { ILogger } from "../../../logging/types";
const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey"; const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey";
@ -26,13 +26,13 @@ export class Storage {
private _db: IDBDatabase; private _db: IDBDatabase;
private _hasWebkitEarlyCloseTxnBug: boolean; private _hasWebkitEarlyCloseTxnBug: boolean;
readonly logger: BaseLogger; readonly logger: ILogger;
readonly idbFactory: IDBFactory readonly idbFactory: IDBFactory
readonly IDBKeyRange: typeof IDBKeyRange; readonly IDBKeyRange: typeof IDBKeyRange;
readonly storeNames: typeof StoreNames; readonly storeNames: typeof StoreNames;
readonly localStorage: IDOMStorage; readonly localStorage: IDOMStorage;
constructor(idbDatabase: IDBDatabase, idbFactory: IDBFactory, _IDBKeyRange: typeof IDBKeyRange, hasWebkitEarlyCloseTxnBug: boolean, localStorage: IDOMStorage, logger: BaseLogger) { constructor(idbDatabase: IDBDatabase, idbFactory: IDBFactory, _IDBKeyRange: typeof IDBKeyRange, hasWebkitEarlyCloseTxnBug: boolean, localStorage: IDOMStorage, logger: ILogger) {
this._db = idbDatabase; this._db = idbDatabase;
this.idbFactory = idbFactory; this.idbFactory = idbFactory;
this.IDBKeyRange = _IDBKeyRange; this.IDBKeyRange = _IDBKeyRange;

View file

@ -20,8 +20,7 @@ import { openDatabase, reqAsPromise } from "./utils";
import { exportSession, importSession, Export } from "./export"; import { exportSession, importSession, Export } from "./export";
import { schema } from "./schema"; import { schema } from "./schema";
import { detectWebkitEarlyCloseTxnBug } from "./quirks"; import { detectWebkitEarlyCloseTxnBug } from "./quirks";
import { BaseLogger } from "../../../logging/BaseLogger"; import { ILogItem } from "../../../logging/types";
import { ILogItem } from "../../../logging/LogItem";
const sessionName = (sessionId: string) => `hydrogen_session_${sessionId}`; const sessionName = (sessionId: string) => `hydrogen_session_${sessionId}`;
const openDatabaseWithSessionId = function(sessionId: string, idbFactory: IDBFactory, localStorage: IDOMStorage, log: ILogItem) { const openDatabaseWithSessionId = function(sessionId: string, idbFactory: IDBFactory, localStorage: IDOMStorage, log: ILogItem) {

View file

@ -18,7 +18,7 @@ import {QueryTarget, IDBQuery, ITransaction} from "./QueryTarget";
import {IDBRequestError, IDBRequestAttemptError} from "./error"; import {IDBRequestError, IDBRequestAttemptError} from "./error";
import {reqAsPromise} from "./utils"; import {reqAsPromise} from "./utils";
import {Transaction, IDBKey} from "./Transaction"; import {Transaction, IDBKey} from "./Transaction";
import {ILogItem} from "../../../logging/LogItem"; import {ILogItem} from "../../../logging/types";
const LOG_REQUESTS = false; const LOG_REQUESTS = false;

View file

@ -36,8 +36,7 @@ import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore";
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore"; import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore";
import {OperationStore} from "./stores/OperationStore"; import {OperationStore} from "./stores/OperationStore";
import {AccountDataStore} from "./stores/AccountDataStore"; import {AccountDataStore} from "./stores/AccountDataStore";
import {ILogItem} from "../../../logging/LogItem"; import type {ILogger, ILogItem} from "../../../logging/types";
import {BaseLogger} from "../../../logging/BaseLogger";
export type IDBKey = IDBValidKey | IDBKeyRange; export type IDBKey = IDBValidKey | IDBKeyRange;
@ -77,7 +76,7 @@ export class Transaction {
return this._storage.databaseName; return this._storage.databaseName;
} }
get logger(): BaseLogger { get logger(): ILogger {
return this._storage.logger; return this._storage.logger;
} }

View file

@ -11,7 +11,7 @@ import {SessionStore} from "./stores/SessionStore";
import {Store} from "./Store"; import {Store} from "./Store";
import {encodeScopeTypeKey} from "./stores/OperationStore"; import {encodeScopeTypeKey} from "./stores/OperationStore";
import {MAX_UNICODE} from "./stores/common"; import {MAX_UNICODE} from "./stores/common";
import {ILogItem} from "../../../logging/LogItem"; import {ILogItem} from "../../../logging/types";
export type MigrationFunc = (db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) => Promise<void> | void; export type MigrationFunc = (db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) => Promise<void> | void;

View file

@ -16,8 +16,8 @@ limitations under the License.
import {Store} from "../Store"; import {Store} from "../Store";
import {IDOMStorage} from "../types"; import {IDOMStorage} from "../types";
import {SESSION_E2EE_KEY_PREFIX} from "../../../e2ee/common.js"; import {SESSION_E2EE_KEY_PREFIX} from "../../../e2ee/common.js";
import {ILogItem} from "../../../../logging/LogItem";
import {parse, stringify} from "../../../../utils/typedJSON"; import {parse, stringify} from "../../../../utils/typedJSON";
import type {ILogItem} from "../../../../logging/types";
export interface SessionEntry { export interface SessionEntry {
key: string; key: string;

View file

@ -20,7 +20,7 @@ import { encodeUint32, decodeUint32 } from "../utils";
import {KeyLimits} from "../../common"; import {KeyLimits} from "../../common";
import {Store} from "../Store"; import {Store} from "../Store";
import {TimelineEvent, StateEvent} from "../../types"; import {TimelineEvent, StateEvent} from "../../types";
import {ILogItem} from "../../../../logging/LogItem"; import {ILogItem} from "../../../../logging/types";
interface Annotation { interface Annotation {
count: number; count: number;