From dad37dece339ec18af53030b20754d48e11a16c2 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 11:46:05 +0530 Subject: [PATCH 01/78] .js --> .ts --- src/logging/{BaseLogger.js => BaseLogger.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/logging/{BaseLogger.js => BaseLogger.ts} (100%) diff --git a/src/logging/BaseLogger.js b/src/logging/BaseLogger.ts similarity index 100% rename from src/logging/BaseLogger.js rename to src/logging/BaseLogger.ts From 030c46264b2e91b5271da67859a9de4d350448a2 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 13:00:37 +0530 Subject: [PATCH 02/78] type annotate fields --- src/logging/BaseLogger.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 584c763b..51a32485 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -17,8 +17,12 @@ limitations under the License. import {LogItem} from "./LogItem.js"; import {LogLevel, LogFilter} from "./LogFilter.js"; +import {Platform} from "../platform/web/Platform.js"; export class BaseLogger { + protected _openItems: Set; + protected _platform: Platform; + constructor({platform}) { this._openItems = new Set(); this._platform = platform; From 377cc4ca1fb89fb576520ad8928bd9d7079a0bff Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 13:52:41 +0530 Subject: [PATCH 03/78] Make BaseLogger abstract --- src/logging/BaseLogger.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 51a32485..d45c2fd3 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -19,7 +19,7 @@ import {LogItem} from "./LogItem.js"; import {LogLevel, LogFilter} from "./LogFilter.js"; import {Platform} from "../platform/web/Platform.js"; -export class BaseLogger { +export abstract class BaseLogger { protected _openItems: Set; protected _platform: Platform; @@ -131,13 +131,9 @@ export class BaseLogger { this._openItems.clear(); } - _persistItem() { - throw new Error("not implemented"); - } + abstract _persistItem(item: LogItem, filter?: LogFilter, forced?: boolean): void; - async export() { - throw new Error("not implemented"); - } + abstract export(): void; // expose log level without needing get level() { From 839d3fb6899cf32d898bb704799a78b2a5d92f5e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 13:53:07 +0530 Subject: [PATCH 04/78] Throw on export() in ConsoleLogger --- src/logging/ConsoleLogger.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logging/ConsoleLogger.js b/src/logging/ConsoleLogger.js index 9610795f..aacbf132 100644 --- a/src/logging/ConsoleLogger.js +++ b/src/logging/ConsoleLogger.js @@ -19,6 +19,10 @@ export class ConsoleLogger extends BaseLogger { _persistItem(item) { printToConsole(item); } + + export() { + throw new Error("Cannot export from ConsoleLogger"); + } } const excludedKeysFromTable = ["l", "id"]; From eef116e26b087d68efb71f544d769ddf25ef53a7 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 17:19:46 +0530 Subject: [PATCH 05/78] annotate labelOrValues --- src/logging/BaseLogger.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index d45c2fd3..ab2d600b 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -19,6 +19,9 @@ import {LogItem} from "./LogItem.js"; import {LogLevel, LogFilter} from "./LogFilter.js"; import {Platform} from "../platform/web/Platform.js"; +// todo: move this to LogItem? +type LabelOrValues = string | {l: string; [key: string]: any}; + export abstract class BaseLogger { protected _openItems: Set; protected _platform: Platform; @@ -28,14 +31,14 @@ export abstract class BaseLogger { this._platform = platform; } - log(labelOrValues, logLevel = LogLevel.Info) { + log(labelOrValues: LabelOrValues, logLevel: number = LogLevel.Info) { const item = new LogItem(labelOrValues, logLevel, null, this); item._end = item._start; this._persistItem(item, null, false); } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item, labelOrValues, callback, logLevel = null, filterCreator = null) { + wrapOrRun(item, labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -48,7 +51,7 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues, callback, logLevel = null, filterCreator = null) { + runDetached(labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } @@ -60,7 +63,7 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues, callback, logLevel = null, filterCreator = null) { + run(labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } From 4c5d0285091ae4e3eba5e50ca66fa05a8888301f Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 17:34:16 +0530 Subject: [PATCH 06/78] any --> unknown --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index ab2d600b..bd9b6811 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -20,7 +20,7 @@ import {LogLevel, LogFilter} from "./LogFilter.js"; import {Platform} from "../platform/web/Platform.js"; // todo: move this to LogItem? -type LabelOrValues = string | {l: string; [key: string]: any}; +type LabelOrValues = string | {l: string; [key: string]: unknown}; export abstract class BaseLogger { protected _openItems: Set; From 7893a121c0d85cf8e747cbfa82005444a96316de Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 17:36:18 +0530 Subject: [PATCH 07/78] Initialize in field --- src/logging/BaseLogger.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index bd9b6811..311af22d 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -23,11 +23,10 @@ import {Platform} from "../platform/web/Platform.js"; type LabelOrValues = string | {l: string; [key: string]: unknown}; export abstract class BaseLogger { - protected _openItems: Set; + protected _openItems: Set = new Set(); protected _platform: Platform; constructor({platform}) { - this._openItems = new Set(); this._platform = platform; } From 8cbc81b8bb715f4d3f0bb441998459c5276af6cc Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 20:57:47 +0530 Subject: [PATCH 08/78] Annotate method arguments --- src/logging/BaseLogger.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 311af22d..7117f9d9 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -21,6 +21,10 @@ import {Platform} from "../platform/web/Platform.js"; // todo: move this to LogItem? type LabelOrValues = string | {l: string; [key: string]: unknown}; +type LogCallback = (item: LogItem) => Promise | undefined; +// todo: this should be an enum +type LogLevel = number | null; +type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; export abstract class BaseLogger { protected _openItems: Set = new Set(); @@ -37,7 +41,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item, labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { + wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -50,27 +54,27 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, null, this); - this._run(item, callback, logLevel, filterCreator, false /* don't throw, nobody is awaiting */); + this._run(item, callback, logLevel!, filterCreator, false /* don't throw, nobody is awaiting */); return item; } /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback, logLevel = null, filterCreator = null) { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, null, this); - return this._run(item, callback, logLevel, filterCreator, true); + return this._run(item, callback, logLevel!, filterCreator, true); } - _run(item, callback, logLevel, filterCreator, shouldThrow) { + _run(item: LogItem, callback: LogCallback, logLevel: number, filterCreator: FilterCreator, shouldThrow: boolean) { this._openItems.add(item); const finishItem = () => { From 55401a746c6d46e57fedfdb75932bf8e109247b7 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 22:28:26 +0530 Subject: [PATCH 09/78] Move type alias to LogItem and add more type annotations --- src/logging/BaseLogger.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 7117f9d9..27dd4983 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -15,16 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LogItem} from "./LogItem.js"; +import {LogItem, LabelOrValues, FilterCreator} from "./LogItem"; import {LogLevel, LogFilter} from "./LogFilter.js"; import {Platform} from "../platform/web/Platform.js"; -// todo: move this to LogItem? -type LabelOrValues = string | {l: string; [key: string]: unknown}; type LogCallback = (item: LogItem) => Promise | undefined; -// todo: this should be an enum -type LogLevel = number | null; -type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; export abstract class BaseLogger { protected _openItems: Set = new Set(); @@ -36,7 +31,7 @@ export abstract class BaseLogger { log(labelOrValues: LabelOrValues, logLevel: number = LogLevel.Info) { const item = new LogItem(labelOrValues, logLevel, null, this); - item._end = item._start; + item.end = item.start; this._persistItem(item, null, false); } @@ -146,7 +141,7 @@ export abstract class BaseLogger { return LogLevel; } - _now() { + _now(): number { return this._platform.clock.now(); } From 2a5d30d749e5a401f33b860f591d532e9c415d9e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 9 Nov 2021 22:32:02 +0530 Subject: [PATCH 10/78] Convert to enum --- src/logging/LogFilter.ts | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/logging/LogFilter.ts diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts new file mode 100644 index 00000000..83f71891 --- /dev/null +++ b/src/logging/LogFilter.ts @@ -0,0 +1,54 @@ +/* +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. +*/ + + +export enum LogLevel { + All = 1, + Debug, + Detail, + Info, + Warn, + Error, + Fatal, + Off +} + +export class LogFilter { + constructor(parentFilter) { + this._parentFilter = parentFilter; + this._min = null; + } + + filter(item, children) { + if (this._parentFilter) { + if (!this._parentFilter.filter(item, children)) { + return false; + } + } + // neither our children or us have a loglevel high enough, filter out. + if (this._min !== null && !Array.isArray(children) && item.logLevel < this._min) { + return false; + } else { + return true; + } + } + + /* methods to build the filter */ + minLevel(logLevel) { + this._min = logLevel; + return this; + } +} From ba4d5453a23ca7185142d628785b758aa1aefdfc Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 12:05:29 +0530 Subject: [PATCH 11/78] Move type LogCallback to LogItem --- src/logging/BaseLogger.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 27dd4983..c47329c2 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -15,11 +15,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LogItem, LabelOrValues, FilterCreator} from "./LogItem"; +import {LogItem, LabelOrValues, FilterCreator, LogCallback} from "./LogItem"; import {LogLevel, LogFilter} from "./LogFilter.js"; import {Platform} from "../platform/web/Platform.js"; -type LogCallback = (item: LogItem) => Promise | undefined; export abstract class BaseLogger { protected _openItems: Set = new Set(); From 97ec680af2af2676d2ba1faa238198840571c79e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 12:06:22 +0530 Subject: [PATCH 12/78] Remove .js files --- src/logging/LogFilter.js | 53 --------- src/logging/LogItem.js | 242 --------------------------------------- 2 files changed, 295 deletions(-) delete mode 100644 src/logging/LogFilter.js delete mode 100644 src/logging/LogItem.js diff --git a/src/logging/LogFilter.js b/src/logging/LogFilter.js deleted file mode 100644 index 81bbb33c..00000000 --- a/src/logging/LogFilter.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -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. -*/ - -export const LogLevel = { - All: 1, - Debug: 2, - Detail: 3, - Info: 4, - Warn: 5, - Error: 6, - Fatal: 7, - Off: 8, -} - -export class LogFilter { - constructor(parentFilter) { - this._parentFilter = parentFilter; - this._min = null; - } - - filter(item, children) { - if (this._parentFilter) { - if (!this._parentFilter.filter(item, children)) { - return false; - } - } - // neither our children or us have a loglevel high enough, filter out. - if (this._min !== null && !Array.isArray(children) && item.logLevel < this._min) { - return false; - } else { - return true; - } - } - - /* methods to build the filter */ - minLevel(logLevel) { - this._min = logLevel; - return this; - } -} diff --git a/src/logging/LogItem.js b/src/logging/LogItem.js deleted file mode 100644 index 90747964..00000000 --- a/src/logging/LogItem.js +++ /dev/null @@ -1,242 +0,0 @@ -/* -Copyright 2020 Bruno Windels -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.js"; - -export class LogItem { - constructor(labelOrValues, logLevel, filterCreator, logger) { - this._logger = logger; - this._start = logger._now(); - this._end = null; - // (l)abel - this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues; - this.error = null; - this.logLevel = logLevel; - this._children = null; - this._filterCreator = filterCreator; - } - - /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues, callback, logLevel, filterCreator) { - return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); - } - - /** start a new detached root log item and log a reference to it from this item */ - wrapDetached(labelOrValues, callback, logLevel, filterCreator) { - this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); - } - - /** logs a reference to a different log item, usually obtained from runDetached. - This is useful if the referenced operation can't be awaited. */ - refDetached(logItem, logLevel = null) { - logItem.ensureRefId(); - return this.log({ref: logItem._values.refId}, logLevel); - } - - ensureRefId() { - if (!this._values.refId) { - this.set("refId", this._logger._createRefId()); - } - } - - /** - * Creates a new child item and runs it in `callback`. - */ - wrap(labelOrValues, callback, logLevel = null, filterCreator = null) { - const item = this.child(labelOrValues, logLevel, filterCreator); - return item.run(callback); - } - - get duration() { - if (this._end) { - return this._end - this._start; - } else { - return null; - } - } - - durationWithoutType(type) { - return this.duration - this.durationOfType(type); - } - - durationOfType(type) { - if (this._values.t === type) { - return this.duration; - } else if (this._children) { - return this._children.reduce((sum, c) => { - return sum + c.durationOfType(type); - }, 0); - } else { - return 0; - } - } - - /** - * Creates a new child item that finishes immediately - * and can hence not be modified anymore. - * - * Hence, the child item is not returned. - */ - log(labelOrValues, logLevel = null) { - const item = this.child(labelOrValues, logLevel, null); - item._end = item._start; - } - - set(key, value) { - if(typeof key === "object") { - const values = key; - Object.assign(this._values, values); - } else { - this._values[key] = value; - } - } - - serialize(filter, parentStartTime = null, forced) { - if (this._filterCreator) { - try { - filter = this._filterCreator(new LogFilter(filter), this); - } catch (err) { - console.error("Error creating log filter", err); - } - } - let children; - if (this._children !== null) { - children = this._children.reduce((array, c) => { - const s = c.serialize(filter, this._start, false); - if (s) { - if (array === null) { - array = []; - } - array.push(s); - } - return array; - }, null); - } - if (filter && !filter.filter(this, children)) { - return null; - } - // in (v)alues, (l)abel and (t)ype are also reserved. - const item = { - // (s)tart - s: parentStartTime === null ? this._start : this._start - parentStartTime, - // (d)uration - d: this.duration, - // (v)alues - v: this._values, - // (l)evel - l: this.logLevel - }; - if (this.error) { - // (e)rror - item.e = { - stack: this.error.stack, - name: this.error.name, - message: this.error.message.split("\n")[0] - }; - } - if (forced) { - item.f = true; //(f)orced - } - if (children) { - // (c)hildren - item.c = children; - } - return item; - } - - /** - * You probably want to use `wrap` instead of this. - * - * Runs a callback passing this log item, - * recording the timing and any error. - * - * callback can return a Promise. - * - * Should only be called once. - * - * @param {Function} callback [description] - * @return {[type]} [description] - */ - run(callback) { - if (this._end !== null) { - console.trace("log item is finished, additional logs will likely not be recorded"); - } - let result; - try { - result = callback(this); - if (result instanceof Promise) { - return result.then(promiseResult => { - this.finish(); - return promiseResult; - }, err => { - throw this.catch(err); - }); - } else { - this.finish(); - return result; - } - } catch (err) { - throw this.catch(err); - } - } - - /** - * finished the item, recording the end time. After finishing, an item can't be modified anymore as it will be persisted. - * @internal shouldn't typically be called by hand. allows to force finish if a promise is still running when closing the app - */ - finish() { - if (this._end === null) { - if (this._children !== null) { - for(const c of this._children) { - c.finish(); - } - } - this._end = this._logger._now(); - } - } - - // expose log level without needing import everywhere - get level() { - return LogLevel; - } - - catch(err) { - this.error = err; - this.logLevel = LogLevel.Error; - this.finish(); - return err; - } - - child(labelOrValues, logLevel, filterCreator) { - if (this._end !== null) { - console.trace("log item is finished, additional logs will likely not be recorded"); - } - if (!logLevel) { - logLevel = this.logLevel || LogLevel.Info; - } - const item = new LogItem(labelOrValues, logLevel, filterCreator, this._logger); - if (this._children === null) { - this._children = []; - } - this._children.push(item); - return item; - } - - get logger() { - return this._logger; - } -} From db792ab5a91188f7e4d62f08689ef31cb3829f58 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 12:06:50 +0530 Subject: [PATCH 13/78] Add type annotations to LogItem --- src/logging/LogItem.ts | 270 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/logging/LogItem.ts diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts new file mode 100644 index 00000000..bd6958e1 --- /dev/null +++ b/src/logging/LogItem.ts @@ -0,0 +1,270 @@ +/* +Copyright 2020 Bruno Windels +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 {BaseLogger} from "./BaseLogger"; +import {LogLevel, LogFilter} from "./LogFilter.js"; + +type LogItemValues = {l: string; [key: string]: unknown}; +export type LabelOrValues = string | LogItemValues; +export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; +export type LogCallback = (item: LogItem) => Promise | undefined; + +export class LogItem { + public start: number; + public logLevel: LogLevel; + public error: Error | null; + public end: number | null; + private _values: LogItemValues; + private _logger: BaseLogger; + private _filterCreator: FilterCreator; + private _children: Array | null; + + constructor(labelOrValues: LabelOrValues, logLevel: LogLevel, filterCreator: FilterCreator, logger: BaseLogger) { + this._logger = logger; + this.start = logger._now(); + this.end = null; + // (l)abel + this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues; + this.error = null; + this.logLevel = logLevel; + this._children = null; + this._filterCreator = filterCreator; + } + + /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator) { + return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); + } + + /** start a new detached root log item and log a reference to it from this item */ + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator) { + this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); + } + + /** logs a reference to a different log item, usually obtained from runDetached. + This is useful if the referenced operation can't be awaited. */ + refDetached(logItem: LogItem, logLevel: LogLevel | null = null) { + logItem.ensureRefId(); + return this.log({ref: logItem._values.refId}, logLevel); + } + + ensureRefId() { + if (!this._values.refId) { + this.set("refId", this._logger._createRefId()); + } + } + + /** + * Creates a new child item and runs it in `callback`. + */ + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel | null = null, filterCreator: FilterCreator = null) { + const item = this.child(labelOrValues, logLevel, filterCreator); + return item.run(callback); + } + + get duration() { + if (this.end) { + return this.end - this.start; + } else { + return null; + } + } + + durationWithoutType(type) { + return this.duration - this.durationOfType(type); + } + + durationOfType(type) { + if (this._values.t === type) { + return this.duration; + } else if (this._children) { + return this._children.reduce((sum, c) => { + return sum + c.durationOfType(type); + }, 0); + } else { + return 0; + } + } + + /** + * Creates a new child item that finishes immediately + * and can hence not be modified anymore. + * + * Hence, the child item is not returned. + */ + log(labelOrValues: LabelOrValues, logLevel: LogLevel | null = null) { + const item = this.child(labelOrValues, logLevel, null); + item.end = item.start; + } + + set(key, value) { + if(typeof key === "object") { + const values = key; + Object.assign(this._values, values); + } else { + this._values[key] = value; + } + } + + serialize(filter: LogFilter, parentStartTime: number | null = null, forced: boolean) { + if (this._filterCreator) { + try { + filter = this._filterCreator(new LogFilter(filter), this); + } catch (err) { + console.error("Error creating log filter", err); + } + } + interface Item { + s: number; + d: number | null; + v: LogItemValues; + l: LogLevel; + e?: { + stack: string | undefined; + name: string; + message: string; + }; + f?: boolean; + c?: Array; + }; + let children: Array | null = null; + if (this._children !== null) { + children = this._children.reduce((array: Array, c) => { + const s = c.serialize(filter, this.start, false); + if (s) { + if (array === null) { + array = []; + } + array.push(s); + } + return array; + }, null); + } + if (filter && !filter.filter(this, children)) { + return null; + } + // in (v)alues, (l)abel and (t)ype are also reserved. + const item: Item = { + // (s)tart + s: parentStartTime === null ? this.start : this.start - parentStartTime, + // (d)uration + d: this.duration, + // (v)alues + v: this._values, + // (l)evel + l: this.logLevel + }; + if (this.error) { + // (e)rror + item.e = { + stack: this.error.stack, + name: this.error.name, + message: this.error.message.split("\n")[0] + }; + } + if (forced) { + item.f = true; //(f)orced + } + if (children) { + // (c)hildren + item.c = children; + } + return item; + } + + /** + * You probably want to use `wrap` instead of this. + * + * Runs a callback passing this log item, + * recording the timing and any error. + * + * callback can return a Promise. + * + * Should only be called once. + * + * @param {Function} callback [description] + * @return {[type]} [description] + */ + run(callback: LogCallback) { + if (this.end !== null) { + console.trace("log item is finished, additional logs will likely not be recorded"); + } + let result; + try { + result = callback(this); + if (result instanceof Promise) { + return result.then(promiseResult => { + this.finish(); + return promiseResult; + }, err => { + throw this.catch(err); + }); + } else { + this.finish(); + return result; + } + } catch (err) { + throw this.catch(err); + } + } + + /** + * finished the item, recording the end time. After finishing, an item can't be modified anymore as it will be persisted. + * @internal shouldn't typically be called by hand. allows to force finish if a promise is still running when closing the app + */ + finish() { + if (this.end === null) { + if (this._children !== null) { + for(const c of this._children) { + c.finish(); + } + } + this.end = this._logger._now(); + } + } + + // expose log level without needing import everywhere + get level() { + return LogLevel; + } + + catch(err: Error) { + this.error = err; + this.logLevel = LogLevel.Error; + this.finish(); + return err; + } + + child(labelOrValues: LabelOrValues, logLevel: LogLevel | null, filterCreator: FilterCreator) { + if (this.end !== null) { + console.trace("log item is finished, additional logs will likely not be recorded"); + } + if (!logLevel) { + logLevel = this.logLevel || LogLevel.Info; + } + const item = new LogItem(labelOrValues, logLevel, filterCreator, this._logger); + if (this._children === null) { + this._children = []; + } + this._children.push(item); + return item; + } + + get logger() { + return this._logger; + } +} From 772f7a2757c33ed0dd45a4c7b6a8c60f49c7fe94 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 12:17:43 +0530 Subject: [PATCH 14/78] Account for duration being null --- src/logging/LogItem.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index bd6958e1..0a896841 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -85,7 +85,10 @@ export class LogItem { } durationWithoutType(type) { - return this.duration - this.durationOfType(type); + if (this.duration) { + return this.duration - this.durationOfType(type); + } + return null; } durationOfType(type) { From ceb52eedafffe30b9593ca6e9e14a870cacbc55b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 12:36:56 +0530 Subject: [PATCH 15/78] Fix imports and add type annotations --- src/logging/BaseLogger.ts | 2 +- src/logging/ConsoleLogger.js | 2 +- src/logging/IDBLogger.js | 2 +- src/logging/LogItem.ts | 6 +++--- src/logging/NullLogger.js | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index c47329c2..60388f77 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -16,7 +16,7 @@ limitations under the License. */ import {LogItem, LabelOrValues, FilterCreator, LogCallback} from "./LogItem"; -import {LogLevel, LogFilter} from "./LogFilter.js"; +import {LogLevel, LogFilter} from "./LogFilter"; import {Platform} from "../platform/web/Platform.js"; diff --git a/src/logging/ConsoleLogger.js b/src/logging/ConsoleLogger.js index aacbf132..4d3be73b 100644 --- a/src/logging/ConsoleLogger.js +++ b/src/logging/ConsoleLogger.js @@ -13,7 +13,7 @@ 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 {BaseLogger} from "./BaseLogger.js"; +import {BaseLogger} from "./BaseLogger"; export class ConsoleLogger extends BaseLogger { _persistItem(item) { diff --git a/src/logging/IDBLogger.js b/src/logging/IDBLogger.js index 03c2bf88..2360b54c 100644 --- a/src/logging/IDBLogger.js +++ b/src/logging/IDBLogger.js @@ -22,7 +22,7 @@ import { iterateCursor, fetchResults, } from "../matrix/storage/idb/utils"; -import {BaseLogger} from "./BaseLogger.js"; +import {BaseLogger} from "./BaseLogger"; export class IDBLogger extends BaseLogger { constructor(options) { diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 0a896841..a77b7c3d 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -16,7 +16,7 @@ limitations under the License. */ import {BaseLogger} from "./BaseLogger"; -import {LogLevel, LogFilter} from "./LogFilter.js"; +import {LogLevel, LogFilter} from "./LogFilter"; type LogItemValues = {l: string; [key: string]: unknown}; export type LabelOrValues = string | LogItemValues; @@ -84,14 +84,14 @@ export class LogItem { } } - durationWithoutType(type) { + durationWithoutType(type: string) { if (this.duration) { return this.duration - this.durationOfType(type); } return null; } - durationOfType(type) { + durationOfType(type: string) { if (this._values.t === type) { return this.duration; } else if (this._children) { diff --git a/src/logging/NullLogger.js b/src/logging/NullLogger.js index 060212bd..12eec5c9 100644 --- a/src/logging/NullLogger.js +++ b/src/logging/NullLogger.js @@ -13,7 +13,7 @@ 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} from "./LogFilter.js"; +import {LogLevel} from "./LogFilter"; function noop () {} From 142d3ef543321e248fc085bd80a7c64c6092b033 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 13:45:37 +0530 Subject: [PATCH 16/78] Split LogItemValues into union of types --- src/logging/LogItem.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index a77b7c3d..a7f05768 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -18,7 +18,25 @@ limitations under the License. import {BaseLogger} from "./BaseLogger"; import {LogLevel, LogFilter} from "./LogFilter"; -type LogItemValues = {l: string; [key: string]: unknown}; +type LogItemWithLabel = { + l: string; + [key: string]: unknown; +}; + +type LogItemNetwork = { + t: "network"; + method: string; + url: string; + [key: string]: unknown; +} + +type LogItemRef = { + ref: number; + [key: string]: unknown; +} + +type LogItemValues = LogItemWithLabel | LogItemNetwork | LogItemRef; + export type LabelOrValues = string | LogItemValues; export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; export type LogCallback = (item: LogItem) => Promise | undefined; @@ -59,7 +77,7 @@ export class LogItem { This is useful if the referenced operation can't be awaited. */ refDetached(logItem: LogItem, logLevel: LogLevel | null = null) { logItem.ensureRefId(); - return this.log({ref: logItem._values.refId}, logLevel); + return this.log({ref: logItem._values.refId as number}, logLevel); } ensureRefId() { @@ -114,7 +132,7 @@ export class LogItem { item.end = item.start; } - set(key, value) { + set(key: string | object, value: unknown) { if(typeof key === "object") { const values = key; Object.assign(this._values, values); From 0b4eca47249e9a7dfa9272c40fcfd6c1faf2a0fe Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 14:29:23 +0530 Subject: [PATCH 17/78] Create alias for LogLevel | null --- src/logging/BaseLogger.ts | 12 ++++++------ src/logging/LogFilter.ts | 2 ++ src/logging/LogItem.ts | 14 +++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 60388f77..bd17afde 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -16,7 +16,7 @@ limitations under the License. */ import {LogItem, LabelOrValues, FilterCreator, LogCallback} from "./LogItem"; -import {LogLevel, LogFilter} from "./LogFilter"; +import {LogLevel, LogFilter, LogLevelOrNull} from "./LogFilter"; import {Platform} from "../platform/web/Platform.js"; @@ -28,14 +28,14 @@ export abstract class BaseLogger { this._platform = platform; } - log(labelOrValues: LabelOrValues, logLevel: number = LogLevel.Info) { + log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info) { const item = new LogItem(labelOrValues, logLevel, null, this); item.end = item.start; this._persistItem(item, null, false); } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { + wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -48,7 +48,7 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } @@ -60,7 +60,7 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel = null, filterCreator: FilterCreator = null) { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { if (logLevel === null) { logLevel = LogLevel.Info; } @@ -131,7 +131,7 @@ export abstract class BaseLogger { this._openItems.clear(); } - abstract _persistItem(item: LogItem, filter?: LogFilter, forced?: boolean): void; + abstract _persistItem(item: LogItem, filter?: LogFilter | null, forced?: boolean): void; abstract export(): void; diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 83f71891..3099d826 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -26,6 +26,8 @@ export enum LogLevel { Off } +export type LogLevelOrNull = LogLevel | null; + export class LogFilter { constructor(parentFilter) { this._parentFilter = parentFilter; diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index a7f05768..094dc7a2 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -16,7 +16,7 @@ limitations under the License. */ import {BaseLogger} from "./BaseLogger"; -import {LogLevel, LogFilter} from "./LogFilter"; +import {LogLevel, LogLevelOrNull, LogFilter} from "./LogFilter"; type LogItemWithLabel = { l: string; @@ -64,18 +64,18 @@ export class LogItem { } /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator) { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); } /** start a new detached root log item and log a reference to it from this item */ - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator) { + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); } /** logs a reference to a different log item, usually obtained from runDetached. This is useful if the referenced operation can't be awaited. */ - refDetached(logItem: LogItem, logLevel: LogLevel | null = null) { + refDetached(logItem: LogItem, logLevel: LogLevelOrNull = null) { logItem.ensureRefId(); return this.log({ref: logItem._values.refId as number}, logLevel); } @@ -89,7 +89,7 @@ export class LogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevel | null = null, filterCreator: FilterCreator = null) { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -127,7 +127,7 @@ export class LogItem { * * Hence, the child item is not returned. */ - log(labelOrValues: LabelOrValues, logLevel: LogLevel | null = null) { + log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull = null) { const item = this.child(labelOrValues, logLevel, null); item.end = item.start; } @@ -270,7 +270,7 @@ export class LogItem { return err; } - child(labelOrValues: LabelOrValues, logLevel: LogLevel | null, filterCreator: FilterCreator) { + child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } From e3c85c585e2117c9f45cb5f4c91d56342d8fd0e1 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 14:42:43 +0530 Subject: [PATCH 18/78] Log callbacks can return more than Promises --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 094dc7a2..4fdf8ada 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -39,7 +39,7 @@ type LogItemValues = LogItemWithLabel | LogItemNetwork | LogItemRef; export type LabelOrValues = string | LogItemValues; export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; -export type LogCallback = (item: LogItem) => Promise | undefined; +export type LogCallback = (item: LogItem) => unknown; export class LogItem { public start: number; From ab126729e0ee3efc34e605ce267275e4519d4791 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 14:49:59 +0530 Subject: [PATCH 19/78] Use LogLevel as type instead of number --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index bd17afde..fb91e77b 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -68,7 +68,7 @@ export abstract class BaseLogger { return this._run(item, callback, logLevel!, filterCreator, true); } - _run(item: LogItem, callback: LogCallback, logLevel: number, filterCreator: FilterCreator, shouldThrow: boolean) { + _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean) { this._openItems.add(item); const finishItem = () => { From ef2aad89565a8940c3fe32cbae44338a2baceb78 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 15:04:07 +0530 Subject: [PATCH 20/78] Annotate LogFilter --- src/logging/LogFilter.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 3099d826..f13a6179 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {LogItem} from "./LogItem"; export enum LogLevel { All = 1, @@ -29,12 +30,14 @@ export enum LogLevel { export type LogLevelOrNull = LogLevel | null; export class LogFilter { - constructor(parentFilter) { + private _min: LogLevelOrNull = null; + private _parentFilter?: LogFilter; + + constructor(parentFilter?: LogFilter) { this._parentFilter = parentFilter; - this._min = null; } - filter(item, children) { + filter(item: LogItem, children: Array | null) { if (this._parentFilter) { if (!this._parentFilter.filter(item, children)) { return false; @@ -49,7 +52,7 @@ export class LogFilter { } /* methods to build the filter */ - minLevel(logLevel) { + minLevel(logLevel: LogLevel) { this._min = logLevel; return this; } From cfa7708b57caafb131b8e4839243ad232fe54c7f Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 18:51:46 +0530 Subject: [PATCH 21/78] Use type imports --- src/logging/BaseLogger.ts | 9 ++++++--- src/logging/LogFilter.ts | 2 +- src/logging/LogItem.ts | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index fb91e77b..99a8f9b7 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -15,9 +15,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LogItem, LabelOrValues, FilterCreator, LogCallback} from "./LogItem"; -import {LogLevel, LogFilter, LogLevelOrNull} from "./LogFilter"; -import {Platform} from "../platform/web/Platform.js"; +import {LogItem} from "./LogItem"; +import {LogLevel, LogFilter} from "./LogFilter"; +import type {FilterCreator, LabelOrValues, LogCallback} from "./LogItem"; +import type {LogLevelOrNull} from "./LogFilter"; +// todo: should this import be here just for getting the type? should it instead be done when Platform.js --> Platform.ts? +import type {Platform} from "../platform/web/Platform.js"; export abstract class BaseLogger { diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index f13a6179..476bca0e 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LogItem} from "./LogItem"; +import type {LogItem} from "./LogItem"; export enum LogLevel { All = 1, diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 4fdf8ada..2e95813a 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -15,8 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {BaseLogger} from "./BaseLogger"; -import {LogLevel, LogLevelOrNull, LogFilter} from "./LogFilter"; +import {LogLevel, LogFilter} from "./LogFilter"; +import type {LogLevelOrNull} from "./LogFilter"; +import type {BaseLogger} from "./BaseLogger"; type LogItemWithLabel = { l: string; From 7a68c971aa36c81317a6ccacbb7cbf7a4dc6ade1 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 19:07:24 +0530 Subject: [PATCH 22/78] Make field readonly --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 2e95813a..f58a0185 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -43,7 +43,7 @@ export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | export type LogCallback = (item: LogItem) => unknown; export class LogItem { - public start: number; + public readonly start: number; public logLevel: LogLevel; public error: Error | null; public end: number | null; From cd7dccd804852ed38285e7786dc8bc9a5ab6a332 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 10 Nov 2021 19:13:35 +0530 Subject: [PATCH 23/78] Move interface to top --- src/logging/LogItem.ts | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index f58a0185..b0412b02 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -38,6 +38,20 @@ type LogItemRef = { type LogItemValues = LogItemWithLabel | LogItemNetwork | LogItemRef; +interface ISerializedItem { + s: number; + d: number | null; + v: LogItemValues; + l: LogLevel; + e?: { + stack?: string; + name: string; + message: string; + }; + f?: boolean; + c?: Array; +}; + export type LabelOrValues = string | LogItemValues; export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; export type LogCallback = (item: LogItem) => unknown; @@ -150,22 +164,9 @@ export class LogItem { console.error("Error creating log filter", err); } } - interface Item { - s: number; - d: number | null; - v: LogItemValues; - l: LogLevel; - e?: { - stack: string | undefined; - name: string; - message: string; - }; - f?: boolean; - c?: Array; - }; - let children: Array | null = null; + let children: Array | null = null; if (this._children !== null) { - children = this._children.reduce((array: Array, c) => { + children = this._children.reduce((array: Array, c) => { const s = c.serialize(filter, this.start, false); if (s) { if (array === null) { @@ -180,7 +181,7 @@ export class LogItem { return null; } // in (v)alues, (l)abel and (t)ype are also reserved. - const item: Item = { + const item: ISerializedItem = { // (s)tart s: parentStartTime === null ? this.start : this.start - parentStartTime, // (d)uration From 0f7a78ee25b84f3c16800633bdf6d1f9b0c5a674 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 13:05:12 +0530 Subject: [PATCH 24/78] Make return type explicit --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index b0412b02..c33e529f 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -156,7 +156,7 @@ export class LogItem { } } - serialize(filter: LogFilter, parentStartTime: number | null = null, forced: boolean) { + serialize(filter: LogFilter, parentStartTime: number | null = null, forced: boolean): ISerializedItem | null { if (this._filterCreator) { try { filter = this._filterCreator(new LogFilter(filter), this); From 425a3c85a990ca775112d4b2877d78d388d5900d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 13:24:52 +0530 Subject: [PATCH 25/78] Make error prop private and expose via getter --- src/logging/LogItem.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index c33e529f..a464c285 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -59,7 +59,7 @@ export type LogCallback = (item: LogItem) => unknown; export class LogItem { public readonly start: number; public logLevel: LogLevel; - public error: Error | null; + private _error: Error | null; public end: number | null; private _values: LogItemValues; private _logger: BaseLogger; @@ -72,7 +72,7 @@ export class LogItem { this.end = null; // (l)abel this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues; - this.error = null; + this._error = null; this.logLevel = logLevel; this._children = null; this._filterCreator = filterCreator; @@ -191,12 +191,12 @@ export class LogItem { // (l)evel l: this.logLevel }; - if (this.error) { + if (this._error) { // (e)rror item.e = { - stack: this.error.stack, - name: this.error.name, - message: this.error.message.split("\n")[0] + stack: this._error.stack, + name: this._error.name, + message: this._error.message.split("\n")[0] }; } if (forced) { @@ -266,7 +266,7 @@ export class LogItem { } catch(err: Error) { - this.error = err; + this._error = err; this.logLevel = LogLevel.Error; this.finish(); return err; @@ -290,4 +290,8 @@ export class LogItem { get logger() { return this._logger; } + + get error() { + return this._error; + } } From 09851600f7863ace096bb6adb476bb573aa7e745 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 15:35:51 +0530 Subject: [PATCH 26/78] Remove unwanted types --- src/logging/LogItem.ts | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index a464c285..4289aafc 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -19,25 +19,6 @@ import {LogLevel, LogFilter} from "./LogFilter"; import type {LogLevelOrNull} from "./LogFilter"; import type {BaseLogger} from "./BaseLogger"; -type LogItemWithLabel = { - l: string; - [key: string]: unknown; -}; - -type LogItemNetwork = { - t: "network"; - method: string; - url: string; - [key: string]: unknown; -} - -type LogItemRef = { - ref: number; - [key: string]: unknown; -} - -type LogItemValues = LogItemWithLabel | LogItemNetwork | LogItemRef; - interface ISerializedItem { s: number; d: number | null; @@ -52,6 +33,16 @@ interface ISerializedItem { c?: Array; }; +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: LogItem) => LogFilter) | null; export type LogCallback = (item: LogItem) => unknown; From eb7c5c44370d3fbc359d5832ea73e61dd36b991d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 16:08:25 +0530 Subject: [PATCH 27/78] Use undefined only instead of both undefined and null --- src/logging/BaseLogger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 99a8f9b7..259c47eb 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -34,7 +34,7 @@ export abstract class BaseLogger { log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info) { const item = new LogItem(labelOrValues, logLevel, null, this); item.end = item.start; - this._persistItem(item, null, false); + this._persistItem(item, undefined, false); } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ @@ -134,7 +134,7 @@ export abstract class BaseLogger { this._openItems.clear(); } - abstract _persistItem(item: LogItem, filter?: LogFilter | null, forced?: boolean): void; + abstract _persistItem(item: LogItem, filter?: LogFilter, forced?: boolean): void; abstract export(): void; From 9fed2ca41b28be42cc89f6a1260f9b94c4487182 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 16:25:14 +0530 Subject: [PATCH 28/78] Use undefined instead of null --- src/logging/LogFilter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 476bca0e..4da7d457 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -30,7 +30,7 @@ export enum LogLevel { export type LogLevelOrNull = LogLevel | null; export class LogFilter { - private _min: LogLevelOrNull = null; + private _min?: LogLevel; private _parentFilter?: LogFilter; constructor(parentFilter?: LogFilter) { @@ -44,7 +44,7 @@ export class LogFilter { } } // neither our children or us have a loglevel high enough, filter out. - if (this._min !== null && !Array.isArray(children) && item.logLevel < this._min) { + if (this._min && !Array.isArray(children) && item.logLevel < this._min) { return false; } else { return true; From 2ddd2d16ed72b449236f1d25fbf834e8aa5ac979 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 11 Nov 2021 16:50:46 +0530 Subject: [PATCH 29/78] IDBLogger.js --> IDBLogger.ts --- src/logging/{IDBLogger.js => IDBLogger.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/logging/{IDBLogger.js => IDBLogger.ts} (100%) diff --git a/src/logging/IDBLogger.js b/src/logging/IDBLogger.ts similarity index 100% rename from src/logging/IDBLogger.js rename to src/logging/IDBLogger.ts From f3d0f88f957a88bd2ecc48907e4ed558a2328c38 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 12 Nov 2021 15:06:11 +0530 Subject: [PATCH 30/78] Make error public --- src/logging/LogItem.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 4289aafc..64ed6603 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -50,7 +50,7 @@ export type LogCallback = (item: LogItem) => unknown; export class LogItem { public readonly start: number; public logLevel: LogLevel; - private _error: Error | null; + public error: Error | null; public end: number | null; private _values: LogItemValues; private _logger: BaseLogger; @@ -63,7 +63,7 @@ export class LogItem { this.end = null; // (l)abel this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues; - this._error = null; + this.error = null; this.logLevel = logLevel; this._children = null; this._filterCreator = filterCreator; @@ -182,12 +182,12 @@ export class LogItem { // (l)evel l: this.logLevel }; - if (this._error) { + if (this.error) { // (e)rror item.e = { - stack: this._error.stack, - name: this._error.name, - message: this._error.message.split("\n")[0] + stack: this.error.stack, + name: this.error.name, + message: this.error.message.split("\n")[0] }; } if (forced) { @@ -257,7 +257,7 @@ export class LogItem { } catch(err: Error) { - this._error = err; + this.error = err; this.logLevel = LogLevel.Error; this.finish(); return err; @@ -281,8 +281,4 @@ export class LogItem { get logger() { return this._logger; } - - get error() { - return this._error; - } } From 8c7a765e1114762a65be741407e16613e5012877 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 12 Nov 2021 15:06:21 +0530 Subject: [PATCH 31/78] Convert IDBLogger to ts --- src/logging/IDBLogger.ts | 25 +++++++++++++++++++++---- src/platform/web/Platform.js | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 2360b54c..93ba9549 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -23,8 +23,21 @@ import { fetchResults, } from "../matrix/storage/idb/utils"; 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"; + +type QueuedItem = { + json: string; + id?: number; +} export class IDBLogger extends BaseLogger { + private readonly _name: string; + private readonly _limit: number; + private readonly _flushInterval: Interval; + private _queuedItems: QueuedItem[]; + constructor(options) { super(options); const {name, flushInterval = 60 * 1000, limit = 3000} = options; @@ -121,7 +134,7 @@ export class IDBLogger extends BaseLogger { try { const txn = db.transaction(["logs"], "readonly"); const logs = txn.objectStore("logs"); - const storedItems = await fetchResults(logs.openCursor(), () => false); + const storedItems: QueuedItem[] = await fetchResults(logs.openCursor(), () => false); const allItems = storedItems.concat(this._queuedItems); return new IDBLogExport(allItems, this, this._platform); } finally { @@ -154,7 +167,11 @@ export class IDBLogger extends BaseLogger { } class IDBLogExport { - constructor(items, logger, platform) { + private readonly _items: QueuedItem[]; + private readonly _logger: IDBLogger; + private readonly _platform: Platform; + + constructor(items: QueuedItem[], logger: IDBLogger, platform: Platform) { this._items = items; this._logger = logger; this._platform = platform; @@ -171,7 +188,7 @@ class IDBLogExport { return this._logger._removeItems(this._items); } - asBlob() { + asBlob(): BlobHandle { const log = { formatVersion: 1, appVersion: this._platform.updateService?.version, @@ -179,7 +196,7 @@ class IDBLogExport { }; const json = JSON.stringify(log); const buffer = this._platform.encoding.utf8.encode(json); - const blob = this._platform.createBlob(buffer, "application/json"); + const blob: BlobHandle = this._platform.createBlob(buffer, "application/json"); return blob; } } diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 1530ed12..63cbac2e 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -21,7 +21,7 @@ import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionI import {SettingsStorage} from "./dom/SettingsStorage.js"; import {Encoding} from "./utils/Encoding.js"; import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js"; -import {IDBLogger} from "../../logging/IDBLogger.js"; +import {IDBLogger} from "../../logging/IDBLogger"; import {ConsoleLogger} from "../../logging/ConsoleLogger.js"; import {RootView} from "./ui/RootView.js"; import {Clock} from "./dom/Clock.js"; From 29a826051475f61ea945fb5500eda4a12b280c26 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 12 Nov 2021 23:12:15 +0530 Subject: [PATCH 32/78] Add explicit types for return in methods --- src/logging/LogItem.ts | 35 +++++++++++++----------- src/matrix/storage/idb/StorageFactory.ts | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 64ed6603..2909a84e 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -21,7 +21,7 @@ import type {BaseLogger} from "./BaseLogger"; interface ISerializedItem { s: number; - d: number | null; + d?: number; v: LogItemValues; l: LogLevel; e?: { @@ -70,7 +70,7 @@ export class LogItem { } /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): LogItem { return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); } @@ -83,7 +83,7 @@ export class LogItem { This is useful if the referenced operation can't be awaited. */ refDetached(logItem: LogItem, logLevel: LogLevelOrNull = null) { logItem.ensureRefId(); - return this.log({ref: logItem._values.refId as number}, logLevel); + this.log({ref: logItem._values.refId as number}, logLevel); } ensureRefId() { @@ -100,27 +100,30 @@ export class LogItem { return item.run(callback); } - get duration() { + get duration(): number | undefined{ if (this.end) { return this.end - this.start; } else { - return null; + return undefined; } } - durationWithoutType(type: string) { - if (this.duration) { - return this.duration - this.durationOfType(type); + durationWithoutType(type: string): number | undefined{ + const durationOfType = this.durationOfType(type); + if (this.duration && durationOfType) { + return this.duration - durationOfType; } - return null; } - durationOfType(type: string) { + durationOfType(type: string): number | undefined { if (this._values.t === type) { return this.duration; } else if (this._children) { return this._children.reduce((sum, c) => { - return sum + c.durationOfType(type); + const duration = c.durationOfType(type); + if (duration) { + return sum + duration; + } }, 0); } else { return 0; @@ -213,11 +216,11 @@ export class LogItem { * @param {Function} callback [description] * @return {[type]} [description] */ - run(callback: LogCallback) { + run(callback: LogCallback): unknown { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } - let result; + let result: unknown; try { result = callback(this); if (result instanceof Promise) { @@ -252,18 +255,18 @@ export class LogItem { } // expose log level without needing import everywhere - get level() { + get level(): typeof LogLevel { return LogLevel; } - catch(err: Error) { + catch(err: Error): Error { this.error = err; this.logLevel = LogLevel.Error; this.finish(); return err; } - child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { + child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): LogItem { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 71201842..4ae55612 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -101,5 +101,5 @@ async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: nu const migrationFunc = schema[i]; await log.wrap(`v${i + 1}`, log => migrationFunc(db, txn, localStorage, log)); } - }); + }) as Promise; } From 8e42e3f21f23a85c65893a47a9868ccaedc67277 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 12 Nov 2021 23:17:21 +0530 Subject: [PATCH 33/78] Add types to returns in LogFilter.ts --- src/logging/LogFilter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 4da7d457..480e92db 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -37,7 +37,7 @@ export class LogFilter { this._parentFilter = parentFilter; } - filter(item: LogItem, children: Array | null) { + filter(item: LogItem, children: Array | null): boolean { if (this._parentFilter) { if (!this._parentFilter.filter(item, children)) { return false; @@ -52,7 +52,7 @@ export class LogFilter { } /* methods to build the filter */ - minLevel(logLevel: LogLevel) { + minLevel(logLevel: LogLevel): LogFilter { this._min = logLevel; return this; } From 67e8fc0c43ea2ed1508a0a4b3d751a4f9248c143 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 12 Nov 2021 23:27:25 +0530 Subject: [PATCH 34/78] Add return types to methods in BaseLogger --- src/logging/BaseLogger.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 259c47eb..9865355a 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -38,7 +38,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { + wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -51,7 +51,8 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): LogItem { + // todo: Remove jsdoc type? if (logLevel === null) { logLevel = LogLevel.Info; } @@ -63,7 +64,7 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { if (logLevel === null) { logLevel = LogLevel.Info; } @@ -71,7 +72,7 @@ export abstract class BaseLogger { return this._run(item, callback, logLevel!, filterCreator, true); } - _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean) { + _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean): unknown { this._openItems.add(item); const finishItem = () => { @@ -139,7 +140,7 @@ export abstract class BaseLogger { abstract export(): void; // expose log level without needing - get level() { + get level(): typeof LogLevel { return LogLevel; } @@ -147,7 +148,7 @@ export abstract class BaseLogger { return this._platform.clock.now(); } - _createRefId() { + _createRefId(): number { return Math.round(this._platform.random() * Number.MAX_SAFE_INTEGER); } } From 5efa27c2a3c2297885b99bdeb14ac60c8bd5d5be Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 14 Nov 2021 15:48:59 +0530 Subject: [PATCH 35/78] Add more type annotations --- src/logging/IDBLogger.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 93ba9549..2ef5b551 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -26,6 +26,8 @@ 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 {LogItem} from "./LogItem"; +import type {LogFilter} from "./LogFilter"; type QueuedItem = { json: string; @@ -54,7 +56,7 @@ export class IDBLogger extends BaseLogger { this._flushInterval.dispose(); } - handleEvent(evt) { + handleEvent(evt: Event) { if (evt.type === "pagehide") { this._finishAllAndFlush(); } @@ -96,7 +98,7 @@ export class IDBLogger extends BaseLogger { this._persistQueuedItems(this._queuedItems); } - _loadQueuedItems() { + _loadQueuedItems(): QueuedItem[] { const key = `${this._name}_queuedItems`; try { const json = window.localStorage.getItem(key); @@ -110,18 +112,18 @@ export class IDBLogger extends BaseLogger { return []; } - _openDB() { + _openDB(): Promise { return openDatabase(this._name, db => db.createObjectStore("logs", {keyPath: "id", autoIncrement: true}), 1); } - _persistItem(logItem, filter, forced) { - const serializedItem = logItem.serialize(filter, forced); + _persistItem(logItem: LogItem, filter: LogFilter, forced: boolean) { + const serializedItem = logItem.serialize(filter, undefined, forced); this._queuedItems.push({ json: JSON.stringify(serializedItem) }); } - _persistQueuedItems(items) { + _persistQueuedItems(items: QueuedItem[]) { try { window.localStorage.setItem(`${this._name}_queuedItems`, JSON.stringify(items)); } catch (e) { @@ -129,7 +131,7 @@ export class IDBLogger extends BaseLogger { } } - async export() { + async export(): Promise { const db = await this._openDB(); try { const txn = db.transaction(["logs"], "readonly"); @@ -144,7 +146,7 @@ export class IDBLogger extends BaseLogger { } } - async _removeItems(items) { + async _removeItems(items: QueuedItem[]) { const db = await this._openDB(); try { const txn = db.transaction(["logs"], "readwrite"); @@ -177,7 +179,7 @@ class IDBLogExport { this._platform = platform; } - get count() { + get count(): number { return this._items.length; } @@ -195,7 +197,7 @@ class IDBLogExport { items: this._items.map(i => JSON.parse(i.json)) }; const json = JSON.stringify(log); - const buffer = this._platform.encoding.utf8.encode(json); + const buffer: Uint8Array = this._platform.encoding.utf8.encode(json); const blob: BlobHandle = this._platform.createBlob(buffer, "application/json"); return blob; } From 2d8b719ab0a5be648e5d29e6e228b4a538f9f64b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 14 Nov 2021 15:55:42 +0530 Subject: [PATCH 36/78] Add void return types as well --- src/logging/IDBLogger.ts | 16 ++++++++-------- src/logging/LogItem.ts | 17 +++++++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 2ef5b551..4f6301ce 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -51,18 +51,18 @@ export class IDBLogger extends BaseLogger { this._flushInterval = this._platform.clock.createInterval(() => this._tryFlush(), flushInterval); } - dispose() { + dispose(): void { window.removeEventListener("pagehide", this, false); this._flushInterval.dispose(); } - handleEvent(evt: Event) { + handleEvent(evt: Event): void { if (evt.type === "pagehide") { this._finishAllAndFlush(); } } - async _tryFlush() { + async _tryFlush(): Promise { const db = await this._openDB(); try { const txn = db.transaction(["logs"], "readwrite"); @@ -92,7 +92,7 @@ export class IDBLogger extends BaseLogger { } } - _finishAllAndFlush() { + _finishAllAndFlush(): void { this._finishOpenItems(); this.log({l: "pagehide, closing logs", t: "navigation"}); this._persistQueuedItems(this._queuedItems); @@ -116,14 +116,14 @@ export class IDBLogger extends BaseLogger { return openDatabase(this._name, db => db.createObjectStore("logs", {keyPath: "id", autoIncrement: true}), 1); } - _persistItem(logItem: LogItem, filter: LogFilter, forced: boolean) { + _persistItem(logItem: LogItem, filter: LogFilter, forced: boolean): void { const serializedItem = logItem.serialize(filter, undefined, forced); this._queuedItems.push({ json: JSON.stringify(serializedItem) }); } - _persistQueuedItems(items: QueuedItem[]) { + _persistQueuedItems(items: QueuedItem[]): void { try { window.localStorage.setItem(`${this._name}_queuedItems`, JSON.stringify(items)); } catch (e) { @@ -146,7 +146,7 @@ export class IDBLogger extends BaseLogger { } } - async _removeItems(items: QueuedItem[]) { + async _removeItems(items: QueuedItem[]): Promise { const db = await this._openDB(); try { const txn = db.transaction(["logs"], "readwrite"); @@ -186,7 +186,7 @@ class IDBLogExport { /** * @return {Promise} */ - removeFromStore() { + removeFromStore(): Promise { return this._logger._removeItems(this._items); } diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 2909a84e..716a3e73 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -75,18 +75,18 @@ export class LogItem { } /** start a new detached root log item and log a reference to it from this item */ - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator) { + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): void { this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); } /** logs a reference to a different log item, usually obtained from runDetached. This is useful if the referenced operation can't be awaited. */ - refDetached(logItem: LogItem, logLevel: LogLevelOrNull = null) { + refDetached(logItem: LogItem, logLevel: LogLevelOrNull = null): void { logItem.ensureRefId(); this.log({ref: logItem._values.refId as number}, logLevel); } - ensureRefId() { + ensureRefId(): void { if (!this._values.refId) { this.set("refId", this._logger._createRefId()); } @@ -95,7 +95,7 @@ export class LogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null) { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -136,12 +136,12 @@ export class LogItem { * * Hence, the child item is not returned. */ - log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull = null) { + log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull = null): void { const item = this.child(labelOrValues, logLevel, null); item.end = item.start; } - set(key: string | object, value: unknown) { + set(key: string | object, value: unknown): void { if(typeof key === "object") { const values = key; Object.assign(this._values, values); @@ -150,6 +150,7 @@ export class LogItem { } } + // todo: null or undefined here? serialize(filter: LogFilter, parentStartTime: number | null = null, forced: boolean): ISerializedItem | null { if (this._filterCreator) { try { @@ -243,7 +244,7 @@ export class LogItem { * finished the item, recording the end time. After finishing, an item can't be modified anymore as it will be persisted. * @internal shouldn't typically be called by hand. allows to force finish if a promise is still running when closing the app */ - finish() { + finish(): void { if (this.end === null) { if (this._children !== null) { for(const c of this._children) { @@ -281,7 +282,7 @@ export class LogItem { return item; } - get logger() { + get logger(): BaseLogger { return this._logger; } } From 39d0708cca6c8fcbb9e91e398b1eaf0030e1488f Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 14 Nov 2021 15:58:51 +0530 Subject: [PATCH 37/78] Add comment --- src/logging/IDBLogger.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 4f6301ce..3283dd0d 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -154,7 +154,8 @@ export class IDBLogger extends BaseLogger { for (const item of items) { const queuedIdx = this._queuedItems.findIndex(i => i.id === item.id); if (queuedIdx === -1) { - logs.delete(item.id); + // todo: isn't id optional? do we need further checks here + logs.delete(item.id!); // resolve questionable use of non-null assertion operator? } else { this._queuedItems.splice(queuedIdx, 1); } From bba44abf529f665ad47e94e56d90c47fe96fba97 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 14 Nov 2021 16:24:16 +0530 Subject: [PATCH 38/78] Convert console logger to ts --- .../{ConsoleLogger.js => ConsoleLogger.ts} | 44 ++++++++++--------- src/logging/LogItem.ts | 10 ++++- 2 files changed, 32 insertions(+), 22 deletions(-) rename src/logging/{ConsoleLogger.js => ConsoleLogger.ts} (58%) diff --git a/src/logging/ConsoleLogger.js b/src/logging/ConsoleLogger.ts similarity index 58% rename from src/logging/ConsoleLogger.js rename to src/logging/ConsoleLogger.ts index 4d3be73b..5b709bb1 100644 --- a/src/logging/ConsoleLogger.js +++ b/src/logging/ConsoleLogger.ts @@ -14,35 +14,37 @@ See the License for the specific language governing permissions and limitations under the License. */ import {BaseLogger} from "./BaseLogger"; +import type {LogItem, LogItemValues} from "./LogItem"; export class ConsoleLogger extends BaseLogger { - _persistItem(item) { + _persistItem(item: LogItem): void { printToConsole(item); } - export() { + export(): void { throw new Error("Cannot export from ConsoleLogger"); } } const excludedKeysFromTable = ["l", "id"]; -function filterValues(values) { +function filterValues(values: LogItemValues): LogItemValues | null { if (!values) { + // todo: is this check here unnecessary because LogItem will always have values? return null; } return Object.entries(values) .filter(([key]) => !excludedKeysFromTable.includes(key)) - .reduce((obj, [key, value]) => { + .reduce((obj: LogItemValues, [key, value]) => { obj = obj || {}; obj[key] = value; return obj; }, null); } -function printToConsole(item) { +function printToConsole(item: LogItem): void { const label = `${itemCaption(item)} (${item.duration}ms)`; - const filteredValues = filterValues(item._values); - const shouldGroup = item._children || filteredValues; + const filteredValues = filterValues(item.values); + const shouldGroup = item.children || filteredValues; if (shouldGroup) { if (item.error) { console.group(label); @@ -62,8 +64,8 @@ function printToConsole(item) { if (filteredValues) { console.table(filteredValues); } - if (item._children) { - for(const c of item._children) { + if (item.children) { + for(const c of item.children) { printToConsole(c); } } @@ -72,18 +74,18 @@ function printToConsole(item) { } } -function itemCaption(item) { - if (item._values.t === "network") { - return `${item._values.method} ${item._values.url}`; - } else if (item._values.l && typeof item._values.id !== "undefined") { - return `${item._values.l} ${item._values.id}`; - } else if (item._values.l && typeof item._values.status !== "undefined") { - return `${item._values.l} (${item._values.status})`; - } else if (item._values.l && item.error) { - return `${item._values.l} failed`; - } else if (typeof item._values.ref !== "undefined") { - return `ref ${item._values.ref}`; +function itemCaption(item: LogItem): string { + if (item.values.t === "network") { + return `${item.values.method} ${item.values.url}`; + } else if (item.values.l && typeof item.values.id !== "undefined") { + return `${item.values.l} ${item.values.id}`; + } else if (item.values.l && typeof item.values.status !== "undefined") { + return `${item.values.l} (${item.values.status})`; + } else if (item.values.l && item.error) { + return `${item.values.l} failed`; + } else if (typeof item.values.ref !== "undefined") { + return `ref ${item.values.ref}`; } else { - return item._values.l || item._values.type; + return item.values.l || item.values.type; } } diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 716a3e73..051b0353 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -33,7 +33,7 @@ interface ISerializedItem { c?: Array; }; -type LogItemValues = { +export type LogItemValues = { l?: string; t?: string; id?: unknown; @@ -285,4 +285,12 @@ export class LogItem { get logger(): BaseLogger { return this._logger; } + + get values(): LogItemValues { + return this._values; + } + + get children(): Array | null { + return this._children; + } } From a7d059b3ed304269296500e6997507b0a3b9ed3e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 14 Nov 2021 19:42:18 +0530 Subject: [PATCH 39/78] Fix imports --- src/matrix/storage/idb/QueryTarget.ts | 2 +- src/matrix/storage/idb/Storage.ts | 2 +- src/matrix/storage/idb/StorageFactory.ts | 4 ++-- src/matrix/storage/idb/Store.ts | 2 +- src/matrix/storage/idb/Transaction.ts | 4 ++-- src/matrix/storage/idb/schema.ts | 2 +- src/matrix/storage/idb/stores/SessionStore.ts | 2 +- src/matrix/storage/idb/stores/TimelineEventStore.ts | 2 +- src/platform/web/Platform.js | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/matrix/storage/idb/QueryTarget.ts b/src/matrix/storage/idb/QueryTarget.ts index 01f46e1a..03fe66bc 100644 --- a/src/matrix/storage/idb/QueryTarget.ts +++ b/src/matrix/storage/idb/QueryTarget.ts @@ -16,7 +16,7 @@ limitations under the License. import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils"; import {StorageError} from "../common"; -import {LogItem} from "../../../logging/LogItem.js"; +import {LogItem} from "../../../logging/LogItem"; import {IDBKey} from "./Transaction"; // this is the part of the Transaction class API that is used here and in the Store subclass, diff --git a/src/matrix/storage/idb/Storage.ts b/src/matrix/storage/idb/Storage.ts index 53ee7bc0..728d4fca 100644 --- a/src/matrix/storage/idb/Storage.ts +++ b/src/matrix/storage/idb/Storage.ts @@ -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.js"; +import { BaseLogger } from "../../../logging/BaseLogger"; const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey"; diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 4ae55612..f8cc192d 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -20,8 +20,8 @@ import { openDatabase, reqAsPromise } from "./utils"; import { exportSession, importSession, Export } from "./export"; import { schema } from "./schema"; import { detectWebkitEarlyCloseTxnBug } from "./quirks"; -import { BaseLogger } from "../../../logging/BaseLogger.js"; -import { LogItem } from "../../../logging/LogItem.js"; +import { BaseLogger } from "../../../logging/BaseLogger"; +import { LogItem } from "../../../logging/LogItem"; const sessionName = (sessionId: string) => `hydrogen_session_${sessionId}`; const openDatabaseWithSessionId = function(sessionId: string, idbFactory: IDBFactory, localStorage: IDOMStorage, log: LogItem) { diff --git a/src/matrix/storage/idb/Store.ts b/src/matrix/storage/idb/Store.ts index a4c80426..74de2afa 100644 --- a/src/matrix/storage/idb/Store.ts +++ b/src/matrix/storage/idb/Store.ts @@ -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 {LogItem} from "../../../logging/LogItem.js"; +import {LogItem} from "../../../logging/LogItem"; const LOG_REQUESTS = false; diff --git a/src/matrix/storage/idb/Transaction.ts b/src/matrix/storage/idb/Transaction.ts index 3bc4aed2..0d9e55a5 100644 --- a/src/matrix/storage/idb/Transaction.ts +++ b/src/matrix/storage/idb/Transaction.ts @@ -36,8 +36,8 @@ import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore"; import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore"; import {OperationStore} from "./stores/OperationStore"; import {AccountDataStore} from "./stores/AccountDataStore"; -import {LogItem} from "../../../logging/LogItem.js"; -import {BaseLogger} from "../../../logging/BaseLogger.js"; +import {LogItem} from "../../../logging/LogItem"; +import {BaseLogger} from "../../../logging/BaseLogger"; export type IDBKey = IDBValidKey | IDBKeyRange; diff --git a/src/matrix/storage/idb/schema.ts b/src/matrix/storage/idb/schema.ts index cd22d803..a9c4e2e4 100644 --- a/src/matrix/storage/idb/schema.ts +++ b/src/matrix/storage/idb/schema.ts @@ -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 {LogItem} from "../../../logging/LogItem.js"; +import {LogItem} from "../../../logging/LogItem"; export type MigrationFunc = (db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: LogItem) => Promise | void; diff --git a/src/matrix/storage/idb/stores/SessionStore.ts b/src/matrix/storage/idb/stores/SessionStore.ts index 785835b8..6bf87e9b 100644 --- a/src/matrix/storage/idb/stores/SessionStore.ts +++ b/src/matrix/storage/idb/stores/SessionStore.ts @@ -16,7 +16,7 @@ limitations under the License. import {Store} from "../Store"; import {IDOMStorage} from "../types"; import {SESSION_E2EE_KEY_PREFIX} from "../../../e2ee/common.js"; -import {LogItem} from "../../../../logging/LogItem.js"; +import {LogItem} from "../../../../logging/LogItem"; import {parse, stringify} from "../../../../utils/typedJSON"; export interface SessionEntry { diff --git a/src/matrix/storage/idb/stores/TimelineEventStore.ts b/src/matrix/storage/idb/stores/TimelineEventStore.ts index 2087a39f..3c101701 100644 --- a/src/matrix/storage/idb/stores/TimelineEventStore.ts +++ b/src/matrix/storage/idb/stores/TimelineEventStore.ts @@ -20,7 +20,7 @@ import { encodeUint32, decodeUint32 } from "../utils"; import {KeyLimits} from "../../common"; import {Store} from "../Store"; import {TimelineEvent, StateEvent} from "../../types"; -import {LogItem} from "../../../../logging/LogItem.js"; +import {LogItem} from "../../../../logging/LogItem"; interface Annotation { count: number; diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 63cbac2e..f6cd2895 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -22,7 +22,7 @@ import {SettingsStorage} from "./dom/SettingsStorage.js"; import {Encoding} from "./utils/Encoding.js"; import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js"; import {IDBLogger} from "../../logging/IDBLogger"; -import {ConsoleLogger} from "../../logging/ConsoleLogger.js"; +import {ConsoleLogger} from "../../logging/ConsoleLogger"; import {RootView} from "./ui/RootView.js"; import {Clock} from "./dom/Clock.js"; import {ServiceWorkerHandler} from "./dom/ServiceWorkerHandler.js"; From 520e0f1b892299f98d31a6f05157d4b5d82afdb6 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 17:29:08 +0530 Subject: [PATCH 40/78] Use interface ILogItem --- .../room/timeline/ReactionsViewModel.js | 2 +- src/logging/BaseLogger.ts | 12 +-- src/logging/ConsoleLogger.ts | 8 +- src/logging/IDBLogger.ts | 6 +- src/logging/LogFilter.ts | 4 +- src/logging/LogItem.ts | 38 ++++++-- src/logging/{NullLogger.js => NullLogger.ts} | 90 ++++++++++--------- src/logging/utils.js | 2 +- src/matrix/e2ee/megolm/Decryption.ts | 6 +- src/matrix/room/Invite.js | 2 +- src/matrix/room/sending/SendQueue.js | 2 +- src/matrix/room/timeline/Timeline.js | 2 +- .../room/timeline/persistence/GapWriter.js | 2 +- .../timeline/persistence/RelationWriter.js | 2 +- .../room/timeline/persistence/SyncWriter.js | 2 +- src/matrix/storage/idb/QueryTarget.ts | 6 +- src/matrix/storage/idb/StorageFactory.ts | 31 ++++--- src/matrix/storage/idb/Store.ts | 12 +-- src/matrix/storage/idb/Transaction.ts | 14 +-- src/matrix/storage/idb/schema.ts | 12 +-- src/matrix/storage/idb/stores/SessionStore.ts | 4 +- .../storage/idb/stores/TimelineEventStore.ts | 8 +- src/mocks/Storage.ts | 2 +- 23 files changed, 155 insertions(+), 114 deletions(-) rename src/logging/{NullLogger.js => NullLogger.ts} (57%) diff --git a/src/domain/session/room/timeline/ReactionsViewModel.js b/src/domain/session/room/timeline/ReactionsViewModel.js index 25d74b49..3a47aaa0 100644 --- a/src/domain/session/room/timeline/ReactionsViewModel.js +++ b/src/domain/session/room/timeline/ReactionsViewModel.js @@ -184,7 +184,7 @@ import {Clock as MockClock} from "../../../../mocks/Clock.js"; import {createMockStorage} from "../../../../mocks/Storage"; import {ListObserver} from "../../../../mocks/ListObserver.js"; import {createEvent, withTextBody, withContent} from "../../../../mocks/event.js"; -import {NullLogItem, NullLogger} from "../../../../logging/NullLogger.js"; +import {NullLogItem, NullLogger} from "../../../../logging/NullLogger"; import {HomeServer as MockHomeServer} from "../../../../mocks/HomeServer.js"; // other imports import {BaseMessageTile} from "./tiles/BaseMessageTile.js"; diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 9865355a..e420c0df 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -17,14 +17,14 @@ limitations under the License. import {LogItem} from "./LogItem"; import {LogLevel, LogFilter} from "./LogFilter"; -import type {FilterCreator, LabelOrValues, LogCallback} from "./LogItem"; +import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogItem"; import type {LogLevelOrNull} from "./LogFilter"; // todo: should this import be here just for getting the type? should it instead be done when Platform.js --> Platform.ts? import type {Platform} from "../platform/web/Platform.js"; export abstract class BaseLogger { - protected _openItems: Set = new Set(); + protected _openItems: Set = new Set(); protected _platform: Platform; constructor({platform}) { @@ -38,7 +38,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: LogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { + wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -51,7 +51,7 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): LogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): ILogItem { // todo: Remove jsdoc type? if (logLevel === null) { logLevel = LogLevel.Info; @@ -72,7 +72,7 @@ export abstract class BaseLogger { return this._run(item, callback, logLevel!, filterCreator, true); } - _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean): unknown { + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean): unknown { this._openItems.add(item); const finishItem = () => { @@ -135,7 +135,7 @@ export abstract class BaseLogger { this._openItems.clear(); } - abstract _persistItem(item: LogItem, filter?: LogFilter, forced?: boolean): void; + abstract _persistItem(item: ILogItem, filter?: LogFilter, forced?: boolean): void; abstract export(): void; diff --git a/src/logging/ConsoleLogger.ts b/src/logging/ConsoleLogger.ts index 5b709bb1..d8693e38 100644 --- a/src/logging/ConsoleLogger.ts +++ b/src/logging/ConsoleLogger.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ import {BaseLogger} from "./BaseLogger"; -import type {LogItem, LogItemValues} from "./LogItem"; +import type {ILogItem, LogItemValues} from "./LogItem"; export class ConsoleLogger extends BaseLogger { - _persistItem(item: LogItem): void { + _persistItem(item: ILogItem): void { printToConsole(item); } @@ -41,7 +41,7 @@ function filterValues(values: LogItemValues): LogItemValues | null { }, null); } -function printToConsole(item: LogItem): void { +function printToConsole(item: ILogItem): void { const label = `${itemCaption(item)} (${item.duration}ms)`; const filteredValues = filterValues(item.values); const shouldGroup = item.children || filteredValues; @@ -74,7 +74,7 @@ function printToConsole(item: LogItem): void { } } -function itemCaption(item: LogItem): string { +function itemCaption(item: ILogItem): string { if (item.values.t === "network") { return `${item.values.method} ${item.values.url}`; } else if (item.values.l && typeof item.values.id !== "undefined") { diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 3283dd0d..960db0da 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -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 {LogItem} from "./LogItem"; +import type {ILogItem} from "./LogItem"; import type {LogFilter} from "./LogFilter"; type QueuedItem = { @@ -116,8 +116,8 @@ export class IDBLogger extends BaseLogger { return openDatabase(this._name, db => db.createObjectStore("logs", {keyPath: "id", autoIncrement: true}), 1); } - _persistItem(logItem: LogItem, filter: LogFilter, forced: boolean): void { - const serializedItem = logItem.serialize(filter, undefined, forced); + _persistItem(logItem: ILogItem, filter: LogFilter, forced: boolean): void { + const serializedItem = logItem.serialize(filter, null, forced); this._queuedItems.push({ json: JSON.stringify(serializedItem) }); diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 480e92db..dc415ede 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type {LogItem} from "./LogItem"; +import type {ILogItem} from "./LogItem"; export enum LogLevel { All = 1, @@ -37,7 +37,7 @@ export class LogFilter { this._parentFilter = parentFilter; } - filter(item: LogItem, children: Array | null): boolean { + filter(item: ILogItem, children: Array | null): boolean { if (this._parentFilter) { if (!this._parentFilter.filter(item, children)) { return false; diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 051b0353..54957347 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -33,6 +33,30 @@ interface ISerializedItem { c?: Array; }; +export interface ILogItem { + logger: any; + level: typeof LogLevel; + duration?: number; + end?: number | null; + start?: number; + logLevel: LogLevel; + children: Array | null; + values: LogItemValues; + error: Error | null; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, level: LogLevelOrNull, filterCreator: FilterCreator): unknown; + log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull): void; + set(key: string | object, value: unknown): void; + run(callback: LogCallback): unknown; + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem; + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): void; + refDetached(logItem: ILogItem, logLevel: LogLevelOrNull): void; + ensureRefId(): void; + catch(err: Error): Error; + finish(): void; + child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem; + serialize(filter: LogFilter, parentStartTime: number | null, forced: boolean): ISerializedItem | null; +} + export type LogItemValues = { l?: string; t?: string; @@ -44,10 +68,10 @@ export type LogItemValues = { } export type LabelOrValues = string | LogItemValues; -export type FilterCreator = ((filter: LogFilter, item: LogItem) => LogFilter) | null; -export type LogCallback = (item: LogItem) => unknown; +export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter) | null; +export type LogCallback = (item: ILogItem) => unknown; -export class LogItem { +export class LogItem implements ILogItem { public readonly start: number; public logLevel: LogLevel; public error: Error | null; @@ -70,7 +94,7 @@ export class LogItem { } /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): LogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem { return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); } @@ -81,9 +105,9 @@ export class LogItem { /** logs a reference to a different log item, usually obtained from runDetached. This is useful if the referenced operation can't be awaited. */ - refDetached(logItem: LogItem, logLevel: LogLevelOrNull = null): void { + refDetached(logItem: ILogItem, logLevel: LogLevelOrNull = null): void { logItem.ensureRefId(); - this.log({ref: logItem._values.refId as number}, logLevel); + this.log({ref: (logItem as LogItem)._values.refId}, logLevel); } ensureRefId(): void { @@ -267,7 +291,7 @@ export class LogItem { return err; } - child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): LogItem { + child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } diff --git a/src/logging/NullLogger.js b/src/logging/NullLogger.ts similarity index 57% rename from src/logging/NullLogger.js rename to src/logging/NullLogger.ts index 12eec5c9..285ea1e4 100644 --- a/src/logging/NullLogger.js +++ b/src/logging/NullLogger.ts @@ -14,18 +14,17 @@ 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"; -function noop () {} +function noop (): void {} export class NullLogger { - constructor() { - this.item = new NullLogItem(this); - } + public readonly item: ILogItem = new NullLogItem(this); - log() {} + log(): void {} - run(_, callback) { + run(_: null, callback) { return callback(this.item); } @@ -50,50 +49,61 @@ export class NullLogger { } } -export class NullLogItem { - constructor(logger) { +export class NullLogItem implements ILogItem { + public readonly logger: NullLogger; + public readonly logLevel: LogLevel; + public children: Array | null = null; + public values: LogItemValues; + public error: Error | null = null; + + constructor(logger: NullLogger) { this.logger = logger; } - wrap(_, callback) { + wrap(_: LabelOrValues, callback: LogCallback): unknown { return callback(this); } - log() {} - set() {} + log(): void {} + set(): void {} - runDetached(_, callback) { + runDetached(_: LabelOrValues, callback: LogCallback): ILogItem { new Promise(r => r(callback(this))).then(noop, noop); - } - - wrapDetached(_, callback) { - return this.refDetached(null, callback); - } - - run(callback) { - return callback(this); - } - - refDetached() {} - - ensureRefId() {} - - get level() { - return LogLevel; - } - - get duration() { - return 0; - } - - catch(err) { - return err; - } - - child() { return this; } - finish() {} + wrapDetached(_: LabelOrValues, _callback: LogCallback): void { + return this.refDetached(); + } + + run(callback: LogCallback): unknown { + return callback(this); + } + + refDetached(): void {} + + ensureRefId(): void {} + + get level(): typeof LogLevel { + return LogLevel; + } + + get duration(): 0 { + return 0; + } + + catch(err: Error): Error { + return err; + } + + child() { + return this; + } + + finish(): void {} + + serialize() { + return null; + } } export const Instance = new NullLogger(); diff --git a/src/logging/utils.js b/src/logging/utils.js index 3da9aa5d..659df055 100644 --- a/src/logging/utils.js +++ b/src/logging/utils.js @@ -1,7 +1,7 @@ // these are helper functions if you can't assume you always have a log item (e.g. some code paths call with one set, others don't) // 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.js"; +import {Instance as NullLoggerInstance} from "./NullLogger"; export function wrapOrRunNullLogger(logItem, labelOrValues, callback, logLevel = null, filterCreator = null) { if (logItem) { diff --git a/src/matrix/e2ee/megolm/Decryption.ts b/src/matrix/e2ee/megolm/Decryption.ts index 842d423d..4cb66971 100644 --- a/src/matrix/e2ee/megolm/Decryption.ts +++ b/src/matrix/e2ee/megolm/Decryption.ts @@ -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 {LogItem} from "../../../logging/LogItem"; +import type {ILogItem} from "../../../logging/LogItem"; export class Decryption { private keyLoader: KeyLoader; @@ -136,7 +136,7 @@ export class Decryption { * Extracts room keys from decrypted device messages. * The key won't be persisted yet, you need to call RoomKey.write for that. */ - roomKeysFromDeviceMessages(decryptionResults: DecryptionResult[], log: LogItem): IncomingRoomKey[] { + roomKeysFromDeviceMessages(decryptionResults: DecryptionResult[], log: ILogItem): IncomingRoomKey[] { const keys: IncomingRoomKey[] = []; for (const dr of decryptionResults) { if (dr.event?.type !== "m.room_key" || dr.event.content?.algorithm !== MEGOLM_ALGORITHM) { @@ -152,7 +152,7 @@ export class Decryption { log.logLevel = log.level.Warn; log.set("invalid", true); } - }, log.level.Detail); + }, log.level.Detail, null); } return keys; } diff --git a/src/matrix/room/Invite.js b/src/matrix/room/Invite.js index 1bf802dd..da721c77 100644 --- a/src/matrix/room/Invite.js +++ b/src/matrix/room/Invite.js @@ -244,7 +244,7 @@ export class Invite extends EventEmitter { } } -import {NullLogItem} from "../../logging/NullLogger.js"; +import {NullLogItem} from "../../logging/NullLogger"; import {Clock as MockClock} from "../../mocks/Clock.js"; import {default as roomInviteFixture} from "../../fixtures/matrix/invites/room.js"; import {default as dmInviteFixture} from "../../fixtures/matrix/invites/dm.js"; diff --git a/src/matrix/room/sending/SendQueue.js b/src/matrix/room/sending/SendQueue.js index 28408e34..896100c7 100644 --- a/src/matrix/room/sending/SendQueue.js +++ b/src/matrix/room/sending/SendQueue.js @@ -353,7 +353,7 @@ export class SendQueue { import {HomeServer as MockHomeServer} from "../../../mocks/HomeServer.js"; import {createMockStorage} from "../../../mocks/Storage"; import {ListObserver} from "../../../mocks/ListObserver.js"; -import {NullLogger, NullLogItem} from "../../../logging/NullLogger.js"; +import {NullLogger, NullLogItem} from "../../../logging/NullLogger"; import {createEvent, withTextBody, withTxnId} from "../../../mocks/event.js"; import {poll} from "../../../mocks/poll.js"; import {createAnnotation} from "../timeline/relations.js"; diff --git a/src/matrix/room/timeline/Timeline.js b/src/matrix/room/timeline/Timeline.js index 4e6fe40c..bd89ee8d 100644 --- a/src/matrix/room/timeline/Timeline.js +++ b/src/matrix/room/timeline/Timeline.js @@ -346,7 +346,7 @@ import {Clock as MockClock} from "../../../mocks/Clock.js"; import {createMockStorage} from "../../../mocks/Storage"; import {ListObserver} from "../../../mocks/ListObserver.js"; import {createEvent, withTextBody, withContent, withSender} from "../../../mocks/event.js"; -import {NullLogItem} from "../../../logging/NullLogger.js"; +import {NullLogItem} from "../../../logging/NullLogger"; import {EventEntry} from "./entries/EventEntry.js"; import {User} from "../../User.js"; import {PendingEvent} from "../sending/PendingEvent.js"; diff --git a/src/matrix/room/timeline/persistence/GapWriter.js b/src/matrix/room/timeline/persistence/GapWriter.js index 7794b797..3e520608 100644 --- a/src/matrix/room/timeline/persistence/GapWriter.js +++ b/src/matrix/room/timeline/persistence/GapWriter.js @@ -205,7 +205,7 @@ import {FragmentIdComparer} from "../FragmentIdComparer.js"; import {RelationWriter} from "./RelationWriter.js"; import {createMockStorage} from "../../../../mocks/Storage"; import {FragmentBoundaryEntry} from "../entries/FragmentBoundaryEntry.js"; -import {NullLogItem} from "../../../../logging/NullLogger.js"; +import {NullLogItem} from "../../../../logging/NullLogger"; import {TimelineMock, eventIds, eventId} from "../../../../mocks/TimelineMock.ts"; import {SyncWriter} from "./SyncWriter.js"; import {MemberWriter} from "./MemberWriter.js"; diff --git a/src/matrix/room/timeline/persistence/RelationWriter.js b/src/matrix/room/timeline/persistence/RelationWriter.js index c0d3d369..60a2b618 100644 --- a/src/matrix/room/timeline/persistence/RelationWriter.js +++ b/src/matrix/room/timeline/persistence/RelationWriter.js @@ -257,7 +257,7 @@ import {createMockStorage} from "../../../../mocks/Storage"; import {createEvent, withTextBody, withRedacts, withContent} from "../../../../mocks/event.js"; import {createAnnotation} from "../relations.js"; import {FragmentIdComparer} from "../FragmentIdComparer.js"; -import {NullLogItem} from "../../../../logging/NullLogger.js"; +import {NullLogItem} from "../../../../logging/NullLogger"; export function tests() { const fragmentIdComparer = new FragmentIdComparer([]); diff --git a/src/matrix/room/timeline/persistence/SyncWriter.js b/src/matrix/room/timeline/persistence/SyncWriter.js index 749c3392..dc5ae3a8 100644 --- a/src/matrix/room/timeline/persistence/SyncWriter.js +++ b/src/matrix/room/timeline/persistence/SyncWriter.js @@ -258,7 +258,7 @@ export class SyncWriter { import {createMockStorage} from "../../../../mocks/Storage"; import {createEvent, withTextBody} from "../../../../mocks/event.js"; -import {Instance as nullLogger} from "../../../../logging/NullLogger.js"; +import {Instance as nullLogger} from "../../../../logging/NullLogger"; export function tests() { const roomId = "!abc:hs.tld"; return { diff --git a/src/matrix/storage/idb/QueryTarget.ts b/src/matrix/storage/idb/QueryTarget.ts index 03fe66bc..7519beac 100644 --- a/src/matrix/storage/idb/QueryTarget.ts +++ b/src/matrix/storage/idb/QueryTarget.ts @@ -16,7 +16,7 @@ limitations under the License. import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils"; import {StorageError} from "../common"; -import {LogItem} from "../../../logging/LogItem"; +import {ILogItem} from "../../../logging/LogItem"; import {IDBKey} from "./Transaction"; // this is the part of the Transaction class API that is used here and in the Store subclass, @@ -25,7 +25,7 @@ export interface ITransaction { idbFactory: IDBFactory; IDBKeyRange: typeof IDBKeyRange; databaseName: string; - addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined); + addWriteError(error: StorageError, refItem: ILogItem | undefined, operationName: string, keys: IDBKey[] | undefined); } type Reducer = (acc: B, val: A) => B @@ -277,7 +277,7 @@ export function tests() { class MockTransaction extends MockIDBImpl { get databaseName(): string { return "mockdb"; } - addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined) {} + addWriteError(error: StorageError, refItem: ILogItem | undefined, operationName: string, keys: IDBKey[] | undefined) {} } interface TestEntry { diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index f8cc192d..5ca6bce4 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -21,10 +21,10 @@ import { exportSession, importSession, Export } from "./export"; import { schema } from "./schema"; import { detectWebkitEarlyCloseTxnBug } from "./quirks"; import { BaseLogger } from "../../../logging/BaseLogger"; -import { LogItem } from "../../../logging/LogItem"; +import { ILogItem } from "../../../logging/LogItem"; const sessionName = (sessionId: string) => `hydrogen_session_${sessionId}`; -const openDatabaseWithSessionId = function(sessionId: string, idbFactory: IDBFactory, localStorage: IDOMStorage, log: LogItem) { +const openDatabaseWithSessionId = function(sessionId: string, idbFactory: IDBFactory, localStorage: IDOMStorage, log: ILogItem) { const create = (db, txn, oldVersion, version) => createStores(db, txn, oldVersion, version, localStorage, log); return openDatabase(sessionName(sessionId), create, schema.length, idbFactory); } @@ -63,7 +63,7 @@ export class StorageFactory { this._localStorage = localStorage; } - async create(sessionId: string, log: LogItem): Promise { + async create(sessionId: string, log: ILogItem): Promise { await this._serviceWorkerHandler?.preventConcurrentSessionAccess(sessionId); requestPersistedStorage().then(persisted => { // Firefox lies here though, and returns true even if the user denied the request @@ -83,23 +83,30 @@ export class StorageFactory { return reqAsPromise(req); } - async export(sessionId: string, log: LogItem): Promise { + async export(sessionId: string, log: ILogItem): Promise { const db = await openDatabaseWithSessionId(sessionId, this._idbFactory, this._localStorage, log); return await exportSession(db); } - async import(sessionId: string, data: Export, log: LogItem): Promise { + async import(sessionId: string, data: Export, log: ILogItem): Promise { const db = await openDatabaseWithSessionId(sessionId, this._idbFactory, this._localStorage, log); return await importSession(db, data); } } -async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: number | null, version: number, localStorage: IDOMStorage, log: LogItem): Promise { +async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: number | null, version: number, localStorage: IDOMStorage, log: ILogItem): Promise { const startIdx = oldVersion || 0; - return log.wrap({l: "storage migration", oldVersion, version}, async log => { - for(let i = startIdx; i < version; ++i) { - const migrationFunc = schema[i]; - await log.wrap(`v${i + 1}`, log => migrationFunc(db, txn, localStorage, log)); - } - }) as Promise; + return log.wrap( + { l: "storage migration", oldVersion, version }, + async (log) => { + for (let i = startIdx; i < version; ++i) { + const migrationFunc = schema[i]; + await log.wrap(`v${i + 1}`, (log) => + migrationFunc(db, txn, localStorage, log), null, null + ); + } + }, + null, + null + ) as Promise; } diff --git a/src/matrix/storage/idb/Store.ts b/src/matrix/storage/idb/Store.ts index 74de2afa..5a2a9abc 100644 --- a/src/matrix/storage/idb/Store.ts +++ b/src/matrix/storage/idb/Store.ts @@ -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 {LogItem} from "../../../logging/LogItem"; +import {ILogItem} from "../../../logging/LogItem"; const LOG_REQUESTS = false; @@ -145,7 +145,7 @@ export class Store extends QueryTarget { return new QueryTarget(new QueryTargetWrapper(this._idbStore.index(indexName)), this._transaction); } - put(value: T, log?: LogItem): void { + put(value: T, log?: ILogItem): void { // If this request fails, the error will bubble up to the transaction and abort it, // which is the behaviour we want. Therefore, it is ok to not create a promise for this // request and await it. @@ -160,13 +160,13 @@ export class Store extends QueryTarget { this._prepareErrorLog(request, log, "put", undefined, value); } - add(value: T, log?: LogItem): void { + add(value: T, log?: ILogItem): void { // ok to not monitor result of request, see comment in `put`. const request = this._idbStore.add(value); this._prepareErrorLog(request, log, "add", undefined, value); } - async tryAdd(value: T, log: LogItem): Promise { + async tryAdd(value: T, log: ILogItem): Promise { try { await reqAsPromise(this._idbStore.add(value)); return true; @@ -181,13 +181,13 @@ export class Store extends QueryTarget { } } - delete(keyOrKeyRange: IDBValidKey | IDBKeyRange, log?: LogItem): void { + delete(keyOrKeyRange: IDBValidKey | IDBKeyRange, log?: ILogItem): void { // ok to not monitor result of request, see comment in `put`. const request = this._idbStore.delete(keyOrKeyRange); this._prepareErrorLog(request, log, "delete", keyOrKeyRange, undefined); } - private _prepareErrorLog(request: IDBRequest, log: LogItem | undefined, operationName: string, key: IDBKey | undefined, value: T | undefined) { + private _prepareErrorLog(request: IDBRequest, log: ILogItem | undefined, operationName: string, key: IDBKey | undefined, value: T | undefined) { if (log) { log.ensureRefId(); } diff --git a/src/matrix/storage/idb/Transaction.ts b/src/matrix/storage/idb/Transaction.ts index 0d9e55a5..721ee711 100644 --- a/src/matrix/storage/idb/Transaction.ts +++ b/src/matrix/storage/idb/Transaction.ts @@ -36,7 +36,7 @@ import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore"; import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore"; import {OperationStore} from "./stores/OperationStore"; import {AccountDataStore} from "./stores/AccountDataStore"; -import {LogItem} from "../../../logging/LogItem"; +import {ILogItem} from "../../../logging/LogItem"; import {BaseLogger} from "../../../logging/BaseLogger"; export type IDBKey = IDBValidKey | IDBKeyRange; @@ -44,7 +44,7 @@ export type IDBKey = IDBValidKey | IDBKeyRange; class WriteErrorInfo { constructor( public readonly error: StorageError, - public readonly refItem: LogItem | undefined, + public readonly refItem: ILogItem | undefined, public readonly operationName: string, public readonly keys: IDBKey[] | undefined, ) {} @@ -169,7 +169,7 @@ export class Transaction { return this._store(StoreNames.accountData, idbStore => new AccountDataStore(idbStore)); } - async complete(log?: LogItem): Promise { + async complete(log?: ILogItem): Promise { try { await txnAsPromise(this._txn); } catch (err) { @@ -190,7 +190,7 @@ export class Transaction { return error; } - abort(log?: LogItem): void { + abort(log?: ILogItem): void { // TODO: should we wrap the exception in a StorageError? try { this._txn.abort(); @@ -202,14 +202,14 @@ export class Transaction { } } - addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined) { + addWriteError(error: StorageError, refItem: ILogItem | undefined, operationName: string, keys: IDBKey[] | undefined) { // don't log subsequent `AbortError`s if (error.errcode !== "AbortError" || this._writeErrors.length === 0) { this._writeErrors.push(new WriteErrorInfo(error, refItem, operationName, keys)); } } - private _logWriteErrors(parentItem: LogItem | undefined) { + private _logWriteErrors(parentItem: ILogItem | undefined) { const callback = errorGroupItem => { // we don't have context when there is no parentItem, so at least log stores if (!parentItem) { @@ -226,7 +226,7 @@ export class Transaction { }; const label = `${this._writeErrors.length} storage write operation(s) failed`; if (parentItem) { - parentItem.wrap(label, callback); + parentItem.wrap(label, callback, null, null); } else { this.logger.run(label, callback); } diff --git a/src/matrix/storage/idb/schema.ts b/src/matrix/storage/idb/schema.ts index a9c4e2e4..62a4cea1 100644 --- a/src/matrix/storage/idb/schema.ts +++ b/src/matrix/storage/idb/schema.ts @@ -11,10 +11,10 @@ import {SessionStore} from "./stores/SessionStore"; import {Store} from "./Store"; import {encodeScopeTypeKey} from "./stores/OperationStore"; import {MAX_UNICODE} from "./stores/common"; -import {LogItem} from "../../../logging/LogItem"; +import {ILogItem} from "../../../logging/LogItem"; -export type MigrationFunc = (db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: LogItem) => Promise | void; +export type MigrationFunc = (db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) => Promise | void; // FUNCTIONS SHOULD ONLY BE APPENDED!! // the index in the array is the database version export const schema: MigrationFunc[] = [ @@ -166,7 +166,7 @@ function createTimelineRelationsStore(db: IDBDatabase) : void { } //v11 doesn't change the schema, but ensures all userIdentities have all the roomIds they should (see #470) -async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: LogItem) { +async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) { const roomSummaryStore = txn.objectStore("roomSummary"); const trackedRoomIds: string[] = []; await iterateCursor(roomSummaryStore.openCursor(), roomSummary => { @@ -196,7 +196,7 @@ async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransact const updatedIdentity = addRoomToIdentity(identity, userId, roomId); if (updatedIdentity) { log.log({l: `fixing up`, id: userId, - roomsBefore: originalRoomCount, roomsAfter: updatedIdentity.roomIds.length}); + roomsBefore: originalRoomCount, roomsAfter: updatedIdentity.roomIds.length}, null); userIdentitiesStore.put(updatedIdentity); foundMissing = true; } @@ -207,7 +207,7 @@ async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransact // so we'll create a new one on the next message that will be properly shared outboundGroupSessionsStore.delete(roomId); } - }); + }, null, null); } } @@ -220,7 +220,7 @@ async function changeSSSSKeyPrefix(db: IDBDatabase, txn: IDBTransaction) { } } // v13 -async function backupAndRestoreE2EEAccountToLocalStorage(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: LogItem) { +async function backupAndRestoreE2EEAccountToLocalStorage(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) { const session = txn.objectStore("session"); // the Store object gets passed in several things through the Transaction class (a wrapper around IDBTransaction), // the only thing we should need here is the databaseName though, so we mock it out. diff --git a/src/matrix/storage/idb/stores/SessionStore.ts b/src/matrix/storage/idb/stores/SessionStore.ts index 6bf87e9b..dd133b45 100644 --- a/src/matrix/storage/idb/stores/SessionStore.ts +++ b/src/matrix/storage/idb/stores/SessionStore.ts @@ -16,7 +16,7 @@ limitations under the License. import {Store} from "../Store"; import {IDOMStorage} from "../types"; import {SESSION_E2EE_KEY_PREFIX} from "../../../e2ee/common.js"; -import {LogItem} from "../../../../logging/LogItem"; +import {ILogItem} from "../../../../logging/LogItem"; import {parse, stringify} from "../../../../utils/typedJSON"; export interface SessionEntry { @@ -64,7 +64,7 @@ export class SessionStore { }); } - async tryRestoreE2EEIdentityFromLocalStorage(log: LogItem): Promise { + async tryRestoreE2EEIdentityFromLocalStorage(log: ILogItem): Promise { let success = false; const lsPrefix = this._localStorageKeyPrefix; const prefix = lsPrefix + SESSION_E2EE_KEY_PREFIX; diff --git a/src/matrix/storage/idb/stores/TimelineEventStore.ts b/src/matrix/storage/idb/stores/TimelineEventStore.ts index 3c101701..b3663c29 100644 --- a/src/matrix/storage/idb/stores/TimelineEventStore.ts +++ b/src/matrix/storage/idb/stores/TimelineEventStore.ts @@ -20,7 +20,7 @@ import { encodeUint32, decodeUint32 } from "../utils"; import {KeyLimits} from "../../common"; import {Store} from "../Store"; import {TimelineEvent, StateEvent} from "../../types"; -import {LogItem} from "../../../../logging/LogItem"; +import {ILogItem} from "../../../../logging/LogItem"; interface Annotation { count: number; @@ -286,7 +286,7 @@ export class TimelineEventStore { * * Returns if the event was not yet known and the entry was written. */ - tryInsert(entry: TimelineEventEntry, log: LogItem): Promise { + tryInsert(entry: TimelineEventEntry, log: ILogItem): Promise { (entry as TimelineEventStorageEntry).key = encodeKey(entry.roomId, entry.fragmentId, entry.eventIndex); (entry as TimelineEventStorageEntry).eventIdKey = encodeEventIdKey(entry.roomId, entry.event.event_id); return this._timelineStore.tryAdd(entry as TimelineEventStorageEntry, log); @@ -320,7 +320,7 @@ export class TimelineEventStore { import {createMockStorage} from "../../../../mocks/Storage"; import {createEvent, withTextBody} from "../../../../mocks/event.js"; import {createEventEntry} from "../../../room/timeline/persistence/common.js"; -import {Instance as logItem} from "../../../../logging/NullLogger.js"; +import {Instance as nullLogger} from "../../../../logging/NullLogger"; export function tests() { @@ -368,7 +368,7 @@ export function tests() { let eventKey = EventKey.defaultFragmentKey(109); for (const insertedId of insertedIds) { const entry = createEventEntry(eventKey.nextKey(), roomId, createEventWithId(insertedId)); - assert(await txn.timelineEvents.tryInsert(entry, logItem)); + assert(await txn.timelineEvents.tryInsert(entry, nullLogger.item)); eventKey = eventKey.nextKey(); } const eventKeyMap = await txn.timelineEvents.getEventKeysForIds(roomId, checkedIds); diff --git a/src/mocks/Storage.ts b/src/mocks/Storage.ts index 5dba796a..a5a30ffd 100644 --- a/src/mocks/Storage.ts +++ b/src/mocks/Storage.ts @@ -18,7 +18,7 @@ import {FDBFactory, FDBKeyRange} from "../../lib/fake-indexeddb/index.js"; import {StorageFactory} from "../matrix/storage/idb/StorageFactory"; import {IDOMStorage} from "../matrix/storage/idb/types"; import {Storage} from "../matrix/storage/idb/Storage"; -import {Instance as nullLogger} from "../logging/NullLogger.js"; +import {Instance as nullLogger} from "../logging/NullLogger"; import {openDatabase, CreateObjectStore} from "../matrix/storage/idb/utils"; export function createMockStorage(): Promise { From 30a384fe1e8ddcd7fe627cac55a663e7c6d7e8ea Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 18:44:25 +0530 Subject: [PATCH 41/78] Make LogFilter optional --- src/logging/BaseLogger.ts | 18 +++++++++--------- src/logging/LogItem.ts | 16 ++++++++-------- src/matrix/e2ee/megolm/Decryption.ts | 2 +- src/matrix/storage/idb/StorageFactory.ts | 8 ++------ src/matrix/storage/idb/Transaction.ts | 2 +- src/matrix/storage/idb/schema.ts | 2 +- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index e420c0df..28602b17 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -32,13 +32,13 @@ export abstract class BaseLogger { } log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info) { - const item = new LogItem(labelOrValues, logLevel, null, this); + const item = new LogItem(labelOrValues, logLevel, this); item.end = item.start; this._persistItem(item, undefined, false); } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { + wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -51,28 +51,28 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): ILogItem { // todo: Remove jsdoc type? if (logLevel === null) { logLevel = LogLevel.Info; } - const item = new LogItem(labelOrValues, logLevel, null, this); - this._run(item, callback, logLevel!, filterCreator, false /* don't throw, nobody is awaiting */); + const item = new LogItem(labelOrValues, logLevel, this); + this._run(item, callback, logLevel!, false /* don't throw, nobody is awaiting */, filterCreator); return item; } /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { if (logLevel === null) { logLevel = LogLevel.Info; } - const item = new LogItem(labelOrValues, logLevel, null, this); - return this._run(item, callback, logLevel!, filterCreator, true); + const item = new LogItem(labelOrValues, logLevel, this); + return this._run(item, callback, logLevel!, true, filterCreator); } - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, filterCreator: FilterCreator, shouldThrow: boolean): unknown { + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, shouldThrow: boolean, filterCreator?: FilterCreator): unknown { this._openItems.add(item); const finishItem = () => { diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 54957347..c40d7c08 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -43,7 +43,7 @@ export interface ILogItem { children: Array | null; values: LogItemValues; error: Error | null; - wrap(labelOrValues: LabelOrValues, callback: LogCallback, level: LogLevelOrNull, filterCreator: FilterCreator): unknown; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, level: LogLevelOrNull, filterCreator?: FilterCreator): unknown; log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull): void; set(key: string | object, value: unknown): void; run(callback: LogCallback): unknown; @@ -68,7 +68,7 @@ export type LogItemValues = { } export type LabelOrValues = string | LogItemValues; -export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter) | null; +export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter); export type LogCallback = (item: ILogItem) => unknown; export class LogItem implements ILogItem { @@ -78,10 +78,10 @@ export class LogItem implements ILogItem { public end: number | null; private _values: LogItemValues; private _logger: BaseLogger; - private _filterCreator: FilterCreator; + private _filterCreator?: FilterCreator; private _children: Array | null; - constructor(labelOrValues: LabelOrValues, logLevel: LogLevel, filterCreator: FilterCreator, logger: BaseLogger) { + constructor(labelOrValues: LabelOrValues, logLevel: LogLevel, logger: BaseLogger, filterCreator?: FilterCreator) { this._logger = logger; this.start = logger._now(); this.end = null; @@ -119,7 +119,7 @@ export class LogItem implements ILogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator: FilterCreator = null): unknown { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -161,7 +161,7 @@ export class LogItem implements ILogItem { * Hence, the child item is not returned. */ log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull = null): void { - const item = this.child(labelOrValues, logLevel, null); + const item = this.child(labelOrValues, logLevel); item.end = item.start; } @@ -291,14 +291,14 @@ export class LogItem implements ILogItem { return err; } - child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem { + child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator?: FilterCreator): ILogItem { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } if (!logLevel) { logLevel = this.logLevel || LogLevel.Info; } - const item = new LogItem(labelOrValues, logLevel, filterCreator, this._logger); + const item = new LogItem(labelOrValues, logLevel, this._logger, filterCreator); if (this._children === null) { this._children = []; } diff --git a/src/matrix/e2ee/megolm/Decryption.ts b/src/matrix/e2ee/megolm/Decryption.ts index 4cb66971..ee96eca1 100644 --- a/src/matrix/e2ee/megolm/Decryption.ts +++ b/src/matrix/e2ee/megolm/Decryption.ts @@ -152,7 +152,7 @@ export class Decryption { log.logLevel = log.level.Warn; log.set("invalid", true); } - }, log.level.Detail, null); + }, log.level.Detail); } return keys; } diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 5ca6bce4..5c257bfb 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -101,12 +101,8 @@ async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: nu async (log) => { for (let i = startIdx; i < version; ++i) { const migrationFunc = schema[i]; - await log.wrap(`v${i + 1}`, (log) => - migrationFunc(db, txn, localStorage, log), null, null - ); + await log.wrap(`v${i + 1}`, (log) => migrationFunc(db, txn, localStorage, log), null); } }, - null, - null - ) as Promise; + null) as Promise; } diff --git a/src/matrix/storage/idb/Transaction.ts b/src/matrix/storage/idb/Transaction.ts index 721ee711..c68a1759 100644 --- a/src/matrix/storage/idb/Transaction.ts +++ b/src/matrix/storage/idb/Transaction.ts @@ -226,7 +226,7 @@ export class Transaction { }; const label = `${this._writeErrors.length} storage write operation(s) failed`; if (parentItem) { - parentItem.wrap(label, callback, null, null); + parentItem.wrap(label, callback, null); } else { this.logger.run(label, callback); } diff --git a/src/matrix/storage/idb/schema.ts b/src/matrix/storage/idb/schema.ts index 62a4cea1..b21bd30f 100644 --- a/src/matrix/storage/idb/schema.ts +++ b/src/matrix/storage/idb/schema.ts @@ -207,7 +207,7 @@ async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransact // so we'll create a new one on the next message that will be properly shared outboundGroupSessionsStore.delete(roomId); } - }, null, null); + }, null); } } From 7097ba07d168d1a4156099dd9967310aebfa415a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 18:59:33 +0530 Subject: [PATCH 42/78] Replace LogLabelOrNull type with undefined --- src/logging/BaseLogger.ts | 11 +++++------ src/logging/IDBLogger.ts | 1 + src/logging/LogFilter.ts | 2 -- src/logging/LogItem.ts | 25 ++++++++++++------------ src/matrix/storage/idb/StorageFactory.ts | 5 ++--- src/matrix/storage/idb/Transaction.ts | 2 +- src/matrix/storage/idb/schema.ts | 4 ++-- 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 28602b17..6c377d48 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -18,7 +18,6 @@ limitations under the License. import {LogItem} from "./LogItem"; import {LogLevel, LogFilter} from "./LogFilter"; import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogItem"; -import type {LogLevelOrNull} from "./LogFilter"; // todo: should this import be here just for getting the type? should it instead be done when Platform.js --> Platform.ts? import type {Platform} from "../platform/web/Platform.js"; @@ -38,7 +37,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { + wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -51,9 +50,9 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { // todo: Remove jsdoc type? - if (logLevel === null) { + if (!logLevel) { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, this); @@ -64,8 +63,8 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { - if (logLevel === null) { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { + if (!logLevel) { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, this); diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 960db0da..d5ce2f9a 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -40,6 +40,7 @@ export class IDBLogger extends BaseLogger { private readonly _flushInterval: Interval; private _queuedItems: QueuedItem[]; + // todo: type constructor constructor(options) { super(options); const {name, flushInterval = 60 * 1000, limit = 3000} = options; diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index dc415ede..9968e63e 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -27,8 +27,6 @@ export enum LogLevel { Off } -export type LogLevelOrNull = LogLevel | null; - export class LogFilter { private _min?: LogLevel; private _parentFilter?: LogFilter; diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index c40d7c08..c0325ca7 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -16,7 +16,6 @@ limitations under the License. */ import {LogLevel, LogFilter} from "./LogFilter"; -import type {LogLevelOrNull} from "./LogFilter"; import type {BaseLogger} from "./BaseLogger"; interface ISerializedItem { @@ -43,17 +42,17 @@ export interface ILogItem { children: Array | null; values: LogItemValues; error: Error | null; - wrap(labelOrValues: LabelOrValues, callback: LogCallback, level: LogLevelOrNull, filterCreator?: FilterCreator): unknown; - log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull): void; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown; + log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; run(callback: LogCallback): unknown; - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem; - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): void; - refDetached(logItem: ILogItem, logLevel: LogLevelOrNull): void; + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void; + refDetached(logItem: ILogItem, logLevel?: LogLevel): void; ensureRefId(): void; catch(err: Error): Error; finish(): void; - child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem; + child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; serialize(filter: LogFilter, parentStartTime: number | null, forced: boolean): ISerializedItem | null; } @@ -94,18 +93,18 @@ export class LogItem implements ILogItem { } /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); } /** start a new detached root log item and log a reference to it from this item */ - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull, filterCreator: FilterCreator): void { + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void { this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); } /** logs a reference to a different log item, usually obtained from runDetached. This is useful if the referenced operation can't be awaited. */ - refDetached(logItem: ILogItem, logLevel: LogLevelOrNull = null): void { + refDetached(logItem: ILogItem, logLevel?: LogLevel): void { logItem.ensureRefId(); this.log({ref: (logItem as LogItem)._values.refId}, logLevel); } @@ -119,7 +118,7 @@ export class LogItem implements ILogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel: LogLevelOrNull = null, filterCreator?: FilterCreator): unknown { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -160,7 +159,7 @@ export class LogItem implements ILogItem { * * Hence, the child item is not returned. */ - log(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull = null): void { + log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void { const item = this.child(labelOrValues, logLevel); item.end = item.start; } @@ -291,7 +290,7 @@ export class LogItem implements ILogItem { return err; } - child(labelOrValues: LabelOrValues, logLevel: LogLevelOrNull, filterCreator?: FilterCreator): ILogItem { + child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { if (this.end !== null) { console.trace("log item is finished, additional logs will likely not be recorded"); } diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 5c257bfb..120f73f5 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -101,8 +101,7 @@ async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: nu async (log) => { for (let i = startIdx; i < version; ++i) { const migrationFunc = schema[i]; - await log.wrap(`v${i + 1}`, (log) => migrationFunc(db, txn, localStorage, log), null); + await log.wrap(`v${i + 1}`, (log) => migrationFunc(db, txn, localStorage, log)); } - }, - null) as Promise; + }) as Promise; } diff --git a/src/matrix/storage/idb/Transaction.ts b/src/matrix/storage/idb/Transaction.ts index c68a1759..4c3d2b5c 100644 --- a/src/matrix/storage/idb/Transaction.ts +++ b/src/matrix/storage/idb/Transaction.ts @@ -226,7 +226,7 @@ export class Transaction { }; const label = `${this._writeErrors.length} storage write operation(s) failed`; if (parentItem) { - parentItem.wrap(label, callback, null); + parentItem.wrap(label, callback); } else { this.logger.run(label, callback); } diff --git a/src/matrix/storage/idb/schema.ts b/src/matrix/storage/idb/schema.ts index b21bd30f..6250980d 100644 --- a/src/matrix/storage/idb/schema.ts +++ b/src/matrix/storage/idb/schema.ts @@ -196,7 +196,7 @@ async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransact const updatedIdentity = addRoomToIdentity(identity, userId, roomId); if (updatedIdentity) { log.log({l: `fixing up`, id: userId, - roomsBefore: originalRoomCount, roomsAfter: updatedIdentity.roomIds.length}, null); + roomsBefore: originalRoomCount, roomsAfter: updatedIdentity.roomIds.length}); userIdentitiesStore.put(updatedIdentity); foundMissing = true; } @@ -207,7 +207,7 @@ async function fixMissingRoomsInUserIdentities(db: IDBDatabase, txn: IDBTransact // so we'll create a new one on the next message that will be properly shared outboundGroupSessionsStore.delete(roomId); } - }, null); + }); } } From ba5f2032bafbb32a2700f5c8ee664be5b7ef348c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 19:17:49 +0530 Subject: [PATCH 43/78] Make properties in LogItem optional, not null --- src/logging/LogItem.ts | 29 +++++++++++++---------------- src/logging/NullLogger.ts | 4 ++-- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index c0325ca7..012abc57 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -36,12 +36,12 @@ export interface ILogItem { logger: any; level: typeof LogLevel; duration?: number; - end?: number | null; + end?: number; start?: number; logLevel: LogLevel; - children: Array | null; + children?: Array; values: LogItemValues; - error: Error | null; + error?: Error; wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown; log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; @@ -73,22 +73,19 @@ export type LogCallback = (item: ILogItem) => unknown; export class LogItem implements ILogItem { public readonly start: number; public logLevel: LogLevel; - public error: Error | null; - public end: number | null; + public error?: Error; + public end?: number; private _values: LogItemValues; private _logger: BaseLogger; private _filterCreator?: FilterCreator; - private _children: Array | null; + private _children?: Array; constructor(labelOrValues: LabelOrValues, logLevel: LogLevel, logger: BaseLogger, filterCreator?: FilterCreator) { this._logger = logger; this.start = logger._now(); - this.end = null; // (l)abel this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues; - this.error = null; this.logLevel = logLevel; - this._children = null; this._filterCreator = filterCreator; } @@ -183,7 +180,7 @@ export class LogItem implements ILogItem { } } let children: Array | null = null; - if (this._children !== null) { + if (this._children) { children = this._children.reduce((array: Array, c) => { const s = c.serialize(filter, this.start, false); if (s) { @@ -241,7 +238,7 @@ export class LogItem implements ILogItem { * @return {[type]} [description] */ run(callback: LogCallback): unknown { - if (this.end !== null) { + if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } let result: unknown; @@ -268,8 +265,8 @@ export class LogItem implements ILogItem { * @internal shouldn't typically be called by hand. allows to force finish if a promise is still running when closing the app */ finish(): void { - if (this.end === null) { - if (this._children !== null) { + if (!this.end) { + if (this._children) { for(const c of this._children) { c.finish(); } @@ -291,14 +288,14 @@ export class LogItem implements ILogItem { } child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { - if (this.end !== null) { + if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } if (!logLevel) { logLevel = this.logLevel || LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, this._logger, filterCreator); - if (this._children === null) { + if (!this._children) { this._children = []; } this._children.push(item); @@ -313,7 +310,7 @@ export class LogItem implements ILogItem { return this._values; } - get children(): Array | null { + get children(): Array | undefined { return this._children; } } diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index 285ea1e4..601a1c39 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -52,9 +52,9 @@ export class NullLogger { export class NullLogItem implements ILogItem { public readonly logger: NullLogger; public readonly logLevel: LogLevel; - public children: Array | null = null; + public children?: Array; public values: LogItemValues; - public error: Error | null = null; + public error?: Error; constructor(logger: NullLogger) { this.logger = logger; From fe69f84c8537247d158661cdf1f5ec77e5857e79 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 19:32:16 +0530 Subject: [PATCH 44/78] Use undefined in LogItem.serialize --- src/logging/IDBLogger.ts | 2 +- src/logging/LogItem.ts | 8 ++++---- src/logging/NullLogger.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index d5ce2f9a..dcfd3a64 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -118,7 +118,7 @@ export class IDBLogger extends BaseLogger { } _persistItem(logItem: ILogItem, filter: LogFilter, forced: boolean): void { - const serializedItem = logItem.serialize(filter, null, forced); + const serializedItem = logItem.serialize(filter, undefined, forced); this._queuedItems.push({ json: JSON.stringify(serializedItem) }); diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 012abc57..82f785e4 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -53,7 +53,7 @@ export interface ILogItem { catch(err: Error): Error; finish(): void; child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; - serialize(filter: LogFilter, parentStartTime: number | null, forced: boolean): ISerializedItem | null; + serialize(filter: LogFilter, parentStartTime: number | undefined, forced: boolean): ISerializedItem | undefined; } export type LogItemValues = { @@ -171,7 +171,7 @@ export class LogItem implements ILogItem { } // todo: null or undefined here? - serialize(filter: LogFilter, parentStartTime: number | null = null, forced: boolean): ISerializedItem | null { + serialize(filter: LogFilter, parentStartTime: number | undefined, forced: boolean): ISerializedItem | undefined { if (this._filterCreator) { try { filter = this._filterCreator(new LogFilter(filter), this); @@ -193,12 +193,12 @@ export class LogItem implements ILogItem { }, null); } if (filter && !filter.filter(this, children)) { - return null; + return; } // in (v)alues, (l)abel and (t)ype are also reserved. const item: ISerializedItem = { // (s)tart - s: parentStartTime === null ? this.start : this.start - parentStartTime, + s: parentStartTime? this.start - parentStartTime : this.start, // (d)uration d: this.duration, // (v)alues diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index 601a1c39..63e91f61 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -102,7 +102,7 @@ export class NullLogItem implements ILogItem { finish(): void {} serialize() { - return null; + return undefined; } } From 4c1d7a8f2d098a0fbfa850fd1f421e52f4d080a6 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 15 Nov 2021 22:47:38 +0530 Subject: [PATCH 45/78] Use generics over returning unknown --- src/logging/BaseLogger.ts | 9 +++++---- src/logging/LogItem.ts | 20 ++++++++++---------- src/logging/NullLogger.ts | 8 ++++---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 6c377d48..a2463d3a 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -21,6 +21,7 @@ import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogIte // todo: should this import be here just for getting the type? should it instead be done when Platform.js --> Platform.ts? import type {Platform} from "../platform/web/Platform.js"; +type RunResult = T | void | Promise; export abstract class BaseLogger { protected _openItems: Set = new Set(); @@ -37,7 +38,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { + wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): RunResult { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -50,7 +51,7 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { // todo: Remove jsdoc type? if (!logLevel) { logLevel = LogLevel.Info; @@ -63,7 +64,7 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): RunResult { if (!logLevel) { logLevel = LogLevel.Info; } @@ -71,7 +72,7 @@ export abstract class BaseLogger { return this._run(item, callback, logLevel!, true, filterCreator); } - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, shouldThrow: boolean, filterCreator?: FilterCreator): unknown { + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, shouldThrow: boolean, filterCreator?: FilterCreator): RunResult { this._openItems.add(item); const finishItem = () => { diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 82f785e4..4600b6d5 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -42,12 +42,12 @@ export interface ILogItem { children?: Array; values: LogItemValues; error?: Error; - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise; log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; - run(callback: LogCallback): unknown; - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void; + run(callback: LogCallback): T | Promise; + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void; refDetached(logItem: ILogItem, logLevel?: LogLevel): void; ensureRefId(): void; catch(err: Error): Error; @@ -68,7 +68,7 @@ export type LogItemValues = { export type LabelOrValues = string | LogItemValues; export type FilterCreator = ((filter: LogFilter, item: ILogItem) => LogFilter); -export type LogCallback = (item: ILogItem) => unknown; +export type LogCallback = (item: ILogItem) => T; export class LogItem implements ILogItem { public readonly start: number; @@ -90,12 +90,12 @@ export class LogItem implements ILogItem { } /** start a new root log item and run it detached mode, see BaseLogger.runDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { return this._logger.runDetached(labelOrValues, callback, logLevel, filterCreator); } /** start a new detached root log item and log a reference to it from this item */ - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void { + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void { this.refDetached(this.runDetached(labelOrValues, callback, logLevel, filterCreator)); } @@ -115,7 +115,7 @@ export class LogItem implements ILogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): unknown { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -237,11 +237,11 @@ export class LogItem implements ILogItem { * @param {Function} callback [description] * @return {[type]} [description] */ - run(callback: LogCallback): unknown { + run(callback: LogCallback): T | Promise { if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } - let result: unknown; + let result: T | Promise; try { result = callback(this); if (result instanceof Promise) { diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index 63e91f61..9db1eee4 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -60,22 +60,22 @@ export class NullLogItem implements ILogItem { this.logger = logger; } - wrap(_: LabelOrValues, callback: LogCallback): unknown { + wrap(_: LabelOrValues, callback: LogCallback): T | Promise { return callback(this); } log(): void {} set(): void {} - runDetached(_: LabelOrValues, callback: LogCallback): ILogItem { + runDetached(_: LabelOrValues, callback: LogCallback): ILogItem { new Promise(r => r(callback(this))).then(noop, noop); return this; } - wrapDetached(_: LabelOrValues, _callback: LogCallback): void { + wrapDetached(_: LabelOrValues, _callback: LogCallback): void { return this.refDetached(); } - run(callback: LogCallback): unknown { + run(callback: LogCallback): T | Promise { return callback(this); } From 4161d31642bc664ebaec9b3e51780635a5e88587 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 12:23:06 +0530 Subject: [PATCH 46/78] Convert NullLogger to typescript --- src/logging/NullLogger.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index 9db1eee4..d1ac2a03 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -18,21 +18,20 @@ import type {ILogItem, LabelOrValues, LogCallback, LogItemValues} from "./LogIte function noop (): void {} - export class NullLogger { public readonly item: ILogItem = new NullLogItem(this); log(): void {} - run(_: null, callback) { + run(_, callback: LogCallback): T | Promise { return callback(this.item); } - wrapOrRun(item, _, callback) { + wrapOrRun(item: ILogItem, _, callback: LogCallback): T | Promise { if (item) { - return item.wrap(null, callback); + return item.wrap(_, callback); } else { - return this.run(null, callback); + return this.run(_, callback); } } @@ -40,11 +39,11 @@ export class NullLogger { new Promise(r => r(callback(this.item))).then(noop, noop); } - async export() { + async export(): Promise { return null; } - get level() { + get level(): typeof LogLevel { return LogLevel; } } @@ -63,6 +62,7 @@ export class NullLogItem implements ILogItem { wrap(_: LabelOrValues, callback: LogCallback): T | Promise { return callback(this); } + log(): void {} set(): void {} @@ -95,13 +95,13 @@ export class NullLogItem implements ILogItem { return err; } - child() { + child(): ILogItem { return this; } finish(): void {} - serialize() { + serialize(): undefined { return undefined; } } From 3ee160729883dd6ac71f1d1e05da112f18f54781 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 12:32:49 +0530 Subject: [PATCH 47/78] Convert utils to typescript --- src/logging/utils.js | 16 ---------------- src/logging/utils.ts | 18 ++++++++++++++++++ src/matrix/room/BaseRoom.js | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) delete mode 100644 src/logging/utils.js create mode 100644 src/logging/utils.ts diff --git a/src/logging/utils.js b/src/logging/utils.js deleted file mode 100644 index 659df055..00000000 --- a/src/logging/utils.js +++ /dev/null @@ -1,16 +0,0 @@ -// these are helper functions if you can't assume you always have a log item (e.g. some code paths call with one set, others don't) -// 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"; - -export function wrapOrRunNullLogger(logItem, labelOrValues, callback, logLevel = null, filterCreator = null) { - if (logItem) { - return logItem.wrap(logItem, labelOrValues, callback, logLevel, filterCreator); - } else { - return NullLoggerInstance.run(null, callback); - } -} - -export function ensureLogItem(logItem) { - return logItem || NullLoggerInstance.item; -} diff --git a/src/logging/utils.ts b/src/logging/utils.ts new file mode 100644 index 00000000..61cbce80 --- /dev/null +++ b/src/logging/utils.ts @@ -0,0 +1,18 @@ +// these are helper functions if you can't assume you always have a log item (e.g. some code paths call with one set, others don't) +// 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 {LogLevel} from "./LogFilter"; + +export function wrapOrRunNullLogger(logItem: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise { + if (logItem) { + return logItem.wrap(labelOrValues, callback, logLevel, filterCreator); + } else { + return NullLoggerInstance.run(null, callback); + } +} + +export function ensureLogItem(logItem: ILogItem): ILogItem { + return logItem || NullLoggerInstance.item; +} diff --git a/src/matrix/room/BaseRoom.js b/src/matrix/room/BaseRoom.js index 1aa8cb18..93973b71 100644 --- a/src/matrix/room/BaseRoom.js +++ b/src/matrix/room/BaseRoom.js @@ -27,7 +27,7 @@ import {Heroes} from "./members/Heroes.js"; import {EventEntry} from "./timeline/entries/EventEntry.js"; import {ObservedEventMap} from "./ObservedEventMap.js"; import {DecryptionSource} from "../e2ee/common.js"; -import {ensureLogItem} from "../../logging/utils.js"; +import {ensureLogItem} from "../../logging/utils"; import {PowerLevels} from "./PowerLevels.js"; import {RetainedObservableValue} from "../../observable/ObservableValue"; From 286747c23c01074b28ddf29f5e281addb1c31634 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 12:41:03 +0530 Subject: [PATCH 48/78] Add type annotation for ctor --- src/logging/IDBLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index dcfd3a64..c5fa2a52 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -41,7 +41,7 @@ export class IDBLogger extends BaseLogger { private _queuedItems: QueuedItem[]; // todo: type constructor - constructor(options) { + constructor(options: {name: string, flushInterval?: number, limit?: number, platform: Platform}) { super(options); const {name, flushInterval = 60 * 1000, limit = 3000} = options; this._name = name; From e339e730f413d30d3a2891dd5074783c8e817b34 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 12:42:50 +0530 Subject: [PATCH 49/78] Remove todo comment --- src/logging/IDBLogger.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index c5fa2a52..944116b8 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -40,7 +40,6 @@ export class IDBLogger extends BaseLogger { private readonly _flushInterval: Interval; private _queuedItems: QueuedItem[]; - // todo: type constructor constructor(options: {name: string, flushInterval?: number, limit?: number, platform: Platform}) { super(options); const {name, flushInterval = 60 * 1000, limit = 3000} = options; From 34a8463bf912af38a0708586de6bbcb107af8930 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 12:43:23 +0530 Subject: [PATCH 50/78] Fix jsdoc return type --- src/logging/BaseLogger.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index a2463d3a..f6c88aff 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -50,9 +50,8 @@ export abstract class BaseLogger { where the (async) result or errors are not propagated but still logged. Useful to pair with LogItem.refDetached. - @return {LogItem} the log item added, useful to pass to LogItem.refDetached */ + @return {ILogItem} the log item added, useful to pass to LogItem.refDetached */ runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { - // todo: Remove jsdoc type? if (!logLevel) { logLevel = LogLevel.Info; } From 4704a70cb78d5c2c35e57c54248958ca9ad36956 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 13:06:47 +0530 Subject: [PATCH 51/78] Remove todo comment --- src/logging/BaseLogger.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index f6c88aff..ddf1b308 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -18,7 +18,6 @@ limitations under the License. import {LogItem} from "./LogItem"; import {LogLevel, LogFilter} from "./LogFilter"; import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogItem"; -// todo: should this import be here just for getting the type? should it instead be done when Platform.js --> Platform.ts? import type {Platform} from "../platform/web/Platform.js"; type RunResult = T | void | Promise; From 58105824d9669ed2fa9dafb9b76ee2c84965c311 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 13:08:13 +0530 Subject: [PATCH 52/78] Fix error in reduce --- src/logging/LogItem.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 4600b6d5..c12308ef 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -141,9 +141,7 @@ export class LogItem implements ILogItem { } else if (this._children) { return this._children.reduce((sum, c) => { const duration = c.durationOfType(type); - if (duration) { - return sum + duration; - } + return sum + (duration ?? 0); }, 0); } else { return 0; From 14eaa574342eca3cf6443fbdb0d9ed019bdeee8b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 16 Nov 2021 13:14:11 +0530 Subject: [PATCH 53/78] No need for type assertion here --- src/matrix/storage/idb/StorageFactory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 120f73f5..3c7e0e40 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -103,5 +103,5 @@ async function createStores(db: IDBDatabase, txn: IDBTransaction, oldVersion: nu const migrationFunc = schema[i]; await log.wrap(`v${i + 1}`, (log) => migrationFunc(db, txn, localStorage, log)); } - }) as Promise; + }); } From 8fce29caf7593c82677e35342e41d9e88d8a046b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 11:38:33 +0530 Subject: [PATCH 54/78] Explicitly check for undefined --- src/logging/LogFilter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 9968e63e..5f0e7ae7 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -42,7 +42,7 @@ export class LogFilter { } } // neither our children or us have a loglevel high enough, filter out. - if (this._min && !Array.isArray(children) && item.logLevel < this._min) { + if (this._min !== undefined && !Array.isArray(children) && item.logLevel < this._min) { return false; } else { return true; From b0ab8cd77f8ae373b07cb330e1f7881c17192253 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 11:40:38 +0530 Subject: [PATCH 55/78] Space before { --- src/logging/LogItem.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index c12308ef..717eadfd 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -120,7 +120,7 @@ export class LogItem implements ILogItem { return item.run(callback); } - get duration(): number | undefined{ + get duration(): number | undefined { if (this.end) { return this.end - this.start; } else { @@ -128,7 +128,7 @@ export class LogItem implements ILogItem { } } - durationWithoutType(type: string): number | undefined{ + durationWithoutType(type: string): number | undefined { const durationOfType = this.durationOfType(type); if (this.duration && durationOfType) { return this.duration - durationOfType; From 9c8f96e233e2bb16234d5a536d39d88932f0a9f0 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Wed, 17 Nov 2021 11:43:59 +0530 Subject: [PATCH 56/78] value is optional Co-authored-by: Bruno Windels --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 717eadfd..fd9fcb1d 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -159,7 +159,7 @@ export class LogItem implements ILogItem { item.end = item.start; } - set(key: string | object, value: unknown): void { + set(key: string | object, value?: unknown): void { if(typeof key === "object") { const values = key; Object.assign(this._values, values); From 835da58b53fe745de68741a548fd45d7695d6c15 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 11:59:50 +0530 Subject: [PATCH 57/78] Remove ! --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index ddf1b308..c9ce6aaf 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -55,7 +55,7 @@ export abstract class BaseLogger { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, this); - this._run(item, callback, logLevel!, false /* don't throw, nobody is awaiting */, filterCreator); + this._run(item, callback, logLevel, false /* don't throw, nobody is awaiting */, filterCreator); return item; } From 07a1130db33963ba4090657432aed766fd8af501 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 12:02:12 +0530 Subject: [PATCH 58/78] children can be array of ISerializedItem --- src/logging/LogFilter.ts | 4 ++-- src/logging/LogItem.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index 5f0e7ae7..d0189631 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type {ILogItem} from "./LogItem"; +import type {ILogItem, ISerializedItem} from "./LogItem"; export enum LogLevel { All = 1, @@ -35,7 +35,7 @@ export class LogFilter { this._parentFilter = parentFilter; } - filter(item: ILogItem, children: Array | null): boolean { + filter(item: ILogItem, children: ISerializedItem[] | null): boolean { if (this._parentFilter) { if (!this._parentFilter.filter(item, children)) { return false; diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index fd9fcb1d..30a6294a 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -18,7 +18,7 @@ limitations under the License. import {LogLevel, LogFilter} from "./LogFilter"; import type {BaseLogger} from "./BaseLogger"; -interface ISerializedItem { +export interface ISerializedItem { s: number; d?: number; v: LogItemValues; From d01271fb150ba19f0183c25e3cd3ffaa78d8899e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 13:22:19 +0530 Subject: [PATCH 59/78] _run return T or void depending on boolean --- src/logging/BaseLogger.ts | 26 +++++++++++++++----------- src/logging/LogItem.ts | 10 +++++----- src/logging/NullLogger.ts | 4 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index c9ce6aaf..999db4cf 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -20,8 +20,6 @@ import {LogLevel, LogFilter} from "./LogFilter"; import type {FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./LogItem"; import type {Platform} from "../platform/web/Platform.js"; -type RunResult = T | void | Promise; - export abstract class BaseLogger { protected _openItems: Set = new Set(); protected _platform: Platform; @@ -37,7 +35,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): RunResult { + wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { @@ -62,7 +60,7 @@ export abstract class BaseLogger { /** run a callback wrapped in a log operation. Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ - run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): RunResult { + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { if (!logLevel) { logLevel = LogLevel.Info; } @@ -70,7 +68,9 @@ export abstract class BaseLogger { return this._run(item, callback, logLevel!, true, filterCreator); } - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, shouldThrow: boolean, filterCreator?: FilterCreator): RunResult { + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: true, filterCreator?: FilterCreator): T; + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: false, filterCreator?: FilterCreator): void; + _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: boolean, filterCreator?: FilterCreator): T | void { this._openItems.add(item); const finishItem = () => { @@ -94,24 +94,28 @@ export abstract class BaseLogger { }; try { - const result = item.run(callback); + let result = item.run(callback); if (result instanceof Promise) { - return result.then(promiseResult => { + result = result.then(promiseResult => { finishItem(); return promiseResult; }, err => { finishItem(); - if (shouldThrow) { + if (wantResult) { throw err; } - }); - } else { + }) as unknown as T; + if (wantResult) { + return result; + } + } + if(wantResult) { finishItem(); return result; } } catch (err) { finishItem(); - if (shouldThrow) { + if (wantResult) { throw err; } } diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 30a6294a..c3d32ef5 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -42,10 +42,10 @@ export interface ILogItem { children?: Array; values: LogItemValues; error?: Error; - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; - run(callback: LogCallback): T | Promise; + run(callback: LogCallback): T; runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void; refDetached(logItem: ILogItem, logLevel?: LogLevel): void; @@ -115,7 +115,7 @@ export class LogItem implements ILogItem { /** * Creates a new child item and runs it in `callback`. */ - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise { + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { const item = this.child(labelOrValues, logLevel, filterCreator); return item.run(callback); } @@ -235,7 +235,7 @@ export class LogItem implements ILogItem { * @param {Function} callback [description] * @return {[type]} [description] */ - run(callback: LogCallback): T | Promise { + run(callback: LogCallback): T { if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } @@ -248,7 +248,7 @@ export class LogItem implements ILogItem { return promiseResult; }, err => { throw this.catch(err); - }); + }) as unknown as T; } else { this.finish(); return result; diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index d1ac2a03..eba453e6 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -59,7 +59,7 @@ export class NullLogItem implements ILogItem { this.logger = logger; } - wrap(_: LabelOrValues, callback: LogCallback): T | Promise { + wrap(_: LabelOrValues, callback: LogCallback): T { return callback(this); } @@ -75,7 +75,7 @@ export class NullLogItem implements ILogItem { return this.refDetached(); } - run(callback: LogCallback): T | Promise { + run(callback: LogCallback): T { return callback(this); } From 1942c31eff00b46451efc27d410ccf009548968d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 10:42:54 +0100 Subject: [PATCH 60/78] still finish item when not returning from sync callback --- src/logging/BaseLogger.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 999db4cf..f14caa5e 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -69,6 +69,7 @@ export abstract class BaseLogger { } _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: true, filterCreator?: FilterCreator): T; + // we don't return if we don't throw, as we don't have anything to return when an error is caught but swallowed for the fire-and-forget case. _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: false, filterCreator?: FilterCreator): void; _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: boolean, filterCreator?: FilterCreator): T | void { this._openItems.add(item); @@ -108,10 +109,11 @@ export abstract class BaseLogger { if (wantResult) { return result; } - } - if(wantResult) { + } else { finishItem(); - return result; + if(wantResult) { + return result; + } } } catch (err) { finishItem(); From f93bdd962a8085d827cfc14bc5c3757f9d817b47 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 10:50:55 +0100 Subject: [PATCH 61/78] might as well use generic here --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index f14caa5e..4b04b510 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -48,7 +48,7 @@ export abstract class BaseLogger { Useful to pair with LogItem.refDetached. @return {ILogItem} the log item added, useful to pass to LogItem.refDetached */ - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { if (!logLevel) { logLevel = LogLevel.Info; } From 90d7b73dd4b6e328667f7e89132f9352d2d5b547 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 11:08:29 +0100 Subject: [PATCH 62/78] non-persisted queued items don't have an id yet, find them by ref equality --- src/logging/IDBLogger.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 944116b8..ebcf2249 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -152,12 +152,14 @@ export class IDBLogger extends BaseLogger { const txn = db.transaction(["logs"], "readwrite"); const logs = txn.objectStore("logs"); for (const item of items) { - const queuedIdx = this._queuedItems.findIndex(i => i.id === item.id); - if (queuedIdx === -1) { - // todo: isn't id optional? do we need further checks here - logs.delete(item.id!); // resolve questionable use of non-null assertion operator? + if (typeof item.id === "number") { + logs.delete(item.id); } else { - this._queuedItems.splice(queuedIdx, 1); + // assume the (non-persisted) object in each array will be the same + const queuedIdx = this._queuedItems.indexOf(item); + if (queuedIdx === -1) { + this._queuedItems.splice(queuedIdx, 1); + } } } await txnAsPromise(txn); From 3ee7e73ff0530f33c4a3d1d95d287c831ba81cd9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 11:08:44 +0100 Subject: [PATCH 63/78] item is optional here --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 4b04b510..3b2842ad 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -35,7 +35,7 @@ export abstract class BaseLogger { } /** if item is a log item, wrap the callback in a child of it, otherwise start a new root log item. */ - wrapOrRun(item: ILogItem, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { + wrapOrRun(item: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { if (item) { return item.wrap(labelOrValues, callback, logLevel, filterCreator); } else { From 1b13f32d94a17a198533fc001f331078388df7a0 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 17 Nov 2021 15:22:08 +0530 Subject: [PATCH 64/78] Remove resolved todo comment --- src/logging/LogItem.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index c3d32ef5..9521b67b 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -168,7 +168,6 @@ export class LogItem implements ILogItem { } } - // todo: null or undefined here? serialize(filter: LogFilter, parentStartTime: number | undefined, forced: boolean): ISerializedItem | undefined { if (this._filterCreator) { try { From 695996d6e2f5f66edc617aa4b9a0ef54bde630a7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 11:38:17 +0100 Subject: [PATCH 65/78] add ILogger and ILogExport interface, to give export correct return type also move logging related types to own file --- src/logging/BaseLogger.ts | 6 +- src/logging/ConsoleLogger.ts | 6 +- src/logging/IDBLogger.ts | 6 +- src/logging/LogFilter.ts | 2 +- src/logging/LogItem.ts | 53 +---------- src/logging/NullLogger.ts | 15 ++-- src/logging/types.ts | 87 +++++++++++++++++++ src/logging/utils.ts | 2 +- src/matrix/e2ee/megolm/Decryption.ts | 2 +- src/matrix/storage/idb/QueryTarget.ts | 2 +- src/matrix/storage/idb/Storage.ts | 6 +- src/matrix/storage/idb/StorageFactory.ts | 3 +- src/matrix/storage/idb/Store.ts | 2 +- src/matrix/storage/idb/Transaction.ts | 5 +- src/matrix/storage/idb/schema.ts | 2 +- src/matrix/storage/idb/stores/SessionStore.ts | 2 +- .../storage/idb/stores/TimelineEventStore.ts | 2 +- 17 files changed, 119 insertions(+), 84 deletions(-) create mode 100644 src/logging/types.ts diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 3b2842ad..7d015262 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -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 = 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; // expose log level without needing get level(): typeof LogLevel { diff --git a/src/logging/ConsoleLogger.ts b/src/logging/ConsoleLogger.ts index d8693e38..20fdf6a6 100644 --- a/src/logging/ConsoleLogger.ts +++ b/src/logging/ConsoleLogger.ts @@ -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 { + return undefined; } } diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index ebcf2249..621359dc 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -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 { + async export(): Promise { 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; diff --git a/src/logging/LogFilter.ts b/src/logging/LogFilter.ts index d0189631..8611d5f3 100644 --- a/src/logging/LogFilter.ts +++ b/src/logging/LogFilter.ts @@ -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, diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 9521b67b..7774dd41 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -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; -}; - -export interface ILogItem { - logger: any; - level: typeof LogLevel; - duration?: number; - end?: number; - start?: number; - logLevel: LogLevel; - children?: Array; - values: LogItemValues; - error?: Error; - wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; - log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; - set(key: string | object, value: unknown): void; - run(callback: LogCallback): T; - runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; - wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, 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 = (item: ILogItem) => T; +import type {ISerializedItem, ILogItem, LogItemValues, LabelOrValues, FilterCreator, LogCallback} from "./types"; export class LogItem implements ILogItem { public readonly start: number; diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index eba453e6..ed12cd78 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -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(_, callback: LogCallback): T | Promise { + run(_, callback: LogCallback): T { return callback(this.item); } - wrapOrRun(item: ILogItem, _, callback: LogCallback): T | Promise { + wrapOrRun(item: ILogItem | undefined, _, callback: LogCallback): 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 { - return null; + async export(): Promise { + return undefined; } get level(): typeof LogLevel { diff --git a/src/logging/types.ts b/src/logging/types.ts new file mode 100644 index 00000000..6a29a7a2 --- /dev/null +++ b/src/logging/types.ts @@ -0,0 +1,87 @@ +/* +Copyright 2020 Bruno Windels +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; +}; + +export interface ILogItem { + logger: any; + level: typeof LogLevel; + duration?: number; + end?: number; + start?: number; + logLevel: LogLevel; + children?: Array; + values: LogItemValues; + error?: Error; + wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; + log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; + set(key: string | object, value: unknown): void; + run(callback: LogCallback): T; + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; + wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, 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(item: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; + runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; + run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; + export(): Promise; + get level(): typeof LogLevel; +} + +export interface ILogExport { + get count(): number; + removeFromStore(): Promise; + 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 = (item: ILogItem) => T; diff --git a/src/logging/utils.ts b/src/logging/utils.ts index 61cbce80..2b32454d 100644 --- a/src/logging/utils.ts +++ b/src/logging/utils.ts @@ -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(logItem: ILogItem | undefined, labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T | Promise { diff --git a/src/matrix/e2ee/megolm/Decryption.ts b/src/matrix/e2ee/megolm/Decryption.ts index ee96eca1..e139e8c9 100644 --- a/src/matrix/e2ee/megolm/Decryption.ts +++ b/src/matrix/e2ee/megolm/Decryption.ts @@ -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; diff --git a/src/matrix/storage/idb/QueryTarget.ts b/src/matrix/storage/idb/QueryTarget.ts index 7519beac..5bea1139 100644 --- a/src/matrix/storage/idb/QueryTarget.ts +++ b/src/matrix/storage/idb/QueryTarget.ts @@ -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, diff --git a/src/matrix/storage/idb/Storage.ts b/src/matrix/storage/idb/Storage.ts index 728d4fca..6f3ed8ad 100644 --- a/src/matrix/storage/idb/Storage.ts +++ b/src/matrix/storage/idb/Storage.ts @@ -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; diff --git a/src/matrix/storage/idb/StorageFactory.ts b/src/matrix/storage/idb/StorageFactory.ts index 3c7e0e40..5cb1b6e5 100644 --- a/src/matrix/storage/idb/StorageFactory.ts +++ b/src/matrix/storage/idb/StorageFactory.ts @@ -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) { diff --git a/src/matrix/storage/idb/Store.ts b/src/matrix/storage/idb/Store.ts index 5a2a9abc..07cc90b0 100644 --- a/src/matrix/storage/idb/Store.ts +++ b/src/matrix/storage/idb/Store.ts @@ -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; diff --git a/src/matrix/storage/idb/Transaction.ts b/src/matrix/storage/idb/Transaction.ts index 4c3d2b5c..80894105 100644 --- a/src/matrix/storage/idb/Transaction.ts +++ b/src/matrix/storage/idb/Transaction.ts @@ -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; } diff --git a/src/matrix/storage/idb/schema.ts b/src/matrix/storage/idb/schema.ts index 6250980d..ad3e5896 100644 --- a/src/matrix/storage/idb/schema.ts +++ b/src/matrix/storage/idb/schema.ts @@ -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; diff --git a/src/matrix/storage/idb/stores/SessionStore.ts b/src/matrix/storage/idb/stores/SessionStore.ts index dd133b45..7faedc41 100644 --- a/src/matrix/storage/idb/stores/SessionStore.ts +++ b/src/matrix/storage/idb/stores/SessionStore.ts @@ -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; diff --git a/src/matrix/storage/idb/stores/TimelineEventStore.ts b/src/matrix/storage/idb/stores/TimelineEventStore.ts index b3663c29..bb6f652f 100644 --- a/src/matrix/storage/idb/stores/TimelineEventStore.ts +++ b/src/matrix/storage/idb/stores/TimelineEventStore.ts @@ -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; From 5f362cbdbde6b17cfe28e6b39e38d8e8a2245b9a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 11:54:29 +0100 Subject: [PATCH 66/78] remove dead code --- src/logging/ConsoleLogger.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/logging/ConsoleLogger.ts b/src/logging/ConsoleLogger.ts index 20fdf6a6..f2a2efd1 100644 --- a/src/logging/ConsoleLogger.ts +++ b/src/logging/ConsoleLogger.ts @@ -28,10 +28,6 @@ export class ConsoleLogger extends BaseLogger { const excludedKeysFromTable = ["l", "id"]; function filterValues(values: LogItemValues): LogItemValues | null { - if (!values) { - // todo: is this check here unnecessary because LogItem will always have values? - return null; - } return Object.entries(values) .filter(([key]) => !excludedKeysFromTable.includes(key)) .reduce((obj: LogItemValues, [key, value]) => { From b1d20178f816addce705fa143f87a8d1009f013e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 12:37:50 +0100 Subject: [PATCH 67/78] add explicit void return type --- src/logging/BaseLogger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 7d015262..6ff50b98 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -28,7 +28,7 @@ export abstract class BaseLogger implements ILogger { this._platform = platform; } - log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info) { + log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info): void { const item = new LogItem(labelOrValues, logLevel, this); item.end = item.start; this._persistItem(item, undefined, false); From 276d8d4a42c4532fc6fcecb6dbe5b4b4f219a18f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 12:39:57 +0100 Subject: [PATCH 68/78] check for undefined, no need for ! --- src/logging/BaseLogger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 6ff50b98..2f7389ab 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -61,11 +61,11 @@ export abstract class BaseLogger implements ILogger { Errors and duration are transparently logged, also for async operations. Whatever the callback returns is returned here. */ run(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T { - if (!logLevel) { + if (logLevel === undefined) { logLevel = LogLevel.Info; } const item = new LogItem(labelOrValues, logLevel, this); - return this._run(item, callback, logLevel!, true, filterCreator); + return this._run(item, callback, logLevel, true, filterCreator); } _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: true, filterCreator?: FilterCreator): T; From 46dd78162fa9f6f467193e381e287319064c0c4a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 12:54:32 +0100 Subject: [PATCH 69/78] no need to dig into internals here --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 7774dd41..1d9ce20b 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -52,7 +52,7 @@ export class LogItem implements ILogItem { This is useful if the referenced operation can't be awaited. */ refDetached(logItem: ILogItem, logLevel?: LogLevel): void { logItem.ensureRefId(); - this.log({ref: (logItem as LogItem)._values.refId}, logLevel); + this.log({ref: logItem.values.refId}, logLevel); } ensureRefId(): void { From 74fb15e426c549f3ff3d29c8d9aead918298fac4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 12:54:44 +0100 Subject: [PATCH 70/78] add future todo note --- src/logging/IDBLogger.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/logging/IDBLogger.ts b/src/logging/IDBLogger.ts index 621359dc..96147ca1 100644 --- a/src/logging/IDBLogger.ts +++ b/src/logging/IDBLogger.ts @@ -51,6 +51,7 @@ export class IDBLogger extends BaseLogger { this._flushInterval = this._platform.clock.createInterval(() => this._tryFlush(), flushInterval); } + // TODO: move dispose to ILogger, listen to pagehide elsewhere and call dispose from there, which calls _finishAllAndFlush dispose(): void { window.removeEventListener("pagehide", this, false); this._flushInterval.dispose(); From afc538e87598a7bfa82c5158ce5f2c8d20353131 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 12:58:08 +0100 Subject: [PATCH 71/78] explicitly check for type, rather than truthy --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 1d9ce20b..0e5b0ecb 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -144,7 +144,7 @@ export class LogItem implements ILogItem { // in (v)alues, (l)abel and (t)ype are also reserved. const item: ISerializedItem = { // (s)tart - s: parentStartTime? this.start - parentStartTime : this.start, + s: typeof parentStartTime === "number" ? this.start - parentStartTime : this.start, // (d)uration d: this.duration, // (v)alues From 526a81826936eb23454ffbeccb17043bb65de69e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 13:42:49 +0100 Subject: [PATCH 72/78] only used internally --- src/logging/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logging/types.ts b/src/logging/types.ts index 6a29a7a2..280b5606 100644 --- a/src/logging/types.ts +++ b/src/logging/types.ts @@ -46,7 +46,6 @@ export interface ILogItem { wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; - run(callback: LogCallback): T; runDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem; wrapDetached(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): void; refDetached(logItem: ILogItem, logLevel?: LogLevel): void; From 42e5fb33ba9071cc8f0b47e2a335ac40299dbc47 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 13:50:56 +0100 Subject: [PATCH 73/78] remove more non-public methods from ILogItem interface --- src/logging/BaseLogger.ts | 8 ++++---- src/logging/LogItem.ts | 2 +- src/logging/types.ts | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 2f7389ab..7112c948 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -21,7 +21,7 @@ import type {ILogger, ILogExport, FilterCreator, LabelOrValues, LogCallback, ILo import type {Platform} from "../platform/web/Platform.js"; export abstract class BaseLogger implements ILogger { - protected _openItems: Set = new Set(); + protected _openItems: Set = new Set(); protected _platform: Platform; constructor({platform}) { @@ -68,10 +68,10 @@ export abstract class BaseLogger implements ILogger { return this._run(item, callback, logLevel, true, filterCreator); } - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: true, filterCreator?: FilterCreator): T; + _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, wantResult: true, filterCreator?: FilterCreator): T; // we don't return if we don't throw, as we don't have anything to return when an error is caught but swallowed for the fire-and-forget case. - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: false, filterCreator?: FilterCreator): void; - _run(item: ILogItem, callback: LogCallback, logLevel: LogLevel, wantResult: boolean, filterCreator?: FilterCreator): T | void { + _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, wantResult: false, filterCreator?: FilterCreator): void; + _run(item: LogItem, callback: LogCallback, logLevel: LogLevel, wantResult: boolean, filterCreator?: FilterCreator): T | void { this._openItems.add(item); const finishItem = () => { diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 0e5b0ecb..4fb8daa0 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -233,7 +233,7 @@ export class LogItem implements ILogItem { return err; } - child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): ILogItem { + child(labelOrValues: LabelOrValues, logLevel?: LogLevel, filterCreator?: FilterCreator): LogItem { if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } diff --git a/src/logging/types.ts b/src/logging/types.ts index 280b5606..f90572e5 100644 --- a/src/logging/types.ts +++ b/src/logging/types.ts @@ -51,8 +51,6 @@ export interface ILogItem { 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; } From fde0163b978dcc1d9dfc969ad3547c8212514a23 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 13:53:27 +0100 Subject: [PATCH 74/78] remove unneeded union type and simplify code --- src/logging/LogItem.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index 4fb8daa0..f9262db7 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -187,9 +187,8 @@ export class LogItem implements ILogItem { if (this.end) { console.trace("log item is finished, additional logs will likely not be recorded"); } - let result: T | Promise; try { - result = callback(this); + const result = callback(this); if (result instanceof Promise) { return result.then(promiseResult => { this.finish(); From 41a10d9697c8424ec93ca8d2d1820705cfab1161 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 13:56:20 +0100 Subject: [PATCH 75/78] explicitly check for undefined --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index f9262db7..cd5a5a8b 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -184,7 +184,7 @@ export class LogItem implements ILogItem { * @return {[type]} [description] */ run(callback: LogCallback): T { - if (this.end) { + if (this.end !== undefined) { console.trace("log item is finished, additional logs will likely not be recorded"); } try { From 4030a4918d13ebfa72f7d1f7205546fa3fda6a12 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 13:57:11 +0100 Subject: [PATCH 76/78] explicitly check for undefined --- src/logging/LogItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging/LogItem.ts b/src/logging/LogItem.ts index cd5a5a8b..da009b06 100644 --- a/src/logging/LogItem.ts +++ b/src/logging/LogItem.ts @@ -210,7 +210,7 @@ export class LogItem implements ILogItem { * @internal shouldn't typically be called by hand. allows to force finish if a promise is still running when closing the app */ finish(): void { - if (!this.end) { + if (this.end === undefined) { if (this._children) { for(const c of this._children) { c.finish(); From b5e9eb26baf4a0dd71f0d9c69a898fd747f59a71 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 14:33:58 +0100 Subject: [PATCH 77/78] reduce size of ILogItem interface further --- src/logging/BaseLogger.ts | 2 +- src/logging/ConsoleLogger.ts | 5 +++-- src/logging/types.ts | 12 +++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/logging/BaseLogger.ts b/src/logging/BaseLogger.ts index 7112c948..723c2f17 100644 --- a/src/logging/BaseLogger.ts +++ b/src/logging/BaseLogger.ts @@ -139,7 +139,7 @@ export abstract class BaseLogger implements ILogger { this._openItems.clear(); } - abstract _persistItem(item: ILogItem, filter?: LogFilter, forced?: boolean): void; + abstract _persistItem(item: LogItem, filter?: LogFilter, forced?: boolean): void; abstract export(): Promise; diff --git a/src/logging/ConsoleLogger.ts b/src/logging/ConsoleLogger.ts index f2a2efd1..f48c72b2 100644 --- a/src/logging/ConsoleLogger.ts +++ b/src/logging/ConsoleLogger.ts @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ import {BaseLogger} from "./BaseLogger"; +import {LogItem} from "./LogItem"; import type {ILogItem, LogItemValues, ILogExport} from "./types"; export class ConsoleLogger extends BaseLogger { - _persistItem(item: ILogItem): void { + _persistItem(item: LogItem): void { printToConsole(item); } @@ -37,7 +38,7 @@ function filterValues(values: LogItemValues): LogItemValues | null { }, null); } -function printToConsole(item: ILogItem): void { +function printToConsole(item: LogItem): void { const label = `${itemCaption(item)} (${item.duration}ms)`; const filteredValues = filterValues(item.values); const shouldGroup = item.children || filteredValues; diff --git a/src/logging/types.ts b/src/logging/types.ts index f90572e5..01755960 100644 --- a/src/logging/types.ts +++ b/src/logging/types.ts @@ -34,15 +34,13 @@ export interface ISerializedItem { }; export interface ILogItem { - logger: any; - level: typeof LogLevel; - duration?: number; - end?: number; - start?: number; logLevel: LogLevel; - children?: Array; - values: LogItemValues; error?: Error; + readonly logger: ILogger; + readonly level: typeof LogLevel; + readonly end?: number; + readonly start?: number; + readonly values: LogItemValues; wrap(labelOrValues: LabelOrValues, callback: LogCallback, logLevel?: LogLevel, filterCreator?: FilterCreator): T; log(labelOrValues: LabelOrValues, logLevel?: LogLevel): void; set(key: string | object, value: unknown): void; From 692ae25e76efd348f84e2946e6c2945c56467524 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Nov 2021 14:35:26 +0100 Subject: [PATCH 78/78] remove unused method --- src/logging/NullLogger.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/logging/NullLogger.ts b/src/logging/NullLogger.ts index ed12cd78..5ec38aa9 100644 --- a/src/logging/NullLogger.ts +++ b/src/logging/NullLogger.ts @@ -76,10 +76,6 @@ export class NullLogItem implements ILogItem { return this.refDetached(); } - run(callback: LogCallback): T { - return callback(this); - } - refDetached(): void {} ensureRefId(): void {}