From ccb99841b95664b7a17d786bf5032b60517f610a Mon Sep 17 00:00:00 2001 From: namark Date: Sat, 30 Oct 2021 15:57:55 +0400 Subject: [PATCH 1/8] Initial implementation of logging utilities. --- src/domain/shared/Log.ts | 235 ++++++++++++++++++++++++++++++++++ tests/Log.unit.test.ts | 269 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 504 insertions(+) create mode 100644 src/domain/shared/Log.ts create mode 100644 tests/Log.unit.test.ts diff --git a/src/domain/shared/Log.ts b/src/domain/shared/Log.ts new file mode 100644 index 00000000..58affd77 --- /dev/null +++ b/src/domain/shared/Log.ts @@ -0,0 +1,235 @@ +// +// Log.ts +// +// Created by Nshan G. on 29 Oct 2021. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +export enum LogLevel { + DEBUG, + DEFAULT, + INFO, + WARNING, + ERROR, +} + +export const allLogLevels = [ + LogLevel.DEBUG, + LogLevel.DEFAULT, + LogLevel.INFO, + LogLevel.WARNING, + LogLevel.ERROR, +] as const; + +type LogFunction = (message: string, messageType?: string) => void; + +/*@devdoc + * The LoggerContext is an interface for configuration of the output of the Logger class. + * @interface LoggerContext + * + */ +export interface LoggerContext { + getFunction(level: LogLevel): LogFunction | undefined; +} + + +/*@devdoc + * The StringLoggerContext is a logger configuration for logging to the dev console. + * + * @class Logger + */ +export class ConsoleLoggerContext implements LoggerContext { + + static #_typeFirst(func: (fisrs:string, second?:string) => void) { + return (message: string, messageType?: string) => messageType ? func(`[${messageType}]`, message) : func(message); ; + } + // it is necessary to capture the console object here, for things like jest's mocks to work, + // hence the no-op looking lambda wrappers + static #_functions = new Map([ + [LogLevel.DEFAULT, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.log(...params))], + [LogLevel.DEBUG, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.debug(...params))], + [LogLevel.INFO, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.info(...params))], + [LogLevel.WARNING, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.warn(...params))], + [LogLevel.ERROR, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.error(...params))] + ]); + + getFunction(level: LogLevel) + { + return ConsoleLoggerContext.#_functions.get(level); + } +} + +/*@devdoc + * The StringLoggerContext is a configuration for logging to a string. + * + * @class Logger + */ +export class StringLoggerContext implements LoggerContext { + buffer: string = ""; + #_functions = new Map(); + + constructor() { + for(let level of allLogLevels) { + this.#_functions.set(level, (message: string, messageType?: string) => { + if (messageType) { + this.buffer += `[${messageType}]`; + } + this.buffer += `[${LogLevel[level]}] ${message}\n`; + }); + } + } + + getFunction(level: LogLevel) { + return this.#_functions.get(level); + } + +}; + +/*@devdoc + * The Logger class serves as a convenience utility and a centralized configuration point for logging. + * + * @class Logger + */ +export class Logger +{ + #_context: LoggerContext; + #_activeFunctions = new Map(); + #_typeFilter?: Array; + + #_messageIds = new Map(); + #_typedMessageIds = new Map(); + #_messageFlags = new Map(); + + /*@devdoc + * Creates a logger instance with a specified context. + * @param {context} LoggerContext - The context this instance will use for output, + * which can also store any addition state, like an output buffer. + */ + constructor(context: LoggerContext) { + this.#_context = context; + this.filterLevels(() => true); + } + + /*@devdoc + * Logs a message at an appropriate level, with optional type. + * @param {level} LogLevel - the level to log at + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + level(level: LogLevel, message: string, messageType?: string) { + const log = this.#_activeFunctions.get(level); + if (log && this.#_isTypeAllowed(messageType) ) { + log(message, messageType); + } + } + + /*@devdoc + * Logs a message at an appropriate level, with optional type, only once. + * @param {level} LogLevel - the level to log at + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + once(level: LogLevel, message: string, messageType?: string) { + const idMap = messageType ? this.#_typedMessageIds : this.#_messageIds; + + const key = `${messageType} | ${level} | ${message}`; + + let id: Object; + + if(!idMap.has(key)) { + id = new Object(); + idMap.set(key, id); + } else{ + id = idMap.get(key) as Object; + } + + if (!this.#_messageFlags.get(id)) { + this.#_messageFlags.set(id, true); + this.level(level, message, messageType); + } + } + + /*@devdoc + * Logs a message at the default level, with optional type. + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + default(message: string, messageType?: string) { + this.level(LogLevel.DEFAULT, message, messageType); + } + + /*@devdoc + * Logs a message at the info level, with optional type. + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + info(message: string, messageType?: string) { + this.level(LogLevel.INFO, message, messageType); + } + + /*@devdoc + * Logs a message at the debug level, with optional type. + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + debug(message: string, messageType?: string) { + this.level(LogLevel.DEBUG, message, messageType); + } + + /*@devdoc + * Logs a message at the warning level, with optional type. + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + warning(message: string, messageType?: string) { + this.level(LogLevel.WARNING, message, messageType); + } + + /*@devdoc + * Logs a message at the error level, with optional type. + * @param {message} string - the message to log + * @param {messageType} string - optional user defined message type + */ + error(message: string, messageType?: string) { + this.level(LogLevel.ERROR, message, messageType); + } + + /*@devdoc + * Applies a filer to all subsequently logged messages, based on level. + * @param {pred} (level: LogLevel) => boolean - the filtering condition + */ + filterLevels(pred: (level: LogLevel) => boolean) { + this.#_activeFunctions = new Map(); + for (var level of allLogLevels) { + const func = this.#_context.getFunction(level); + if (func && pred(level)) { + this.#_activeFunctions.set(level, func); + } + } + } + + /*@devdoc + * Sets a filter for all subsequently logged messages, based on user defined types. + * @param {filter} Array - the collection of types to allow, + * presence or presence of undefined value will determine whether to show or hide messages with no type specified. + */ + setTypeFilter(filter?: Array) { + this.#_typeFilter = filter; + } + + #_isTypeAllowed(messageType?: string) { + return !this.#_typeFilter || this.#_typeFilter.includes(messageType); + } + +} + +/*@devdoc + * The Log is the main Logger instance used in the SDK. + */ +const Log = new Logger(new ConsoleLoggerContext()); + +export default Log; diff --git a/tests/Log.unit.test.ts b/tests/Log.unit.test.ts new file mode 100644 index 00000000..2fb09bfa --- /dev/null +++ b/tests/Log.unit.test.ts @@ -0,0 +1,269 @@ +// +// DomainServer.unit.test.js +// +// Created by Nshan G. on 30 Oct 2021. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import {Logger, LogLevel, ConsoleLoggerContext, StringLoggerContext} from "../src/domain/shared/Log"; + +describe("Logger - unit tests", () => { + + test("Console context", () => { + + const logger = new Logger(new ConsoleLoggerContext()); + + const debug = jest.spyOn(console, "debug").mockImplementation(() => { /* no-op */ }); + const log = jest.spyOn(console, "log").mockImplementation(() => { /* no-op */ }); + const info = jest.spyOn(console, "info").mockImplementation(() => { /* no-op */ }); + const warn = jest.spyOn(console, "warn").mockImplementation(() => { /* no-op */ }); + const error = jest.spyOn(console, "error").mockImplementation(() => { /* no-op */ }); + + logger.debug("Console debug message"); + logger.default("Console log message"); + logger.info("Console info message"); + logger.warning("Console warning message"); + logger.error("Console error message"); + + expect(debug).toBeCalledWith("Console debug message"); + expect(log).toBeCalledWith("Console log message"); + expect(info).toBeCalledWith("Console info message"); + expect(warn).toBeCalledWith("Console warning message"); + expect(error).toBeCalledWith("Console error message"); + + debug.mockClear(); + log.mockClear(); + info.mockClear(); + warn.mockClear(); + error.mockClear(); + + logger.debug("Console debug message", "Type 1"); + logger.default("Console log message", "Type 2"); + logger.info("Console info message", "Type 3"); + logger.warning("Console warning message", "Type 4"); + logger.error("Console error message", "Type 5"); + + expect(debug).toBeCalledWith("[Type 1]", "Console debug message"); + expect(log).toBeCalledWith("[Type 2]", "Console log message"); + expect(info).toBeCalledWith("[Type 3]", "Console info message"); + expect(warn).toBeCalledWith("[Type 4]", "Console warning message"); + expect(error).toBeCalledWith("[Type 5]", "Console error message"); + + debug.mockRestore(); + log.mockRestore(); + info.mockRestore(); + warn.mockRestore(); + error.mockRestore(); + + }); + + test("String context", () => { + const context = new StringLoggerContext(); + const logger = new Logger(context); + + logger.debug("Debug message"); + logger.default("Default message"); + logger.info("Info message"); + logger.warning("Warning message"); + logger.error("Error message"); + + expect(context.buffer).toBe("" + + "[DEBUG] Debug message\n" + + "[DEFAULT] Default message\n" + + "[INFO] Info message\n" + + "[WARNING] Warning message\n" + + "[ERROR] Error message\n" + ); + context.buffer = ""; + + logger.debug("Debug message", "Type 1"); + logger.default("Default message", "Type 2"); + logger.info("Info message", "Type 3"); + logger.warning("Warning message", "Type 4"); + logger.error("Error message", "Type 5"); + + expect(context.buffer).toBe("" + + "[Type 1][DEBUG] Debug message\n" + + "[Type 2][DEFAULT] Default message\n" + + "[Type 3][INFO] Info message\n" + + "[Type 4][WARNING] Warning message\n" + + "[Type 5][ERROR] Error message\n" + ); + }); + + test("Filtering by level", () => { + const context = new StringLoggerContext(); + const logger = new Logger(context); + + logger.filterLevels(level => level >= LogLevel.INFO); + + logger.debug("Debug message"); + logger.default("Default message"); + logger.info("Info message"); + logger.warning("Warning message"); + logger.error("Error message"); + + expect(context.buffer).toBe("" + + "[INFO] Info message\n" + + "[WARNING] Warning message\n" + + "[ERROR] Error message\n" + ); + context.buffer = ""; + + logger.filterLevels(level => level <= LogLevel.DEFAULT); + + logger.debug("Debug message"); + logger.default("Default message"); + logger.info("Info message"); + logger.warning("Warning message"); + logger.error("Error message"); + + expect(context.buffer).toBe("" + + "[DEBUG] Debug message\n" + + "[DEFAULT] Default message\n" + ); + context.buffer = ""; + + logger.filterLevels(level => [LogLevel.DEBUG, LogLevel.ERROR].includes(level)); + + logger.debug("Debug message"); + logger.default("Default message"); + logger.info("Info message"); + logger.warning("Warning message"); + logger.error("Error message"); + + expect(context.buffer).toBe("" + + "[DEBUG] Debug message\n" + + "[ERROR] Error message\n" + ); + + }); + + test("Filtering by type", () => { + const context = new StringLoggerContext(); + const logger = new Logger(context); + + logger.setTypeFilter(["Type 2", "Type 4"]); + + logger.default("message"); + logger.default("message 1", "Type 1"); + logger.default("message 2", "Type 2"); + logger.default("message 3", "Type 3"); + logger.default("message 4", "Type 4"); + logger.default("message 5", "Type 5"); + + expect(context.buffer).toBe("" + + "[Type 2][DEFAULT] message 2\n" + + "[Type 4][DEFAULT] message 4\n" + ); + context.buffer = ""; + + logger.setTypeFilter(["Type 1", "Type 3", undefined]); + + logger.default("message"); + logger.default("message 1", "Type 1"); + logger.default("message 2", "Type 2"); + logger.default("message 3", "Type 3"); + logger.default("message 4", "Type 4"); + logger.default("message 5", "Type 5"); + + expect(context.buffer).toBe("" + + "[DEFAULT] message\n" + + "[Type 1][DEFAULT] message 1\n" + + "[Type 3][DEFAULT] message 3\n" + ); + context.buffer = ""; + + logger.setTypeFilter([undefined]); + + logger.default("message"); + logger.default("message 1", "Type 1"); + logger.default("message 2", "Type 2"); + logger.default("message 3", "Type 3"); + logger.default("message 4", "Type 4"); + logger.default("message 5", "Type 5"); + + expect(context.buffer).toBe("" + + "[DEFAULT] message\n" + ); + context.buffer = ""; + + logger.setTypeFilter(); + + logger.default("message"); + logger.default("message 1", "Type 1"); + logger.default("message 2", "Type 2"); + logger.default("message 3", "Type 3"); + logger.default("message 4", "Type 4"); + logger.default("message 5", "Type 5"); + + expect(context.buffer).toBe("" + + "[DEFAULT] message\n" + + "[Type 1][DEFAULT] message 1\n" + + "[Type 2][DEFAULT] message 2\n" + + "[Type 3][DEFAULT] message 3\n" + + "[Type 4][DEFAULT] message 4\n" + + "[Type 5][DEFAULT] message 5\n" + ); + context.buffer = ""; + + }); + + test("Mixed filtering", () => { + const context = new StringLoggerContext(); + const logger = new Logger(context); + + logger.filterLevels(level => level <= LogLevel.DEFAULT); + logger.setTypeFilter(["Type 2"]); + + logger.default("message"); + logger.debug("Debug message 1", "Type 1"); + logger.default("Default message 2", "Type 2"); + logger.info("Info message 1", "Type 1"); + logger.warning("message 2", "Type 2"); + logger.error("message 1", "Type 1"); + + expect(context.buffer).toBe("" + + "[Type 2][DEFAULT] Default message 2\n" + ); + context.buffer = ""; + }); + + test("Logger.once", () => { + const context = new StringLoggerContext(); + const logger = new Logger(context); + + logger.once(LogLevel.DEBUG, "message"); + logger.once(LogLevel.DEBUG, "message"); + logger.once(LogLevel.DEBUG, "message"); + + logger.once(LogLevel.DEBUG, "message", "Type"); + logger.once(LogLevel.DEBUG, "message", "Type"); + logger.once(LogLevel.DEBUG, "message", "Type"); + + logger.once(LogLevel.DEBUG, "message", "undefined"); + logger.once(LogLevel.DEBUG, "message", "undefined"); + logger.once(LogLevel.DEBUG, "message", "undefined"); + + logger.once(LogLevel.INFO, "message"); + logger.once(LogLevel.INFO, "message"); + logger.once(LogLevel.INFO, "message"); + + logger.once(LogLevel.DEBUG, "another message"); + logger.once(LogLevel.DEBUG, "another message"); + logger.once(LogLevel.DEBUG, "another message"); + + expect(context.buffer).toBe("" + + "[DEBUG] message\n" + + "[Type][DEBUG] message\n" + + "[undefined][DEBUG] message\n" + + "[INFO] message\n" + + "[DEBUG] another message\n" + ); + context.buffer = ""; + }); + +}); From eed3499fa416e7665727efe8672b1199d97fb2e1 Mon Sep 17 00:00:00 2001 From: namark Date: Sat, 30 Oct 2021 23:40:16 +0400 Subject: [PATCH 2/8] Some not implemented warnings logged only once. --- src/domain/audio-client/AudioClient.ts | 5 +++-- src/domain/audio/InboundAudioStream.ts | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/domain/audio-client/AudioClient.ts b/src/domain/audio-client/AudioClient.ts index 2dfafc63..c3e084cc 100644 --- a/src/domain/audio-client/AudioClient.ts +++ b/src/domain/audio-client/AudioClient.ts @@ -22,6 +22,7 @@ import PacketScribe from "../networking/packets/PacketScribe"; import PacketType, { PacketTypeValue } from "../networking/udt/PacketHeaders"; import assert from "../shared/assert"; import ContextManager from "../shared/ContextManager"; +import Log, {LogLevel} from "../shared/Log"; /*@devdoc @@ -405,7 +406,7 @@ class AudioClient { #processStreamStatsPacket = (message: ReceivedMessage, sendingNode?: Node): void => { // eslint-disable-line // C++ void AudioIOStats::processStreamStatsPacket(ReceivedMessage*, Node* sendingNode) - console.warn("AudioClient: AudioStreamStats packet not processed."); + Log.once(LogLevel.WARNING, "AudioClient: AudioStreamStats packet not processed."); // WEBRTC TODO: Address further C++ code. @@ -417,7 +418,7 @@ class AudioClient { #handleAudioEnvironmentDataPacket = (message: ReceivedMessage): void => { // eslint-disable-line // C++ void handleAudioEnvironmentDataPacket(ReceivedMessage* message) - console.warn("AudioClient: AudioEnvironment packet not processed."); + Log.once(LogLevel.WARNING, "AudioClient: AudioEnvironment packet not processed."); // WEBRTC TODO: Address further C++ code. diff --git a/src/domain/audio/InboundAudioStream.ts b/src/domain/audio/InboundAudioStream.ts index 51f9e20b..0e29571b 100644 --- a/src/domain/audio/InboundAudioStream.ts +++ b/src/domain/audio/InboundAudioStream.ts @@ -16,6 +16,7 @@ import { SilentAudioFrameDetails } from "../networking/packets/SilentAudioFrame" import PacketType from "../networking/udt/PacketHeaders"; import UDT from "../networking/udt/UDT"; import ContextManager from "../shared/ContextManager"; +import Log, {LogLevel} from "../shared/Log"; /*@devdoc @@ -124,7 +125,7 @@ class InboundAudioStream { // C++ int writeDroppableSilentFrames(int silentFrames) // WEBRTC TODO: Address further C++ code. - console.warn("InboundAudioStream.#writeDroppableSilentFrames() not implemented. Frames:", silentFrames); + Log.once(LogLevel.WARNING, `InboundAudioStream.#writeDroppableSilentFrames() not implemented. Frames: ${silentFrames}`); } From 2684c9f49d5f3e11476325c273838e4dad742270 Mon Sep 17 00:00:00 2001 From: namark Date: Sun, 31 Oct 2021 00:36:24 +0400 Subject: [PATCH 3/8] Fixed linting errors. --- src/domain/audio-client/AudioClient.ts | 2 +- src/domain/audio/InboundAudioStream.ts | 2 +- src/domain/shared/Log.ts | 90 +++++++++++++----------- tests/Log.unit.test.ts | 96 +++++++++++++------------- 4 files changed, 100 insertions(+), 90 deletions(-) diff --git a/src/domain/audio-client/AudioClient.ts b/src/domain/audio-client/AudioClient.ts index c3e084cc..767e2c86 100644 --- a/src/domain/audio-client/AudioClient.ts +++ b/src/domain/audio-client/AudioClient.ts @@ -22,7 +22,7 @@ import PacketScribe from "../networking/packets/PacketScribe"; import PacketType, { PacketTypeValue } from "../networking/udt/PacketHeaders"; import assert from "../shared/assert"; import ContextManager from "../shared/ContextManager"; -import Log, {LogLevel} from "../shared/Log"; +import Log, { LogLevel } from "../shared/Log"; /*@devdoc diff --git a/src/domain/audio/InboundAudioStream.ts b/src/domain/audio/InboundAudioStream.ts index 0e29571b..94d5a549 100644 --- a/src/domain/audio/InboundAudioStream.ts +++ b/src/domain/audio/InboundAudioStream.ts @@ -16,7 +16,7 @@ import { SilentAudioFrameDetails } from "../networking/packets/SilentAudioFrame" import PacketType from "../networking/udt/PacketHeaders"; import UDT from "../networking/udt/UDT"; import ContextManager from "../shared/ContextManager"; -import Log, {LogLevel} from "../shared/Log"; +import Log, { LogLevel } from "../shared/Log"; /*@devdoc diff --git a/src/domain/shared/Log.ts b/src/domain/shared/Log.ts index 58affd77..ef7a3c50 100644 --- a/src/domain/shared/Log.ts +++ b/src/domain/shared/Log.ts @@ -14,7 +14,7 @@ export enum LogLevel { DEFAULT, INFO, WARNING, - ERROR, + ERROR } export const allLogLevels = [ @@ -22,7 +22,7 @@ export const allLogLevels = [ LogLevel.DEFAULT, LogLevel.INFO, LogLevel.WARNING, - LogLevel.ERROR, + LogLevel.ERROR ] as const; type LogFunction = (message: string, messageType?: string) => void; @@ -44,23 +44,32 @@ export interface LoggerContext { */ export class ConsoleLoggerContext implements LoggerContext { - static #_typeFirst(func: (fisrs:string, second?:string) => void) { - return (message: string, messageType?: string) => messageType ? func(`[${messageType}]`, message) : func(message); ; + static #_typeFirst(func: (fisrs: string, second?: string) => void): LogFunction { + return (message: string, messageType?: string) => { + if (messageType) { + return func(`[${messageType}]`, message); + } + return func(message); + }; } + // it is necessary to capture the console object here, for things like jest's mocks to work, // hence the no-op looking lambda wrappers static #_functions = new Map([ + /* eslint-disable @typescript-eslint/no-explicit-any */ [LogLevel.DEFAULT, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.log(...params))], [LogLevel.DEBUG, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.debug(...params))], [LogLevel.INFO, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.info(...params))], [LogLevel.WARNING, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.warn(...params))], [LogLevel.ERROR, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.error(...params))] + /* eslint-enable @typescript-eslint/no-explicit-any */ ]); - getFunction(level: LogLevel) - { + /* eslint-disable class-methods-use-this */ + getFunction(level: LogLevel): LogFunction | undefined { return ConsoleLoggerContext.#_functions.get(level); } + /* eslint-enable class-methods-use-this */ } /*@devdoc @@ -69,40 +78,39 @@ export class ConsoleLoggerContext implements LoggerContext { * @class Logger */ export class StringLoggerContext implements LoggerContext { - buffer: string = ""; + buffer = ""; #_functions = new Map(); constructor() { - for(let level of allLogLevels) { + for (const level of allLogLevels) { this.#_functions.set(level, (message: string, messageType?: string) => { if (messageType) { - this.buffer += `[${messageType}]`; + this.buffer += `[${messageType}]`; } - this.buffer += `[${LogLevel[level]}] ${message}\n`; + this.buffer += `[${LogLevel[level] as string}] ${message}\n`; }); } } - getFunction(level: LogLevel) { + getFunction(level: LogLevel): LogFunction | undefined { return this.#_functions.get(level); } -}; +} /*@devdoc * The Logger class serves as a convenience utility and a centralized configuration point for logging. * * @class Logger */ -export class Logger -{ +export class Logger { #_context: LoggerContext; - #_activeFunctions = new Map(); + #_activeFunctions = new Map(); #_typeFilter?: Array; - #_messageIds = new Map(); - #_typedMessageIds = new Map(); - #_messageFlags = new Map(); + #_messageIds = new Map(); + #_typedMessageIds = new Map(); + #_messageFlags = new Map(); /*@devdoc * Creates a logger instance with a specified context. @@ -120,9 +128,9 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - level(level: LogLevel, message: string, messageType?: string) { + level(level: LogLevel, message: string, messageType?: string): void { const log = this.#_activeFunctions.get(level); - if (log && this.#_isTypeAllowed(messageType) ) { + if (log && this.#_isTypeAllowed(messageType)) { log(message, messageType); } } @@ -133,19 +141,12 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - once(level: LogLevel, message: string, messageType?: string) { + once(level: LogLevel, message: string, messageType?: string): void { const idMap = messageType ? this.#_typedMessageIds : this.#_messageIds; - const key = `${messageType} | ${level} | ${message}`; + const key = `${messageType || "undefined"} | ${level} | ${message}`; - let id: Object; - - if(!idMap.has(key)) { - id = new Object(); - idMap.set(key, id); - } else{ - id = idMap.get(key) as Object; - } + const id = Logger.#_getMessageId(idMap, key); if (!this.#_messageFlags.get(id)) { this.#_messageFlags.set(id, true); @@ -158,7 +159,7 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - default(message: string, messageType?: string) { + message(message: string, messageType?: string): void { this.level(LogLevel.DEFAULT, message, messageType); } @@ -167,7 +168,7 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - info(message: string, messageType?: string) { + info(message: string, messageType?: string): void { this.level(LogLevel.INFO, message, messageType); } @@ -176,7 +177,7 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - debug(message: string, messageType?: string) { + debug(message: string, messageType?: string): void { this.level(LogLevel.DEBUG, message, messageType); } @@ -185,7 +186,7 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - warning(message: string, messageType?: string) { + warning(message: string, messageType?: string): void { this.level(LogLevel.WARNING, message, messageType); } @@ -194,7 +195,7 @@ export class Logger * @param {message} string - the message to log * @param {messageType} string - optional user defined message type */ - error(message: string, messageType?: string) { + error(message: string, messageType?: string): void { this.level(LogLevel.ERROR, message, messageType); } @@ -202,12 +203,12 @@ export class Logger * Applies a filer to all subsequently logged messages, based on level. * @param {pred} (level: LogLevel) => boolean - the filtering condition */ - filterLevels(pred: (level: LogLevel) => boolean) { + filterLevels(pred: (level: LogLevel) => boolean): void { this.#_activeFunctions = new Map(); - for (var level of allLogLevels) { + for (const level of allLogLevels) { const func = this.#_context.getFunction(level); if (func && pred(level)) { - this.#_activeFunctions.set(level, func); + this.#_activeFunctions.set(level, func); } } } @@ -217,14 +218,23 @@ export class Logger * @param {filter} Array - the collection of types to allow, * presence or presence of undefined value will determine whether to show or hide messages with no type specified. */ - setTypeFilter(filter?: Array) { + setTypeFilter(filter?: Array): void { this.#_typeFilter = filter; } - #_isTypeAllowed(messageType?: string) { + #_isTypeAllowed(messageType?: string): boolean { return !this.#_typeFilter || this.#_typeFilter.includes(messageType); } + static #_getMessageId(idMap: Map, key: string): unknown { + if (!idMap.has(key)) { + const id = {}; + idMap.set(key, id); + return id; + } + return idMap.get(key); + } + } /*@devdoc diff --git a/tests/Log.unit.test.ts b/tests/Log.unit.test.ts index 2fb09bfa..090b2c36 100644 --- a/tests/Log.unit.test.ts +++ b/tests/Log.unit.test.ts @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import {Logger, LogLevel, ConsoleLoggerContext, StringLoggerContext} from "../src/domain/shared/Log"; +import { Logger, LogLevel, ConsoleLoggerContext, StringLoggerContext } from "../src/domain/shared/Log"; describe("Logger - unit tests", () => { @@ -23,16 +23,16 @@ describe("Logger - unit tests", () => { const error = jest.spyOn(console, "error").mockImplementation(() => { /* no-op */ }); logger.debug("Console debug message"); - logger.default("Console log message"); + logger.message("Console log message"); logger.info("Console info message"); logger.warning("Console warning message"); logger.error("Console error message"); - expect(debug).toBeCalledWith("Console debug message"); - expect(log).toBeCalledWith("Console log message"); - expect(info).toBeCalledWith("Console info message"); - expect(warn).toBeCalledWith("Console warning message"); - expect(error).toBeCalledWith("Console error message"); + expect(debug).toHaveBeenCalledWith("Console debug message"); + expect(log).toHaveBeenCalledWith("Console log message"); + expect(info).toHaveBeenCalledWith("Console info message"); + expect(warn).toHaveBeenCalledWith("Console warning message"); + expect(error).toHaveBeenCalledWith("Console error message"); debug.mockClear(); log.mockClear(); @@ -41,16 +41,16 @@ describe("Logger - unit tests", () => { error.mockClear(); logger.debug("Console debug message", "Type 1"); - logger.default("Console log message", "Type 2"); + logger.message("Console log message", "Type 2"); logger.info("Console info message", "Type 3"); logger.warning("Console warning message", "Type 4"); logger.error("Console error message", "Type 5"); - expect(debug).toBeCalledWith("[Type 1]", "Console debug message"); - expect(log).toBeCalledWith("[Type 2]", "Console log message"); - expect(info).toBeCalledWith("[Type 3]", "Console info message"); - expect(warn).toBeCalledWith("[Type 4]", "Console warning message"); - expect(error).toBeCalledWith("[Type 5]", "Console error message"); + expect(debug).toHaveBeenCalledWith("[Type 1]", "Console debug message"); + expect(log).toHaveBeenCalledWith("[Type 2]", "Console log message"); + expect(info).toHaveBeenCalledWith("[Type 3]", "Console info message"); + expect(warn).toHaveBeenCalledWith("[Type 4]", "Console warning message"); + expect(error).toHaveBeenCalledWith("[Type 5]", "Console error message"); debug.mockRestore(); log.mockRestore(); @@ -65,7 +65,7 @@ describe("Logger - unit tests", () => { const logger = new Logger(context); logger.debug("Debug message"); - logger.default("Default message"); + logger.message("Default message"); logger.info("Info message"); logger.warning("Warning message"); logger.error("Error message"); @@ -80,7 +80,7 @@ describe("Logger - unit tests", () => { context.buffer = ""; logger.debug("Debug message", "Type 1"); - logger.default("Default message", "Type 2"); + logger.message("Default message", "Type 2"); logger.info("Info message", "Type 3"); logger.warning("Warning message", "Type 4"); logger.error("Error message", "Type 5"); @@ -98,10 +98,10 @@ describe("Logger - unit tests", () => { const context = new StringLoggerContext(); const logger = new Logger(context); - logger.filterLevels(level => level >= LogLevel.INFO); + logger.filterLevels((level) => level >= LogLevel.INFO); logger.debug("Debug message"); - logger.default("Default message"); + logger.message("Default message"); logger.info("Info message"); logger.warning("Warning message"); logger.error("Error message"); @@ -113,10 +113,10 @@ describe("Logger - unit tests", () => { ); context.buffer = ""; - logger.filterLevels(level => level <= LogLevel.DEFAULT); + logger.filterLevels((level) => level <= LogLevel.DEFAULT); logger.debug("Debug message"); - logger.default("Default message"); + logger.message("Default message"); logger.info("Info message"); logger.warning("Warning message"); logger.error("Error message"); @@ -127,10 +127,10 @@ describe("Logger - unit tests", () => { ); context.buffer = ""; - logger.filterLevels(level => [LogLevel.DEBUG, LogLevel.ERROR].includes(level)); + logger.filterLevels((level) => [LogLevel.DEBUG, LogLevel.ERROR].includes(level)); logger.debug("Debug message"); - logger.default("Default message"); + logger.message("Default message"); logger.info("Info message"); logger.warning("Warning message"); logger.error("Error message"); @@ -148,12 +148,12 @@ describe("Logger - unit tests", () => { logger.setTypeFilter(["Type 2", "Type 4"]); - logger.default("message"); - logger.default("message 1", "Type 1"); - logger.default("message 2", "Type 2"); - logger.default("message 3", "Type 3"); - logger.default("message 4", "Type 4"); - logger.default("message 5", "Type 5"); + logger.message("message"); + logger.message("message 1", "Type 1"); + logger.message("message 2", "Type 2"); + logger.message("message 3", "Type 3"); + logger.message("message 4", "Type 4"); + logger.message("message 5", "Type 5"); expect(context.buffer).toBe("" + "[Type 2][DEFAULT] message 2\n" @@ -163,12 +163,12 @@ describe("Logger - unit tests", () => { logger.setTypeFilter(["Type 1", "Type 3", undefined]); - logger.default("message"); - logger.default("message 1", "Type 1"); - logger.default("message 2", "Type 2"); - logger.default("message 3", "Type 3"); - logger.default("message 4", "Type 4"); - logger.default("message 5", "Type 5"); + logger.message("message"); + logger.message("message 1", "Type 1"); + logger.message("message 2", "Type 2"); + logger.message("message 3", "Type 3"); + logger.message("message 4", "Type 4"); + logger.message("message 5", "Type 5"); expect(context.buffer).toBe("" + "[DEFAULT] message\n" @@ -179,12 +179,12 @@ describe("Logger - unit tests", () => { logger.setTypeFilter([undefined]); - logger.default("message"); - logger.default("message 1", "Type 1"); - logger.default("message 2", "Type 2"); - logger.default("message 3", "Type 3"); - logger.default("message 4", "Type 4"); - logger.default("message 5", "Type 5"); + logger.message("message"); + logger.message("message 1", "Type 1"); + logger.message("message 2", "Type 2"); + logger.message("message 3", "Type 3"); + logger.message("message 4", "Type 4"); + logger.message("message 5", "Type 5"); expect(context.buffer).toBe("" + "[DEFAULT] message\n" @@ -193,12 +193,12 @@ describe("Logger - unit tests", () => { logger.setTypeFilter(); - logger.default("message"); - logger.default("message 1", "Type 1"); - logger.default("message 2", "Type 2"); - logger.default("message 3", "Type 3"); - logger.default("message 4", "Type 4"); - logger.default("message 5", "Type 5"); + logger.message("message"); + logger.message("message 1", "Type 1"); + logger.message("message 2", "Type 2"); + logger.message("message 3", "Type 3"); + logger.message("message 4", "Type 4"); + logger.message("message 5", "Type 5"); expect(context.buffer).toBe("" + "[DEFAULT] message\n" @@ -216,12 +216,12 @@ describe("Logger - unit tests", () => { const context = new StringLoggerContext(); const logger = new Logger(context); - logger.filterLevels(level => level <= LogLevel.DEFAULT); + logger.filterLevels((level) => level <= LogLevel.DEFAULT); logger.setTypeFilter(["Type 2"]); - logger.default("message"); + logger.message("message"); logger.debug("Debug message 1", "Type 1"); - logger.default("Default message 2", "Type 2"); + logger.message("Default message 2", "Type 2"); logger.info("Info message 1", "Type 1"); logger.warning("message 2", "Type 2"); logger.error("message 1", "Type 1"); From ceddde4375fcc5fcda5090097ead77ffa922fe51 Mon Sep 17 00:00:00 2001 From: namark Date: Sun, 31 Oct 2021 02:08:04 +0400 Subject: [PATCH 4/8] Moved logger test to appropriate directory. --- tests/{ => domain/shared}/Log.unit.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{ => domain/shared}/Log.unit.test.ts (100%) diff --git a/tests/Log.unit.test.ts b/tests/domain/shared/Log.unit.test.ts similarity index 100% rename from tests/Log.unit.test.ts rename to tests/domain/shared/Log.unit.test.ts From 7fd356fff44be4658afe4dc01f9537d9b1812ecf Mon Sep 17 00:00:00 2001 From: namark Date: Sun, 31 Oct 2021 02:10:38 +0400 Subject: [PATCH 5/8] Fixed logger unit test import. --- tests/domain/shared/Log.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/domain/shared/Log.unit.test.ts b/tests/domain/shared/Log.unit.test.ts index 090b2c36..f4196b2e 100644 --- a/tests/domain/shared/Log.unit.test.ts +++ b/tests/domain/shared/Log.unit.test.ts @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import { Logger, LogLevel, ConsoleLoggerContext, StringLoggerContext } from "../src/domain/shared/Log"; +import { Logger, LogLevel, ConsoleLoggerContext, StringLoggerContext } from "../../../src/domain/shared/Log"; describe("Logger - unit tests", () => { From 666bb7fcf40bfad8f1d1fc74efc81186bb9008a5 Mon Sep 17 00:00:00 2001 From: namark Date: Sun, 31 Oct 2021 02:21:39 +0400 Subject: [PATCH 6/8] Replaced all console logs with the logger utility. --- src/AudioMixer.ts | 7 +++--- src/DomainServer.ts | 19 ++++++++-------- src/domain/AssignmentClient.ts | 3 ++- src/domain/audio-client/AudioClient.ts | 17 +++++++------- src/domain/audio/AudioInput.ts | 7 +++--- src/domain/audio/AudioOutput.ts | 3 ++- src/domain/audio/InboundAudioStream.ts | 7 +++--- src/domain/networking/DomainHandler.ts | 11 +++++----- src/domain/networking/HMACAuth.ts | 3 ++- src/domain/networking/LimitedNodeList.ts | 22 ++++++++++--------- src/domain/networking/NLPacket.ts | 5 +++-- src/domain/networking/NetworkPeer.ts | 13 ++++++----- src/domain/networking/NodeList.ts | 7 +++--- src/domain/networking/PacketReceiver.ts | 5 +++-- src/domain/networking/udt/BasePacket.ts | 5 +++-- src/domain/networking/udt/Packet.ts | 7 +++--- src/domain/networking/udt/PacketHeaders.ts | 3 ++- src/domain/networking/udt/Socket.ts | 12 +++++----- .../networking/webrtc/WebRTCDataChannel.ts | 17 +++++++------- .../webrtc/WebRTCSignalingChannel.ts | 7 +++--- src/domain/worklets/AudioInputProcessor.ts | 3 ++- 21 files changed, 103 insertions(+), 80 deletions(-) diff --git a/src/AudioMixer.ts b/src/AudioMixer.ts index a60e6bfe..96fde04b 100644 --- a/src/AudioMixer.ts +++ b/src/AudioMixer.ts @@ -15,6 +15,7 @@ import AudioOutput from "./domain/audio/AudioOutput"; import AudioClient from "./domain/audio-client/AudioClient"; import NodeType from "./domain/networking/NodeType"; import ContextManager from "./domain/shared/ContextManager"; +import Log from "./domain/shared/Log"; /*@sdkdoc @@ -109,13 +110,13 @@ class AudioMixer extends AssignmentClient { set audioInput(audioInput: MediaStream | null) { if (audioInput !== null && !(audioInput instanceof MediaStream)) { - console.error("Tried to set an invalid AudioMixer.audioInput value!"); + Log.error("Tried to set an invalid AudioMixer.audioInput value!", "audio"); return; } void this.#_audioClient.switchInputDevice(audioInput).then((success) => { if (!success) { - console.warn("Could not set the audio input."); + Log.warning("Could not set the audio input.", "audio"); } }); } @@ -126,7 +127,7 @@ class AudioMixer extends AssignmentClient { set inputMuted(inputMuted: boolean) { if (typeof inputMuted !== "boolean") { - console.error("Tried to set an invalid AudioMixer.inputMuted value!"); + Log.error("Tried to set an invalid AudioMixer.inputMuted value!", "audio"); return; } this.#_audioClient.setMuted(inputMuted); diff --git a/src/DomainServer.ts b/src/DomainServer.ts index f1f37189..603d949d 100644 --- a/src/DomainServer.ts +++ b/src/DomainServer.ts @@ -15,6 +15,7 @@ import Node from "./domain/networking/Node"; import NodeList from "./domain/networking/NodeList"; import NodeType from "./domain/networking/NodeType"; import ContextManager from "./domain/shared/ContextManager"; +import Log from "./domain/shared/Log"; /*@sdkdoc @@ -208,7 +209,7 @@ class DomainServer { if (typeof callback === "function" || callback === null) { this.#_onStateChanged = callback; } else { - console.error("ERROR: DomainServer.onStateChanged callback not a function or null!"); + Log.error("ERROR: DomainServer.onStateChanged callback not a function or null!"); this.#_onStateChanged = null; } } @@ -239,7 +240,7 @@ class DomainServer { if (typeof location === "string") { this.#_location = location.trim(); } else { - console.error("ERROR: DomainServer.connect() location parameter not a string!"); + Log.error("ERROR: DomainServer.connect() location parameter not a string!"); this.#_location = ""; } @@ -291,7 +292,7 @@ class DomainServer { #setState(state: ConnectionState, info = ""): void { const hasStateChanged = state !== this.#_state; if (this.#_DEBUG && !hasStateChanged) { - console.warn("DomainServer: State hasn't changed."); + Log.warning("DomainServer: State hasn't changed."); } this.#_state = state; @@ -341,7 +342,7 @@ class DomainServer { #nodeAdded = (node: Node): void => { // C++ void Application:: nodeAdded(Node* node) if (node.getType() === NodeType.EntityServer) { - console.warn("DomainServer: EntityServer support implemented!"); + Log.warning("DomainServer: EntityServer support implemented!"); // WEBRTC TODO: Address further code - for EntityServer node. @@ -356,17 +357,17 @@ class DomainServer { // AudioMixer node is handled in AudioMixer.ts. if (nodeType === NodeType.AssetServer) { - console.warn("DomainServer: AssetServer support not implemented!"); + Log.warning("DomainServer: AssetServer support not implemented!"); // WEBRTC TODO: Address further code - for AssetServer node. } else if (nodeType === NodeType.EntityServer) { - console.warn("DomainServer: EntityServer support not implemented!"); + Log.warning("DomainServer: EntityServer support not implemented!"); // WEBRTC TODO: Address further code - for EntityServer node. } else if (nodeType === NodeType.AvatarMixer) { - console.warn("DomainServer: AvatarMixer support not implemented!"); + Log.warning("DomainServer: AvatarMixer support not implemented!"); // WEBRTC TODO: Address further code - for AvatarMixer node. @@ -383,12 +384,12 @@ class DomainServer { // AudioMixer node is handled in AudioMixer.ts. if (nodeType === NodeType.EntityServer) { - console.warn("DomainServer: EntityServer support not implemented!"); + Log.warning("DomainServer: EntityServer support not implemented!"); // WEBRTC TODO: Address further code - for EntityServer node. } else if (nodeType === NodeType.AssetServer) { - console.warn("DomainServer: AssetServer support not implemented!"); + Log.warning("DomainServer: AssetServer support not implemented!"); // WEBRTC TODO: Address further code - for AssetServer node. diff --git a/src/domain/AssignmentClient.ts b/src/domain/AssignmentClient.ts index ef238e27..637b0582 100644 --- a/src/domain/AssignmentClient.ts +++ b/src/domain/AssignmentClient.ts @@ -12,6 +12,7 @@ import Node from "./networking/Node"; import NodeList from "./networking/NodeList"; import { NodeTypeValue } from "./networking/NodeType"; import ContextManager from "./shared/ContextManager"; +import Log from "./shared/Log"; /*@devdoc @@ -152,7 +153,7 @@ class AssignmentClient { if (typeof callback === "function" || callback === null) { this.#_onStateChanged = callback; } else { - console.error("ERROR: AssignmentClient.onStateChanged callback not a function or null!"); + Log.error("AssignmentClient.onStateChanged callback not a function or null!"); this.#_onStateChanged = null; } } diff --git a/src/domain/audio-client/AudioClient.ts b/src/domain/audio-client/AudioClient.ts index 767e2c86..4a20108d 100644 --- a/src/domain/audio-client/AudioClient.ts +++ b/src/domain/audio-client/AudioClient.ts @@ -186,10 +186,10 @@ class AudioClient { ? inputDeviceAudioSettings.echoCancellation : false; } - console.log("[audioclient] Input device info:", inputDeviceAudioSettings + Log.message("Input device info:" + (inputDeviceAudioSettings ? `${deviceName}, ${channelCount} channels, ${sampleRate}Hz, ${sampleSize} bits, ` + `echo cancellation ${echoCancellation ? "on" : "off"}` - : null); + : ""), "audioclient"); let supportedFormat = false; @@ -211,7 +211,7 @@ class AudioClient { // WEBRTC TODO: Address further C++. if (isShutdownRequest) { - console.log("[audioclient] The audio input device has shut down."); + Log.message("The audio input device has shut down.", "audioclient"); return true; } @@ -232,12 +232,12 @@ class AudioClient { this.#_audioInput.readyRead.connect(this.#handleMicAudioInput); supportedFormat = true; } else { - console.error("[audioclient] Error starting audio input -", this.#_audioInput.errorString()); + Log.error(`Error starting audio input - ${this.#_audioInput.errorString()}`, "audioclient"); } } if (!supportedFormat) { - console.log("[audioclient] Audio input device is not available, using dummy input."); + Log.message("Audio input device is not available, using dummy input.", "audioclient"); // WEBRTC TODO: Address further C++. @@ -369,7 +369,8 @@ class AudioClient { this.#_selectedCodecName = selectedCodecName; - console.log("[audioclient] Selected codec:", this.#_selectedCodecName, "; Is stereo input:", this.#_isStereoInput); + Log.message(`Selected codec: ${this.#_selectedCodecName} ; Is stereo input: ${this.#_isStereoInput.toString()}`, + "audioclient"); // WEBRTC TODO: Address further C++ code. @@ -406,7 +407,7 @@ class AudioClient { #processStreamStatsPacket = (message: ReceivedMessage, sendingNode?: Node): void => { // eslint-disable-line // C++ void AudioIOStats::processStreamStatsPacket(ReceivedMessage*, Node* sendingNode) - Log.once(LogLevel.WARNING, "AudioClient: AudioStreamStats packet not processed."); + Log.once(LogLevel.WARNING, "AudioClient: AudioStreamStats packet not processed.", "audioclient"); // WEBRTC TODO: Address further C++ code. @@ -418,7 +419,7 @@ class AudioClient { #handleAudioEnvironmentDataPacket = (message: ReceivedMessage): void => { // eslint-disable-line // C++ void handleAudioEnvironmentDataPacket(ReceivedMessage* message) - Log.once(LogLevel.WARNING, "AudioClient: AudioEnvironment packet not processed."); + Log.once(LogLevel.WARNING, "AudioClient: AudioEnvironment packet not processed.", "audioclient"); // WEBRTC TODO: Address further C++ code. diff --git a/src/domain/audio/AudioInput.ts b/src/domain/audio/AudioInput.ts index de43ebd1..74565f53 100644 --- a/src/domain/audio/AudioInput.ts +++ b/src/domain/audio/AudioInput.ts @@ -11,6 +11,7 @@ import AudioConstants from "../audio/AudioConstants"; import assert from "../shared/assert"; import Signal from "../shared/Signal"; +import Log from "../shared/Log"; // eslint-disable-next-line // @ts-ignore @@ -50,7 +51,7 @@ class AudioInput { set audioInput(audioInput: MediaStream | null) { // C++ N/A if (audioInput && this.#_isStarted) { - console.error("Cannot set the audio input while it is running!"); + Log.error("Cannot set the audio input while it is running!", "audio"); return; } @@ -200,7 +201,7 @@ class AudioInput { } if (frame === undefined) { this.#_errorString = "Unexpected read of empty audio input buffer!"; - console.error(this.#_errorString); + Log.error(this.#_errorString, "audio"); return null; } return frame; @@ -268,7 +269,7 @@ class AudioInput { // Audio worklet. if (!this.#_audioContext.audioWorklet) { this.#_errorString = "Cannot set up audio input stream. App may not be being served via HTTPS or from localhost."; - console.error(this.#_errorString); + Log.error(this.#_errorString, "audio"); return false; } await this.#_audioContext.audioWorklet.addModule(audioInputProcessorURL); diff --git a/src/domain/audio/AudioOutput.ts b/src/domain/audio/AudioOutput.ts index 082674a8..bf1eeead 100644 --- a/src/domain/audio/AudioOutput.ts +++ b/src/domain/audio/AudioOutput.ts @@ -10,6 +10,7 @@ import assert from "../shared/assert"; import AudioConstants from "../audio/AudioConstants"; +import Log from "../shared/Log"; // eslint-disable-next-line // @ts-ignore @@ -159,7 +160,7 @@ class AudioOutput { // Audio worklet. if (!this.#_audioContext.audioWorklet) { - console.error("Cannot set up audio output stream. App may not be being served via HTTPS or from localhost."); + Log.error("Cannot set up audio output stream. App may not be being served via HTTPS or from localhost.", "audio"); return; } await this.#_audioContext.audioWorklet.addModule(audioOutputProcessorURL); diff --git a/src/domain/audio/InboundAudioStream.ts b/src/domain/audio/InboundAudioStream.ts index 94d5a549..b5a64c2a 100644 --- a/src/domain/audio/InboundAudioStream.ts +++ b/src/domain/audio/InboundAudioStream.ts @@ -87,7 +87,7 @@ class InboundAudioStream { } else { // WEBRTC TODO: Address further C++ code. - console.warn("Codec mismatch not handled."); + Log.warning("Codec mismatch not handled.", "audio"); } } @@ -125,7 +125,8 @@ class InboundAudioStream { // C++ int writeDroppableSilentFrames(int silentFrames) // WEBRTC TODO: Address further C++ code. - Log.once(LogLevel.WARNING, `InboundAudioStream.#writeDroppableSilentFrames() not implemented. Frames: ${silentFrames}`); + Log.once(LogLevel.WARNING, `InboundAudioStream.#writeDroppableSilentFrames() not implemented. Frames: ${silentFrames}`, + "audio"); } @@ -137,7 +138,7 @@ class InboundAudioStream { if (this.#_decoder) { // WEBRTC TODO: Address further C++ code. - console.warn("Codec support not implemented.", this.#_selectedCodecName); + Log.once(LogLevel.WARNING, `Codec support not implemented. ${this.#_selectedCodecName}`, "audio"); decodedBuffer = new Int16Array(); } else { diff --git a/src/domain/networking/DomainHandler.ts b/src/domain/networking/DomainHandler.ts index 019b22d5..6b9e743d 100644 --- a/src/domain/networking/DomainHandler.ts +++ b/src/domain/networking/DomainHandler.ts @@ -15,6 +15,7 @@ import Signal from "../shared/Signal"; import Uuid from "../shared/Uuid"; import PacketScribe from "./packets/PacketScribe"; import ReceivedMessage from "./ReceivedMessage"; +import Log from "../shared/Log"; /*@devdoc @@ -253,8 +254,8 @@ class DomainHandler { // WEBRTC TODO: Should C++ clear _domainConnectionRefusals also? this.#_domainConnectionRefusals.clear(); // Re-report any refusals if retry connecting to the same domain. - console.log("[networking] Disconnecting from domain server."); - console.log("[networking] REASON:", reason); + Log.message("Disconnecting from domain server.", "networking"); + Log.message(`REASON: ${reason}`, "networking"); this.setIsConnected(false, forceDisconnect); } @@ -279,7 +280,7 @@ class DomainHandler { */ softReset(reason: string): void { // C++ void softReset(QString reason) { - console.log("[networking] Resetting current domain connection information."); + Log.message("Resetting current domain connection information.", "networking"); this.disconnect(reason); // WEBRTC TODO: Address further C++ code. @@ -298,8 +299,8 @@ class DomainHandler { const info = PacketScribe.DomainConnectionDenied.read(message.getMessage()); const sanitizedExtraInfo = info.extraInfo.toLowerCase().startsWith("http") ? "" : info.extraInfo; - console.warn("[networking] The domain-server denied a connection request: ", info.reasonMessage, "extraInfo:", - sanitizedExtraInfo); + Log.warning(`The domain-server denied a connection request: ${info.reasonMessage} extraInfo: ${sanitizedExtraInfo}`, + "networking"); if (!this.#_domainConnectionRefusals.has(info.reasonMessage)) { this.#_domainConnectionRefusals.add(info.reasonMessage); diff --git a/src/domain/networking/HMACAuth.ts b/src/domain/networking/HMACAuth.ts index 4baf3c60..63e4b341 100644 --- a/src/domain/networking/HMACAuth.ts +++ b/src/domain/networking/HMACAuth.ts @@ -11,6 +11,7 @@ import Uuid from "../shared/Uuid"; import UDT from "./udt/UDT"; import "../shared/DataViewExtensions"; +import Log from "../shared/Log"; import CryptoJS from "crypto-js"; @@ -85,7 +86,7 @@ class HMACAuth { // Vircadia only uses MD5. if (authMethod !== HMACAuth.MD5) { - console.error("HMACAuth method not supported:", authMethod); + Log.error(`HMACAuth method not supported: ${authMethod}`); } this.#_keyWordArray = CryptoJS.lib.WordArray.create([]); diff --git a/src/domain/networking/LimitedNodeList.ts b/src/domain/networking/LimitedNodeList.ts index e5ce3685..5a36efb3 100644 --- a/src/domain/networking/LimitedNodeList.ts +++ b/src/domain/networking/LimitedNodeList.ts @@ -22,6 +22,7 @@ import Socket from "./udt/Socket"; import assert from "../shared/assert"; import Signal from "../shared/Signal"; import Uuid from "../shared/Uuid"; +import Log from "../shared/Log"; type NewNodeInfo = { @@ -179,7 +180,7 @@ class LimitedNodeList { if (packet.isReliable()) { - console.warn("sendPacket() : isReliable : Not implemented!"); + Log.warning("sendPacket() : isReliable : Not implemented!"); // WEBRTC TODO: Address further C++ code. @@ -203,8 +204,8 @@ class LimitedNodeList { return this.sendPacket(packet, activeSocket, destinationNode.getAuthenticateHash()); } - console.log("[networking] LimitedNodeList.sendPacket called without active socket for node", - NodeType.getNodeTypeName(destinationNode.getType()), "- not sending"); + Log.message(`LimitedNodeList.sendPacket called without active socket for node ` + + `${NodeType.getNodeTypeName(destinationNode.getType())} - not sending`, "networking"); return LimitedNodeList.#ERROR_SENDING_PACKET_BYTES; } @@ -213,8 +214,8 @@ class LimitedNodeList { const overridenSockAddr = param2; if (overridenSockAddr.isNull() && !destinationNode.getActiveSocket()) { - console.log("[networking] LimitedNodeList.sendPacket called without active socket for node", - destinationNode.getUUID(), ". Not sending."); + Log.message(`LimitedNodeList.sendPacket called without active socket for node ` + + `${destinationNode.getUUID().stringify()} . Not sending.`, "networking"); return LimitedNodeList.#ERROR_SENDING_PACKET_BYTES; } @@ -228,7 +229,8 @@ class LimitedNodeList { } - console.error("Invalid parameters in LimiteNodeList.sendPacket()!", typeof packet, typeof param1, typeof param2); + Log.error(`Invalid parameters in LimiteNodeList.sendPacket()! ` + + `${typeof packet} ${typeof param1} ${typeof param2}`, "networking"); return LimitedNodeList.#ERROR_SENDING_PACKET_BYTES; } @@ -336,7 +338,7 @@ class LimitedNodeList { // WEBRTC TODO: Address further C++ code. - console.log("[networking] Added", NodeType.getNodeTypeName(newNode.getType())); + Log.message(`Added ${NodeType.getNodeTypeName(newNode.getType())}`, "networking"); // WEBRTC TODO: Address further C++ code. @@ -569,8 +571,8 @@ class LimitedNodeList { // WEBRTC TODO: Address further C++ code. - console.log("[networking] Killed", NodeType.getNodeTypeName(node.getType()), node.getUUID().stringify(), - node.getPublicSocket().toString(), "/", node.getLocalSocket().toString()); + Log.message(`Killed ${NodeType.getNodeTypeName(node.getType())} ${node.getUUID().stringify()} ` + + `${node.getPublicSocket().toString()} / ${node.getLocalSocket().toString()}`, "networking"); // Ping timer N/A. @@ -630,7 +632,7 @@ class LimitedNodeList { const killedNodes = []; if (this.#_nodeHash.size > 0) { - console.log("[networking] Removing all nodes from nodes list:", reason); + Log.message(`Removing all nodes from nodes list: ${reason}`, "networking"); for (const node of this.#_nodeHash.values()) { killedNodes.push(node); } diff --git a/src/domain/networking/NLPacket.ts b/src/domain/networking/NLPacket.ts index 2bd0fc87..fea49d01 100644 --- a/src/domain/networking/NLPacket.ts +++ b/src/domain/networking/NLPacket.ts @@ -15,6 +15,7 @@ import UDT from "./udt/UDT"; import { LocalID } from "../networking/NetworkPeer"; import Node from "../networking/Node"; import assert from "../shared/assert"; +import Log from "../shared/Log"; /*@devdoc @@ -133,8 +134,8 @@ class NLPacket extends Packet { this.adjustPayloadStartAndCapacity(NLPacket.#localHeaderSize(this._messageData.type)); } else { - console.error("Invalid parameters in Packet constructor!", typeof param0, typeof param1, typeof param2, - typeof param3, typeof param4); + Log.error(`Invalid parameters in Packet constructor! ` + + `${typeof param0} ${typeof param1} ${typeof param2} ${typeof param3} ${typeof param4}`, "networking"); super(0, false, false); } } diff --git a/src/domain/networking/NetworkPeer.ts b/src/domain/networking/NetworkPeer.ts index bd36c937..fd149812 100644 --- a/src/domain/networking/NetworkPeer.ts +++ b/src/domain/networking/NetworkPeer.ts @@ -12,6 +12,7 @@ import SockAddr from "./SockAddr"; import Signal from "../shared/Signal"; import Uuid from "../shared/Uuid"; +import Log from "../shared/Log"; type LocalID = number; @@ -124,8 +125,8 @@ class NetworkPeer { this._publicSocket.setObjectName(previousSocket.objectName()); if (!wasOldSocketNull) { - console.log("[networking] Public socket change for node", this.#toString(), - "; previously", previousSocket.toString()); + Log.message(`Public socket change for node", ${this.#toString()}; ` + + `previously ${previousSocket.toString()}`, "networking"); this.socketUpdated.emit(previousSocket, this._publicSocket); } } @@ -160,8 +161,8 @@ class NetworkPeer { this._localSocket.setObjectName(previousSocket.objectName()); if (!wasOldSocketNull) { - console.log("[networking] Local socket change for node", this.#toString(), - "; previously", previousSocket.toString()); + Log.message(`Local socket change for node ${this.#toString()}; ` + + `previously ${previousSocket.toString()}`, "networking"); this.socketUpdated.emit(previousSocket, this._localSocket); } } @@ -173,7 +174,7 @@ class NetworkPeer { activateLocalSocket(): void { // C++ void activateLocalSocket() if (this.#_activeSocket !== this._localSocket) { - console.log("[networking] Activating local socket for network peer with ID", this.#_uuid.stringify()); + Log.message(`Activating local socket for network peer with ID ${this.#_uuid.stringify()}`, "networking"); this.#setActiveSocket(this._localSocket); } } @@ -184,7 +185,7 @@ class NetworkPeer { activatePublicSocket(): void { // C++ void activatePublicSocket() if (this.#_activeSocket !== this._publicSocket) { - console.log("[networking] Activating public socket for network peer with ID", this.#_uuid.stringify()); + Log.message(`Activating public socket for network peer with ID ${this.#_uuid.stringify()}`, "networking"); this.#setActiveSocket(this._publicSocket); } } diff --git a/src/domain/networking/NodeList.ts b/src/domain/networking/NodeList.ts index 5dd15cba..acf11c72 100644 --- a/src/domain/networking/NodeList.ts +++ b/src/domain/networking/NodeList.ts @@ -23,6 +23,7 @@ import Socket from "./udt/Socket"; import assert from "../shared/assert"; import ContextManager from "../shared/ContextManager"; import Uuid from "../shared/Uuid"; +import Log from "../shared/Log"; /*@devdoc @@ -194,7 +195,7 @@ class NodeList extends LimitedNodeList { // C++ void processDomainServerRemovedNode(ReceivedMessage* message) const info = PacketScribe.DomainServerRemovedNode.read(message.getMessage()); const nodeUUID = info.nodeUUID; - console.log("[networking] Received packet from domain-server to remove node with UUID", nodeUUID.stringify()); + Log.message(`Received packet from domain-server to remove node with UUID ${nodeUUID.stringify()}`, "networking"); this.killNodeWithUUID(nodeUUID); // WEBRTC TODO: Address further C++ code. @@ -298,7 +299,7 @@ class NodeList extends LimitedNodeList { // Open a WebRTC data channel to the domain server if not already open. const domainServerSocketState = this._nodeSocket.getSocketState(domainURL, NodeType.DomainServer); if (domainServerSocketState !== Socket.CONNECTED) { - console.log("[networking] Opening domain server connection. Will not send domain server check-in."); + Log.message("Opening domain server connection. Will not send domain server check-in.", "networking"); if (domainServerSocketState === Socket.UNCONNECTED) { this._nodeSocket.openSocket(domainURL, NodeType.DomainServer, (socketID: number) => { this.#_domainHandler.setPort(socketID); @@ -444,7 +445,7 @@ class NodeList extends LimitedNodeList { }); } else { - console.error("Unexpected socket state for", NodeType.getNodeTypeName(node.getType())); + Log.error(`Unexpected socket state for ${NodeType.getNodeTypeName(node.getType())}`, "networking"); } // Vircadia clients can never have upstream nodes or downstream nodes so we don't need to cater for these. diff --git a/src/domain/networking/PacketReceiver.ts b/src/domain/networking/PacketReceiver.ts index 3c869103..60a876f1 100644 --- a/src/domain/networking/PacketReceiver.ts +++ b/src/domain/networking/PacketReceiver.ts @@ -15,6 +15,7 @@ import ReceivedMessage from "./ReceivedMessage"; import Packet from "./udt/Packet"; import { PacketTypeValue } from "./udt/PacketHeaders"; import ContextManager from "../shared/ContextManager"; +import Log from "../shared/Log"; type Listener = (message: ReceivedMessage, sendingNode?: Node) => void; @@ -160,7 +161,7 @@ class PacketReceiver { if (matchingNode) { messageListener.listener(receivedMessage, matchingNode); } else { - console.error("Could not find node for message type:", receivedMessage.getType()); + Log.error(`Could not find node for message type: ${receivedMessage.getType()}`); // WEBRTC TODO: Add string name of packet type to message. } } else { @@ -168,7 +169,7 @@ class PacketReceiver { } } else { - console.error("Could not find listener for message type:", receivedMessage.getType()); + Log.error(`Could not find listener for message type: ${receivedMessage.getType()}`); // WEBRTC TODO: Add string name of packet type to message. // WEBRTC TODO: Address further code. diff --git a/src/domain/networking/udt/BasePacket.ts b/src/domain/networking/udt/BasePacket.ts index 85812f7b..ca630033 100644 --- a/src/domain/networking/udt/BasePacket.ts +++ b/src/domain/networking/udt/BasePacket.ts @@ -12,6 +12,7 @@ import UDT from "./UDT"; import MessageData from "../MessageData"; import SockAddr from "../SockAddr"; import assert from "../../shared/assert"; +import Log from "../../shared/Log"; /*@devdoc @@ -81,7 +82,7 @@ class BasePacket { this._messageData.packetSize = size; this._messageData.senderSockAddr = senderSockAddr; if (data.byteLength !== size) { - console.error("Invalid size parameter in BasePacket constructor!", size); + Log.error(`Invalid size parameter in BasePacket constructor! ${size}`); } } else if (param0 instanceof BasePacket) { @@ -94,7 +95,7 @@ class BasePacket { } else { // Invalid call. this._messageData = new MessageData(); - console.error("Invalid parameters in BasePacket constructor!", typeof param0, typeof param1, typeof param2); + Log.error(`Invalid parameters in BasePacket constructor! ${typeof param0} ${typeof param1} ${typeof param2}`); } } diff --git a/src/domain/networking/udt/Packet.ts b/src/domain/networking/udt/Packet.ts index 1f301ff4..8cc4dd46 100644 --- a/src/domain/networking/udt/Packet.ts +++ b/src/domain/networking/udt/Packet.ts @@ -12,6 +12,7 @@ import BasePacket from "./BasePacket"; import UDT from "./UDT"; import SockAddr from "../SockAddr"; import assert from "../../shared/assert"; +import Log from "../../shared/Log"; /*@devdoc @@ -154,7 +155,7 @@ class Packet extends BasePacket { this.#readHeader(); // adjustPayloadStartAndCapacity(); N/A if (this._messageData.obfuscationLevel !== Packet.ObfuscationLevel.NoObfuscation) { - console.warn("Packet() : Undo obfuscation : Not implemented!"); + Log.warning("Packet() : Undo obfuscation : Not implemented!"); // WEBRTC TODO: Address further C++ code. @@ -168,7 +169,7 @@ class Packet extends BasePacket { this._messageData.dataPosition = Packet.totalHeaderSize(this._messageData.isPartOfMessage); } else { - console.error("Invalid parameters in Packet constructor!", typeof param0, typeof param1, typeof param2); + Log.error(`Invalid parameters in Packet constructor! ${typeof param0} ${typeof param1} ${typeof param2}`); super(0); } } @@ -206,7 +207,7 @@ class Packet extends BasePacket { this._messageData.dataPosition += 4; if (this._messageData.isPartOfMessage) { - console.warn("Multi-packet messages not yet implemented!"); + Log.warning("Multi-packet messages not yet implemented!"); // WEBRTC TODO: Address further C++ code. diff --git a/src/domain/networking/udt/PacketHeaders.ts b/src/domain/networking/udt/PacketHeaders.ts index ce589b52..8f76d76e 100644 --- a/src/domain/networking/udt/PacketHeaders.ts +++ b/src/domain/networking/udt/PacketHeaders.ts @@ -9,6 +9,7 @@ // import assert from "../../shared/assert"; +import Log from "../../shared/Log"; /*@devdoc @@ -518,7 +519,7 @@ const PacketType = new class { // C++ default for remainder of packets is 22 but we want to report packets we haven't implemented, so explicitly // list those packets we know about. default: - console.error("ERROR - Unknown packet type in versionForPacketType() :", packetType); + Log.error(`ERROR - Unknown packet type in versionForPacketType() : ${packetType}`); } return 0; } diff --git a/src/domain/networking/udt/Socket.ts b/src/domain/networking/udt/Socket.ts index 1080a652..a3aa4a1e 100644 --- a/src/domain/networking/udt/Socket.ts +++ b/src/domain/networking/udt/Socket.ts @@ -14,6 +14,7 @@ import { NodeTypeValue } from "../NodeType"; import SockAddr from "../SockAddr"; import { default as WebRTCSocket, WebRTCSocketDatagram } from "../webrtc/WebRTCSocket"; import assert from "../../shared/assert"; +import Log from "../../shared/Log"; /*@devdoc @@ -204,8 +205,9 @@ class Socket { handleRemoteAddressChange = (previousAddress: SockAddr, currentAddress: SockAddr): void => { // C++ void handleRemoteAddressChange(SockAddr previousAddress, SockAddr currentAddress) - console.log("[networking] Remote address changes from", previousAddress.toString(), "to", currentAddress.toString()); - console.warn("handleRemoteAddressChange() : Not implemented!"); + Log.message(`Remote address changes from ${previousAddress.toString()} "to" ${currentAddress.toString()}`, + "networking"); + Log.warning("handleRemoteAddressChange() : Not implemented!", "networking"); // WEBRTC TODO: Address further C++ code. @@ -242,7 +244,7 @@ class Socket { // WEBRTC TODO: Address further C++ code. - console.warn("Control packets not yet implemented!"); + Log.warning("Control packets not yet implemented!", "networking"); } else { @@ -253,7 +255,7 @@ class Socket { // WEBRTC TODO: Address further C++ code. if (packet.isReliable()) { - console.warn("Reliable packets not yet implemented!"); + Log.warning("Reliable packets not yet implemented!", "networking"); // WEBRTC TODO: Address further C++ code. @@ -263,7 +265,7 @@ class Socket { // WEBRTC TODO: Address further C++ code. if (messageData.isPartOfMessage) { - console.warn("Multi-packet messages not yet implemented!"); + Log.warning("Multi-packet messages not yet implemented!", "networking"); // WEBRTC TODO: Address further C++ code. diff --git a/src/domain/networking/webrtc/WebRTCDataChannel.ts b/src/domain/networking/webrtc/WebRTCDataChannel.ts index 2a528b8e..927e3ad6 100644 --- a/src/domain/networking/webrtc/WebRTCDataChannel.ts +++ b/src/domain/networking/webrtc/WebRTCDataChannel.ts @@ -10,6 +10,7 @@ import NodeType, { NodeTypeValue } from "../NodeType"; import WebRTCSignalingChannel, { SignalingMessage } from "./WebRTCSignalingChannel"; +import Log from "../../shared/Log"; type OnOpenCallback = () => void; @@ -176,7 +177,7 @@ class WebRTCDataChannel { // eslint-disable-next-line addEventListener(event: string, callback: OnOpenCallback | OnMessageCallback | OnCloseCallback | OnErrorCallback): void { const errorMessage = "WebRTCDataChannel.addEventListener(): Not implemented!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -197,7 +198,7 @@ class WebRTCDataChannel { } const errorMessage = "WebRTCDataChannel: Data channel not open for sending!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -254,7 +255,7 @@ class WebRTCDataChannel { }); } catch (err) { const errorMessage = "WebRTCDataChannel: Error during offer negotiation: " + err; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -288,7 +289,7 @@ class WebRTCDataChannel { // Unexpected condition. errorMessage = "WebRTCDataChannel: Unexpected connection state: " + (this.#_peerConnection ? this.#_peerConnection.connectionState : "undefined"); - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -338,7 +339,7 @@ class WebRTCDataChannel { if (!this.#_signalingChannel || this.#_signalingChannel.readyState !== WebRTCSignalingChannel.OPEN) { this.#_readyState = WebRTCDataChannel.CLOSED; const errorMessage = "WebRTCDataChannel: Signaling channel not open!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -365,7 +366,7 @@ class WebRTCDataChannel { if (description) { if (!this.#_peerConnection) { const errorMessage = "WebRTCDataChannel: Peer connection is closed!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } @@ -393,14 +394,14 @@ class WebRTCDataChannel { } else { // Unexpected message. const errorMessage = "WebRTCDataChannel: Unexpected signaling channel message!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } } } catch (err) { const errorMessage = "WebRTCDataChannel: Error processing signaling channel message!"; - console.error(errorMessage); + Log.error(errorMessage); if (this.#_onerrorCallback) { this.#_onerrorCallback(errorMessage); } diff --git a/src/domain/networking/webrtc/WebRTCSignalingChannel.ts b/src/domain/networking/webrtc/WebRTCSignalingChannel.ts index 1f486cbb..cc316770 100644 --- a/src/domain/networking/webrtc/WebRTCSignalingChannel.ts +++ b/src/domain/networking/webrtc/WebRTCSignalingChannel.ts @@ -9,6 +9,7 @@ // import { NodeTypeValue } from "../NodeType"; +import Log from "../../shared/Log"; type EventCallback = (event: Event) => void; @@ -124,7 +125,7 @@ class WebRTCSignalingChannel { constructor(websocketURL: string) { if (typeof websocketURL !== "string" || websocketURL === "") { - console.error("WebRTCSignalingChannel: Invalid WebSocket URL!"); + Log.error("WebRTCSignalingChannel: Invalid WebSocket URL!"); } try { this.#_websocket = new WebSocket(websocketURL); @@ -211,7 +212,7 @@ class WebRTCSignalingChannel { return true; } - console.error("WebRTCSignalingChannel: Channel not open for sending!"); + Log.error("WebRTCSignalingChannel: Channel not open for sending!"); if (this.#_websocket && this.#_websocket.onerror) { this.#_websocket.onerror("Channel not open for sending!"); } @@ -243,7 +244,7 @@ class WebRTCSignalingChannel { } } if (!success) { - console.error("WebRTCSignalingChannel: Invalid message received!"); + Log.error("WebRTCSignalingChannel: Invalid message received!"); } } diff --git a/src/domain/worklets/AudioInputProcessor.ts b/src/domain/worklets/AudioInputProcessor.ts index f449bbac..e9df03e9 100644 --- a/src/domain/worklets/AudioInputProcessor.ts +++ b/src/domain/worklets/AudioInputProcessor.ts @@ -8,6 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import Log from "../shared/Log"; /*@devdoc * The AudioInputProcessor class implements a Web Audio @@ -75,7 +76,7 @@ class AudioInputProcessor extends AudioWorkletProcessor { // @ts-ignore process(inputList: Float32Array[][] /* , outputList: Float32Array[][], parameters: Record */) { if (!inputList || !inputList[0] || !inputList[0][0] || this._channelCount === 2 && !inputList[0][1]) { - console.log("Early return!"); + Log.message("Early return!", "audioworklet"); return true; } From 53ba810ec61f3d46e7a376db13a9b20153c45b83 Mon Sep 17 00:00:00 2001 From: namark Date: Sat, 6 Nov 2021 02:50:21 +0400 Subject: [PATCH 7/8] Fixed new linting errors in logger code. --- src/domain/shared/Log.ts | 34 +++++++++++++++++++++++----- tests/domain/shared/Log.unit.test.ts | 16 +++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/domain/shared/Log.ts b/src/domain/shared/Log.ts index ef7a3c50..242d396a 100644 --- a/src/domain/shared/Log.ts +++ b/src/domain/shared/Log.ts @@ -57,11 +57,31 @@ export class ConsoleLoggerContext implements LoggerContext { // hence the no-op looking lambda wrappers static #_functions = new Map([ /* eslint-disable @typescript-eslint/no-explicit-any */ - [LogLevel.DEFAULT, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.log(...params))], - [LogLevel.DEBUG, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.debug(...params))], - [LogLevel.INFO, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.info(...params))], - [LogLevel.WARNING, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.warn(...params))], - [LogLevel.ERROR, ConsoleLoggerContext.#_typeFirst((...params: any[]) => console.error(...params))] + [ + LogLevel.DEFAULT, ConsoleLoggerContext.#_typeFirst((...params: any[]) => { + return console.log(...params); + }) + ], + [ + LogLevel.DEBUG, ConsoleLoggerContext.#_typeFirst((...params: any[]) => { + return console.debug(...params); + }) + ], + [ + LogLevel.INFO, ConsoleLoggerContext.#_typeFirst((...params: any[]) => { + return console.info(...params); + }) + ], + [ + LogLevel.WARNING, ConsoleLoggerContext.#_typeFirst((...params: any[]) => { + return console.warn(...params); + }) + ], + [ + LogLevel.ERROR, ConsoleLoggerContext.#_typeFirst((...params: any[]) => { + return console.error(...params); + }) + ] /* eslint-enable @typescript-eslint/no-explicit-any */ ]); @@ -119,7 +139,9 @@ export class Logger { */ constructor(context: LoggerContext) { this.#_context = context; - this.filterLevels(() => true); + this.filterLevels(() => { + return true; + }); } /*@devdoc diff --git a/tests/domain/shared/Log.unit.test.ts b/tests/domain/shared/Log.unit.test.ts index f4196b2e..2b4dbb75 100644 --- a/tests/domain/shared/Log.unit.test.ts +++ b/tests/domain/shared/Log.unit.test.ts @@ -98,7 +98,9 @@ describe("Logger - unit tests", () => { const context = new StringLoggerContext(); const logger = new Logger(context); - logger.filterLevels((level) => level >= LogLevel.INFO); + logger.filterLevels((level) => { + return level >= LogLevel.INFO; + }); logger.debug("Debug message"); logger.message("Default message"); @@ -113,7 +115,9 @@ describe("Logger - unit tests", () => { ); context.buffer = ""; - logger.filterLevels((level) => level <= LogLevel.DEFAULT); + logger.filterLevels((level) => { + return level <= LogLevel.DEFAULT; + }); logger.debug("Debug message"); logger.message("Default message"); @@ -127,7 +131,9 @@ describe("Logger - unit tests", () => { ); context.buffer = ""; - logger.filterLevels((level) => [LogLevel.DEBUG, LogLevel.ERROR].includes(level)); + logger.filterLevels((level) => { + return [LogLevel.DEBUG, LogLevel.ERROR].includes(level); + }); logger.debug("Debug message"); logger.message("Default message"); @@ -216,7 +222,9 @@ describe("Logger - unit tests", () => { const context = new StringLoggerContext(); const logger = new Logger(context); - logger.filterLevels((level) => level <= LogLevel.DEFAULT); + logger.filterLevels((level) => { + return level <= LogLevel.DEFAULT; + }); logger.setTypeFilter(["Type 2"]); logger.message("message"); From d6638e2e6dd1186e9ad166ec7a6b5854f2c8d894 Mon Sep 17 00:00:00 2001 From: namark Date: Sat, 6 Nov 2021 03:27:07 +0400 Subject: [PATCH 8/8] More console logs adapted to use centralized logger. --- src/MessageMixer.ts | 9 ++++---- src/domain/networking/LimitedNodeList.ts | 18 ++++++++-------- src/domain/networking/NLPacketList.ts | 21 +++++++++++-------- src/domain/networking/udt/Connection.ts | 17 ++++++++------- src/domain/networking/udt/ControlPacket.ts | 3 ++- .../networking/udt/PendingReceivedMessage.ts | 3 ++- src/domain/networking/udt/SendQueue.ts | 21 ++++++++++--------- 7 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/MessageMixer.ts b/src/MessageMixer.ts index 71c18f4f..1eda83df 100644 --- a/src/MessageMixer.ts +++ b/src/MessageMixer.ts @@ -14,6 +14,7 @@ import AssignmentClient from "./domain/AssignmentClient"; import MessagesClient from "./domain/networking/MessagesClient"; import NodeType from "./domain/networking/NodeType"; import { Signal } from "./domain/shared/SignalEmitter"; +import Log from "./domain/shared/Log"; /*@sdkdoc @@ -97,7 +98,7 @@ class MessageMixer extends AssignmentClient { */ subscribe(channel: string): void { if (typeof channel !== "string" || channel.length === 0) { - console.error("[MessageMixer] subscribe() called with invalid channel value!"); + Log.error("subscribe() called with invalid channel value!", "MessageMixer"); return; } @@ -111,7 +112,7 @@ class MessageMixer extends AssignmentClient { */ unsubscribe(channel: string): void { if (typeof channel !== "string" || channel.length === 0) { - console.error("[MessageMixer] unsubscribe() called with invalid channel value!"); + Log.error("unsubscribe() called with invalid channel value!", "MessageMixer"); return; } @@ -133,7 +134,7 @@ class MessageMixer extends AssignmentClient { // @ts-ignore sendMessage(channel: string, message: string, localOnly = false): void { // eslint-disable-line if (typeof channel !== "string" || typeof message !== "string" || typeof localOnly !== "boolean") { - console.error("[MessageMixer] sendMessage() called with invalid channel parameters!"); + Log.error("sendMessage() called with invalid channel parameters!", "MessageMixer"); return; } @@ -156,7 +157,7 @@ class MessageMixer extends AssignmentClient { // @ts-ignore sendData(channel: string, data: ArrayBuffer, localOnly = false): void { // eslint-disable-line if (typeof channel !== "string" || !(data instanceof ArrayBuffer) || typeof localOnly !== "boolean") { - console.error("[MessageMixer] sendData() called with invalid channel parameters!"); + Log.error("sendData() called with invalid channel parameters!", "MessageMixer"); return; } diff --git a/src/domain/networking/LimitedNodeList.ts b/src/domain/networking/LimitedNodeList.ts index 2d845f5e..9edc23e7 100644 --- a/src/domain/networking/LimitedNodeList.ts +++ b/src/domain/networking/LimitedNodeList.ts @@ -502,7 +502,7 @@ class LimitedNodeList { this.#_sessionUUID = sessionUUID; if (sessionUUID.value() !== oldUUID.value()) { - console.log("[networking] NodeList UUID changed from", oldUUID.stringify(), "to", sessionUUID.stringify()); + Log.message(`[networking] NodeList UUID changed from ${oldUUID.stringify()} to ${sessionUUID.stringify()}`); this.#_uuidChanged.emit(sessionUUID, oldUUID); } } @@ -570,8 +570,8 @@ class LimitedNodeList { return this._nodeSocket.writePacketList(packetList, activeSocket); } - console.log(`[networking] LimitedNodeList.sendPacketList called without active socket for node - ${destinationNode.getUUID().stringify()}. Not sending.`); + Log.message(`LimitedNodeList.sendPacketList called without active socket for node + ${destinationNode.getUUID().stringify()}. Not sending.`, "networking"); return LimitedNodeList.#ERROR_SENDING_PACKET_BYTES; } @@ -830,8 +830,8 @@ class LimitedNodeList { } if (!hasBeenOutput) { - console.log("[networking] Packet version mismatch on", headerType, "- Sender", senderString, "sent", - headerVersion, "but", PacketType.versionForPacketType(headerType), "expected."); + Log.message(`Packet version mismatch on ${headerType} - Sender ${senderString}, sent ` + + `${headerVersion} but ${PacketType.versionForPacketType(headerType)} expected.`, "networking"); this.#_packetVersionMismatch.emit(headerType, senderSockAddr, sourceID); } @@ -870,8 +870,8 @@ class LimitedNodeList { if (sendingNodeType !== NodeType.Unassigned) { return true; } - console.log("[networking] Replicated packet of type", headerType, "received from unknown upstream", - senderSockAddr?.toString()); + Log.message(`Replicated packet of type ${headerType} received from unknown upstream ` + + (senderSockAddr ? senderSockAddr.toString() : ""), "networking"); return false; } @@ -908,8 +908,8 @@ class LimitedNodeList { } if (!this.#isDelayedNode(sourceID)) { - console.log("[networking] Packet of type", headerType, "received from unknown node with Local ID", - sourceLocalID); + Log.message(` Packet of type ${headerType} received from unknown node with Local ID ` + + sourceLocalID.toString(), "networking"); } return false; diff --git a/src/domain/networking/NLPacketList.ts b/src/domain/networking/NLPacketList.ts index 5fb76bf1..e574c6b9 100644 --- a/src/domain/networking/NLPacketList.ts +++ b/src/domain/networking/NLPacketList.ts @@ -14,6 +14,7 @@ import { PacketTypeValue } from "./udt/PacketHeaders"; import UDT from "./udt/UDT"; import assert from "../shared/assert"; import Uuid from "../shared/Uuid"; +import Log from "../shared/Log"; /*@devdoc @@ -96,7 +97,7 @@ class NLPacketList { assert(!(!isReliable && isOrdered), "PacketList: Unreliable ordered PacketLists are not supported."); if (this.#_extendedHeader !== null) { - console.error("PacketList extended header not implemented."); + Log.error("PacketList extended header not implemented."); } } @@ -138,10 +139,10 @@ class NLPacketList { this.#_uuidData.setBigUint128(0, value.value(), UDT.BIG_ENDIAN); return this.#writeData(this.#_uuidArray, this.#UUID_LENGTH); } - console.error("NLPacketList.writePrimitive() - Unhandled type:", typeof value); + Log.error(`NLPacketList.writePrimitive() - Unhandled type: ${typeof value}`); return 0; default: - console.error("NLPacketList.writePrimitive() - Unhandled type:", typeof value); + Log.error(`NLPacketList.writePrimitive() - Unhandled type: ${typeof value}`); return 0; } } @@ -273,8 +274,8 @@ class NLPacketList { messageData.buffer.set(new Uint8Array(this.#_extendedHeader), messageData.dataPosition); messageData.dataPosition += this.#_extendedHeader.byteLength; } else { - console.log("[networking] Could not write extendedHeader in NLPacketList.createPacketWithExtendedHeader", - "- make sure the extendedHeader is not larger than the payload capacity."); + Log.message("Could not write extendedHeader in NLPacketList.createPacketWithExtendedHeader" + + "- make sure the extendedHeader is not larger than the payload capacity.", "networking"); } } @@ -320,8 +321,9 @@ class NLPacketList { if (segmentSize + sizeRemaining > messageData.buffer.byteLength - messageData.dataPosition) { // This is an unsupported case - the segment is bigger than the size of an individual packet // but the PacketList is not going to be sent ordered. - console.error("[networking] Error in PacketList.writeData()", - "Attempted to write a segment to an unordered packet that is larger than the payload size."); + Log.error("Error in PacketList.writeData() " + + "Attempted to write a segment to an unordered packet that is larger than the payload size.", + "networking"); // We won't be writing this new data to the packet. // Go back before the current segment and return -1 to indicate error. @@ -342,8 +344,9 @@ class NLPacketList { if (sizeRemaining > newMessageData.buffer.byteLength - newMessageData.dataPosition) { // This is an unsupported case - attempting to write a block of data larger than the capacity of a new // packet in an unordered PacketList. - console.error("[networking] Error in PacketList.writeData()", - "Attempted to write data to an unordered packet that is larger than the payload size."); + Log.error("Error in PacketList.writeData() " + + "Attempted to write data to an unordered packet that is larger than the payload size.", + "networking"); return NLPacketList.#PACKET_LIST_WRITE_ERROR; } diff --git a/src/domain/networking/udt/Connection.ts b/src/domain/networking/udt/Connection.ts index cd6a4a85..cbf95a45 100644 --- a/src/domain/networking/udt/Connection.ts +++ b/src/domain/networking/udt/Connection.ts @@ -20,6 +20,7 @@ import NLPacketList from "../NLPacketList"; import SockAddr from "../SockAddr"; import assert from "../../shared/assert"; import SignalEmitter, { Signal } from "../../shared/SignalEmitter"; +import Log from "../../shared/Log"; /*@devdoc @@ -141,7 +142,7 @@ class Connection { // Refuse to process any packets until we've received the handshake. // Send handshake request to re-request a handshake. if (Socket.UDT_CONNECTION_DEBUG) { - console.log("[networking] Received packet before receiving handshake, sending HandshakeRequest."); + Log.message("Received packet before receiving handshake, sending HandshakeRequest.", "networking"); } this.#sendHandshakeRequest(); return false; @@ -203,14 +204,14 @@ class Connection { // We're already in a state where we've received a handshake ACK, so we are likely in a state where the // other end expired our connection. Let's reset. - console.log("[networking] Got HandshakeRequest from", this.#_destination.toString(), - "while active. Stopping SendQueue"); + Log.message(`Got HandshakeRequest from ${this.#_destination.toString()}` + + "while active. Stopping SendQueue", "networking"); this.#_hasReceivedHandshakeACK = false; this.#stopSendQueue(); } break; default: - console.error("[networking] Invalid control packet type!"); + Log.error("Invalid control packet type!", "networking"); } } @@ -265,7 +266,7 @@ class Connection { this.#stopSendQueue(); if (Socket.UDT_CONNECTION_DEBUG) { - console.log("[networking] Connection to", this.#_destination.toString(), "has stopped its SendQueue."); + Log.message(`Connection to ${this.#_destination.toString()} has stopped its SendQueue.`, "networking"); } }; @@ -333,7 +334,7 @@ class Connection { // Validate that this isn't a BS ACK. if (ack.isGreaterThan(this.#getSendQueue().getCurrentSequenceNumber())) { // In UDT they specifically break the connection here - do we want to do anything? - console.error("[networking] Connection.processACK()", "ACK received higher than largest sent sequence number."); + Log.error("Connection.processACK() ACK received higher than largest sent sequence number.", "networking"); return; } @@ -384,7 +385,7 @@ class Connection { if (Socket.UDT_CONNECTION_DEBUG) { if (initialSequenceNumber.isNotEqualTo(this.#_initialReceiveSequenceNumber)) { - console.log("[networking] Resetting receive state, received a new initial sequence number in handshake."); + Log.message("Resetting receive state, received a new initial sequence number in handshake.", "networking"); } } @@ -463,7 +464,7 @@ class Connection { } if (Socket.UDT_CONNECTION_DEBUG) { - console.log("[networking] Created SendQueue for connection to", this.#_destination.toString()); + Log.message(`Created SendQueue for connection to ${this.#_destination.toString()}`, "networking"); } // WEBRTC TODO: Address further C++ code. - Stats and congestion control. diff --git a/src/domain/networking/udt/ControlPacket.ts b/src/domain/networking/udt/ControlPacket.ts index 34cf7db5..0960e452 100644 --- a/src/domain/networking/udt/ControlPacket.ts +++ b/src/domain/networking/udt/ControlPacket.ts @@ -13,6 +13,7 @@ import SequenceNumber from "./SequenceNumber"; import UDT from "./UDT"; import SockAddr from "../../networking/SockAddr"; import assert from "../../shared/assert"; +import Log from "../../shared/Log"; enum ControlPacketType { ACK, @@ -177,7 +178,7 @@ class ControlPacket extends BasePacket { this.#_type = other.getType(); } else { - console.error("Invalid parameters in ControlPacket constructor!", typeof param0, typeof param1, typeof param2); + Log.error(`Invalid parameters in ControlPacket constructor! ${typeof param0} ${typeof param1} ${typeof param2}`); super(0); } } diff --git a/src/domain/networking/udt/PendingReceivedMessage.ts b/src/domain/networking/udt/PendingReceivedMessage.ts index 36a36fe1..226a5f9c 100644 --- a/src/domain/networking/udt/PendingReceivedMessage.ts +++ b/src/domain/networking/udt/PendingReceivedMessage.ts @@ -10,6 +10,7 @@ import Packet from "./Packet"; import assert from "../../shared/assert"; +import Log from "../../shared/Log"; /*@devdoc @@ -45,7 +46,7 @@ class PendingReceivedMessage { index += 1; if (index < this.#_packets.length && this.#_packets[index]!.getMessagePartNumber() === messagePartNumber) { - console.log("[networking] PendingReceivedMessage.enqueuePacket(): Duplicate packet."); + Log.message("PendingReceivedMessage.enqueuePacket(): Duplicate packet.", "networking"); return; } diff --git a/src/domain/networking/udt/SendQueue.ts b/src/domain/networking/udt/SendQueue.ts index 1bbdda27..7e763b98 100644 --- a/src/domain/networking/udt/SendQueue.ts +++ b/src/domain/networking/udt/SendQueue.ts @@ -20,6 +20,7 @@ import assert from "../../shared/assert"; import ConditionVariable from "../../shared/ConditionVariable"; import HighResolutionClock from "../../shared/HighResolutionClock"; import SignalEmitter, { Signal } from "../../shared/SignalEmitter"; +import Log from "../../shared/Log"; type PacketResendPair = { first: number, second: Packet }; // Number of resends for a packet. @@ -383,7 +384,7 @@ class SendQueue { debugString += `\n Message Number: ${messageData.messageNumber} `; debugString += `Part Number: ${messageData.messagePartNumber}.`; } - console.log(debugString); + Log.message(debugString); } // Create copy of the packet @@ -491,9 +492,9 @@ class SendQueue { if (!notified && (this.#_packets.isEmpty() || this.#isFlowWindowFull()) && this.#_naks.isEmpty()) { if (Socket.UDT_CONNECTION_DEBUG) { const S_TO_MS = 1000; - console.log("[networking] SendQueue to", this.#_destination.toString(), "has been empty for", - EMPTY_QUEUES_INACTIVE_TIMEOUT_MS / S_TO_MS, "seconds and receiver has ACKed all packets.", - "The queue is now inactive and will be stopped."); + Log.message(`SendQueue to ${this.#_destination.toString()} has been empty for ` + + `${EMPTY_QUEUES_INACTIVE_TIMEOUT_MS / S_TO_MS} seconds and receiver has ACKed all packets.` + + "The queue is now inactive and will be stopped.", "networking"); } // Deactivate the queue. @@ -582,14 +583,14 @@ class SendQueue { if (this.#_state === SendQueue.#State.Stopped) { // We've already been asked to stop before we even got a chance to start; don't start now. if (Socket.UDT_CONNECTION_DEBUG) { - console.log("[networking] SendQueue asked to run after being told to stop. Will not run."); + Log.message("SendQueue asked to run after being told to stop. Will not run.", "networking"); } return; } if (this.#_state === SendQueue.#State.Running) { // We're already running; don't start another run. if (Socket.UDT_CONNECTION_DEBUG) { - console.log("[networking] SendQueue asked to run but is already running. Will not re-run."); + Log.message("SendQueue asked to run but is already running. Will not re-run.", "networking"); } return; } @@ -658,10 +659,10 @@ class SendQueue { const MAX_SEND_QUEUE_SLEEP_USECS = 2000000n; if (timeToSleep > MAX_SEND_QUEUE_SLEEP_USECS) { - console.warn("SendQueue wanted to sleep for", timeToSleep, "microseconds"); - console.warn("Capping sleep to", MAX_SEND_QUEUE_SLEEP_USECS); - console.warn("PSP:", this.#_packetSendPeriod, "NPD:", nextPacketDelta, "NPT:", nextPacketTimestamp, - "NOW:", now); + Log.warning(`SendQueue wanted to sleep for ${timeToSleep} microseconds`); + Log.warning(`Capping sleep to ${MAX_SEND_QUEUE_SLEEP_USECS}`); + Log.warning(`PSP: ${this.#_packetSendPeriod} NPD: ${nextPacketDelta} NPT: ${nextPacketTimestamp} ` + + `NOW: ${now}`); // WEBRTC TODO: Address further C++ code. - UserActivityLogger.