// `arguments` cannot be used as variable name in functions arguments: messageArguments, // `level` corresponds to the console method used level: method, stacktrace, timeStamp, } = data; // Step numbers below refer to the specifications at // https://w3c.github.io/webdriver-bidi/#event-log-entryAdded // Translate the console message method to a log.LogEntry level const logEntrylevel = this.#getLogEntryLevelFromConsoleMethod(method); // Use the message's timeStamp or fallback on the current time value. const timestamp = timeStamp || Date.now(); // Start assembling the text representation of the message. let text = ""; // Formatters have already been applied at this points. // message.arguments corresponds to the "formatted args" from the // specifications. // Concatenate all formatted arguments in text // TODO: For m1 we only support string arguments, so we rely on the builtin // toString for each argument which will be available in message.arguments. const args = messageArguments || []; text += args.map(String).join(" "); const defaultRealm = this.messageHandler.getRealm(); const serializedArgs = []; const seenNodeIds = new Map(); // Serialize each arg as remote value. for (const arg of args) { // Note that we can pass a default realm for now since realms are only // involved when creating object references, which will not happen with // OwnershipModel.None. This will be revisited in Bug 1742589. serializedArgs.push( this.serialize( Cu.waiveXrays(arg), lazy.setDefaultSerializationOptions(), lazy.OwnershipModel.None, defaultRealm, { seenNodeIds } ) ); } // Set source to an object which contains realm and browsing context. // TODO: Bug 1742589. Use an actual realm from which the event came from. const source = this.#buildSource(defaultRealm); // Set stack trace only for certain methods. let stackTrace; if (["assert", "error", "trace", "warn"].includes(method)) { stackTrace = this.#buildStackTrace(stacktrace); } // Build the ConsoleLogEntry const entry = { type: "console", method, source, args: serializedArgs, level: logEntrylevel, text, timestamp, stackTrace, _extraData: { seenNodeIds }, }; // TODO: Those steps relate to: // - emitting associated BrowsingContext. See log.entryAdded full support // in https://bugzilla.mozilla.org/show_bug.cgi?id=1724669#c0 // - handling cases where session doesn't exist or the event is not // monitored. The implementation differs from the spec here because we // only react to events if there is a session & if the session subscribed // to those events. this.emitEvent("log.entryAdded", entry); }; #onJavaScriptError = (eventName, data = {}) => { const { level, message, stacktrace, timeStamp } = data; const defaultRealm = this.messageHandler.getRealm(); // Build the JavascriptLogEntry const entry = { type: "javascript", level, // TODO: Bug 1742589. Use an actual realm from which the event came from. source: this.#buildSource(defaultRealm), text: message, timestamp: timeStamp || Date.now(), stackTrace: this.#buildStackTrace(stacktrace), }; this.emitEvent("log.entryAdded", entry); }; #subscribeEvent(event) { if (event === "log.entryAdded") { this.#consoleAPIListener.startListening(); this.#consoleMessageListener.startListening(); this.#subscribedEvents.add(event); } } #unsubscribeEvent(event) { if (event === "log.entryAdded") { this.#consoleAPIListener.stopListening(); this.#consoleMessageListener.stopListening(); this.#subscribedEvents.delete(event); } } /** * Internal commands */ _applySessionData(params) { // TODO: Bug 1775231. Move this logic to a shared module or an abstract // class. const { category } = params; if (category === "event") { const filteredSessionData = params.sessionData.filter(item => this.messageHandler.matchesContext(item.contextDescriptor) ); for (const event of this.#subscribedEvents.values()) { const hasSessionItem = filteredSessionData.some( item => item.value === event ); // If there are no session items for this context, we should unsubscribe from the event. if (!hasSessionItem) { this.#unsubscribeEvent(event); } } // Subscribe to all events, which have an item in SessionData. for (const { value } of filteredSessionData) { this.#subscribeEvent(value); } } } } export const log = LogModule; PK