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 {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";
export abstract class BaseLogger {
export abstract class BaseLogger implements ILogger {
protected _openItems: Set<ILogItem> = new Set();
protected _platform: Platform;
@ -141,7 +141,7 @@ export abstract class BaseLogger {
abstract _persistItem(item: ILogItem, filter?: LogFilter, forced?: boolean): void;
abstract export(): void;
abstract export(): Promise<ILogExport | undefined>;
// expose log level without needing
get level(): typeof LogLevel {

View file

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

View file

@ -26,7 +26,7 @@ import {BaseLogger} from "./BaseLogger";
import type {Interval} from "../platform/web/dom/Clock";
import type {Platform} from "../platform/web/Platform.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";
type QueuedItem = {
@ -131,7 +131,7 @@ export class IDBLogger extends BaseLogger {
}
}
async export(): Promise<IDBLogExport> {
async export(): Promise<ILogExport> {
const db = await this._openDB();
try {
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 _logger: IDBLogger;
private readonly _platform: Platform;

View file

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

View file

@ -17,58 +17,7 @@ limitations under the License.
import {LogLevel, LogFilter} from "./LogFilter";
import type {BaseLogger} from "./BaseLogger";
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;
import type {ISerializedItem, ILogItem, LogItemValues, LabelOrValues, FilterCreator, LogCallback} from "./types";
export class LogItem implements ILogItem {
public readonly start: number;

View file

@ -14,20 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
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 {}
export class NullLogger {
export class NullLogger implements ILogger {
public readonly item: ILogItem = new NullLogItem(this);
log(): void {}
run<T>(_, callback: LogCallback<T>): T | Promise<T> {
run<T>(_, callback: LogCallback<T>): T {
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) {
return item.wrap(_, callback);
} else {
@ -35,12 +35,13 @@ export class NullLogger {
}
}
runDetached(_, callback) {
runDetached(_, callback): ILogItem {
new Promise(r => r(callback(this.item))).then(noop, noop);
return this.item;
}
async export(): Promise<null> {
return null;
async export(): Promise<ILogExport | undefined> {
return undefined;
}
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.
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";
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 {TimelineEvent} from "../../storage/types";
import type {DecryptionResult} from "../DecryptionResult";
import type {ILogItem} from "../../../logging/LogItem";
import type {ILogItem} from "../../../logging/types";
export class Decryption {
private keyLoader: KeyLoader;

View file

@ -16,7 +16,7 @@ limitations under the License.
import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils";
import {StorageError} from "../common";
import {ILogItem} from "../../../logging/LogItem";
import {ILogItem} from "../../../logging/types";
import {IDBKey} from "./Transaction";
// 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 { STORE_NAMES, StoreNames, StorageError } from "../common";
import { reqAsPromise } from "./utils";
import { BaseLogger } from "../../../logging/BaseLogger";
import { ILogger } from "../../../logging/types";
const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey";
@ -26,13 +26,13 @@ export class Storage {
private _db: IDBDatabase;
private _hasWebkitEarlyCloseTxnBug: boolean;
readonly logger: BaseLogger;
readonly logger: ILogger;
readonly idbFactory: IDBFactory
readonly IDBKeyRange: typeof IDBKeyRange;
readonly storeNames: typeof StoreNames;
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.idbFactory = idbFactory;
this.IDBKeyRange = _IDBKeyRange;

View file

@ -20,8 +20,7 @@ import { openDatabase, reqAsPromise } from "./utils";
import { exportSession, importSession, Export } from "./export";
import { schema } from "./schema";
import { detectWebkitEarlyCloseTxnBug } from "./quirks";
import { BaseLogger } from "../../../logging/BaseLogger";
import { ILogItem } from "../../../logging/LogItem";
import { ILogItem } from "../../../logging/types";
const sessionName = (sessionId: string) => `hydrogen_session_${sessionId}`;
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 {reqAsPromise} from "./utils";
import {Transaction, IDBKey} from "./Transaction";
import {ILogItem} from "../../../logging/LogItem";
import {ILogItem} from "../../../logging/types";
const LOG_REQUESTS = false;

View file

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

View file

@ -11,7 +11,7 @@ import {SessionStore} from "./stores/SessionStore";
import {Store} from "./Store";
import {encodeScopeTypeKey} from "./stores/OperationStore";
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;

View file

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

View file

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