summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/middleware
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webconsole/middleware')
-rw-r--r--devtools/client/webconsole/middleware/event-telemetry.js129
-rw-r--r--devtools/client/webconsole/middleware/history-persistence.js71
-rw-r--r--devtools/client/webconsole/middleware/moz.build10
-rw-r--r--devtools/client/webconsole/middleware/performance-marker.js27
4 files changed, 237 insertions, 0 deletions
diff --git a/devtools/client/webconsole/middleware/event-telemetry.js b/devtools/client/webconsole/middleware/event-telemetry.js
new file mode 100644
index 0000000000..bf5b203af6
--- /dev/null
+++ b/devtools/client/webconsole/middleware/event-telemetry.js
@@ -0,0 +1,129 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+ FILTER_TEXT_SET,
+ FILTER_TOGGLE,
+ DEFAULT_FILTERS_RESET,
+ EVALUATE_EXPRESSION,
+ MESSAGES_ADD,
+ PERSIST_TOGGLE,
+ REVERSE_SEARCH_INPUT_TOGGLE,
+ REVERSE_SEARCH_NEXT,
+ REVERSE_SEARCH_BACK,
+} = require("resource://devtools/client/webconsole/constants.js");
+
+/**
+ * Event telemetry middleware is responsible for logging specific events to telemetry.
+ */
+function eventTelemetryMiddleware(telemetry, store) {
+ return next => action => {
+ const oldState = store.getState();
+ const res = next(action);
+
+ const state = store.getState();
+
+ const filterChangeActions = [
+ FILTER_TEXT_SET,
+ FILTER_TOGGLE,
+ DEFAULT_FILTERS_RESET,
+ ];
+
+ if (filterChangeActions.includes(action.type)) {
+ filterChange({
+ action,
+ state,
+ oldState,
+ telemetry,
+ });
+ } else if (action.type === MESSAGES_ADD) {
+ messagesAdd({ action, telemetry });
+ } else if (action.type === PERSIST_TOGGLE) {
+ telemetry.recordEvent(
+ "persist_changed",
+ "webconsole",
+ String(state.ui.persistLogs)
+ );
+ } else if (action.type === EVALUATE_EXPRESSION) {
+ // Send telemetry event. If we are in the browser toolbox we send -1 as the
+ // toolbox session id.
+
+ telemetry.recordEvent("execute_js", "webconsole", null, {
+ lines: action.expression.split(/\n/).length,
+ input: state.ui.editor ? "multiline" : "inline",
+ });
+
+ if (action.from === "reverse-search") {
+ telemetry.recordEvent("reverse_search", "webconsole", null, {
+ functionality: "evaluate expression",
+ });
+ }
+ } else if (
+ action.type === REVERSE_SEARCH_INPUT_TOGGLE &&
+ state.ui.reverseSearchInputVisible
+ ) {
+ telemetry.recordEvent("reverse_search", "webconsole", action.access, {
+ functionality: "open",
+ });
+ } else if (action.type === REVERSE_SEARCH_NEXT) {
+ telemetry.recordEvent("reverse_search", "webconsole", action.access, {
+ functionality: "navigate next",
+ });
+ } else if (action.type === REVERSE_SEARCH_BACK) {
+ telemetry.recordEvent("reverse_search", "webconsole", action.access, {
+ functionality: "navigate previous",
+ });
+ }
+
+ return res;
+ };
+}
+
+function filterChange({ action, state, oldState, telemetry }) {
+ const oldFilterState = oldState.filters;
+ const filterState = state.filters;
+ const activeFilters = [];
+ const inactiveFilters = [];
+ for (const [key, value] of Object.entries(filterState)) {
+ if (value) {
+ activeFilters.push(key);
+ } else {
+ inactiveFilters.push(key);
+ }
+ }
+
+ let trigger;
+ if (action.type === FILTER_TOGGLE) {
+ trigger = action.filter;
+ } else if (action.type === DEFAULT_FILTERS_RESET) {
+ trigger = "reset";
+ } else if (action.type === FILTER_TEXT_SET) {
+ if (oldFilterState.text !== "" && filterState.text !== "") {
+ return;
+ }
+
+ trigger = "text";
+ }
+
+ telemetry.recordEvent("filters_changed", "webconsole", null, {
+ trigger,
+ active: activeFilters.join(","),
+ inactive: inactiveFilters.join(","),
+ });
+}
+
+function messagesAdd({ action, telemetry }) {
+ const { messages } = action;
+ for (const message of messages) {
+ if (message.level === "error" && message.source === "javascript") {
+ telemetry
+ .getKeyedHistogramById("DEVTOOLS_JAVASCRIPT_ERROR_DISPLAYED")
+ .add(message.errorMessageName || "Unknown", true);
+ }
+ }
+}
+
+module.exports = eventTelemetryMiddleware;
diff --git a/devtools/client/webconsole/middleware/history-persistence.js b/devtools/client/webconsole/middleware/history-persistence.js
new file mode 100644
index 0000000000..b6b6ca9f7c
--- /dev/null
+++ b/devtools/client/webconsole/middleware/history-persistence.js
@@ -0,0 +1,71 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+ APPEND_TO_HISTORY,
+ CLEAR_HISTORY,
+ EVALUATE_EXPRESSION,
+} = require("resource://devtools/client/webconsole/constants.js");
+
+const historyActions = require("resource://devtools/client/webconsole/actions/history.js");
+
+loader.lazyRequireGetter(
+ this,
+ "asyncStorage",
+ "resource://devtools/shared/async-storage.js"
+);
+
+/**
+ * History persistence middleware is responsible for loading
+ * and maintaining history of executed expressions in JSTerm.
+ */
+function historyPersistenceMiddleware(webConsoleUI, store) {
+ let historyLoaded = false;
+ asyncStorage.getItem("webConsoleHistory").then(
+ value => {
+ if (Array.isArray(value)) {
+ store.dispatch(historyActions.historyLoaded(value));
+ }
+ historyLoaded = true;
+ },
+ err => {
+ historyLoaded = true;
+ console.error(err);
+ }
+ );
+
+ return next => action => {
+ const res = next(action);
+
+ const triggerStoreActions = [
+ APPEND_TO_HISTORY,
+ CLEAR_HISTORY,
+ EVALUATE_EXPRESSION,
+ ];
+
+ // Save the current history entries when modified, but wait till
+ // entries from the previous session are loaded.
+ const { isPrivate } =
+ webConsoleUI.hud?.commands?.targetCommand?.targetFront?.targetForm || {};
+
+ if (
+ !isPrivate &&
+ historyLoaded &&
+ triggerStoreActions.includes(action.type)
+ ) {
+ const state = store.getState();
+ asyncStorage
+ .setItem("webConsoleHistory", state.history.entries)
+ .catch(e => {
+ console.error("Error when saving WebConsole input history", e);
+ });
+ }
+
+ return res;
+ };
+}
+
+module.exports = historyPersistenceMiddleware;
diff --git a/devtools/client/webconsole/middleware/moz.build b/devtools/client/webconsole/middleware/moz.build
new file mode 100644
index 0000000000..ecb2088ca4
--- /dev/null
+++ b/devtools/client/webconsole/middleware/moz.build
@@ -0,0 +1,10 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DevToolsModules(
+ "event-telemetry.js",
+ "history-persistence.js",
+ "performance-marker.js",
+)
diff --git a/devtools/client/webconsole/middleware/performance-marker.js b/devtools/client/webconsole/middleware/performance-marker.js
new file mode 100644
index 0000000000..93fcee279c
--- /dev/null
+++ b/devtools/client/webconsole/middleware/performance-marker.js
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+ MESSAGES_ADD,
+} = require("resource://devtools/client/webconsole/constants.js");
+
+const {
+ createPerformanceMarkerMiddleware,
+} = require("resource://devtools/client/shared/redux/middleware/performance-marker.js");
+
+module.exports = function (sessionId) {
+ return createPerformanceMarkerMiddleware({
+ [MESSAGES_ADD]: {
+ label: "WebconsoleAddMessages",
+ sessionId,
+ getMarkerDescription({ action, state }) {
+ const { messages } = action;
+ const totalMessageCount = state.messages.mutableMessagesById.size;
+ return `${messages.length} messages handled, store now has ${totalMessageCount} messages`;
+ },
+ },
+ });
+};