event-telemetry.js (3662B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 FILTER_TEXT_SET, 9 FILTER_TOGGLE, 10 DEFAULT_FILTERS_RESET, 11 EVALUATE_EXPRESSION, 12 MESSAGES_ADD, 13 PERSIST_TOGGLE, 14 REVERSE_SEARCH_INPUT_TOGGLE, 15 REVERSE_SEARCH_NEXT, 16 REVERSE_SEARCH_BACK, 17 } = require("resource://devtools/client/webconsole/constants.js"); 18 19 /** 20 * Event telemetry middleware is responsible for logging specific events to telemetry. 21 */ 22 function eventTelemetryMiddleware(telemetry, store) { 23 return next => action => { 24 const oldState = store.getState(); 25 const res = next(action); 26 27 const state = store.getState(); 28 29 const filterChangeActions = [ 30 FILTER_TEXT_SET, 31 FILTER_TOGGLE, 32 DEFAULT_FILTERS_RESET, 33 ]; 34 35 if (filterChangeActions.includes(action.type)) { 36 filterChange({ 37 action, 38 state, 39 oldState, 40 telemetry, 41 }); 42 } else if (action.type === MESSAGES_ADD) { 43 messagesAdd({ action }); 44 } else if (action.type === PERSIST_TOGGLE) { 45 telemetry.recordEvent( 46 "persist_changed", 47 "webconsole", 48 String(state.ui.persistLogs) 49 ); 50 } else if (action.type === EVALUATE_EXPRESSION) { 51 // Send telemetry event. If we are in the browser toolbox we send -1 as the 52 // toolbox session id. 53 54 telemetry.recordEvent("execute_js", "webconsole", null, { 55 lines: action.expression.split(/\n/).length, 56 input: state.ui.editor ? "multiline" : "inline", 57 }); 58 59 if (action.from === "reverse-search") { 60 telemetry.recordEvent("reverse_search", "webconsole", null, { 61 functionality: "evaluate expression", 62 }); 63 } 64 } else if ( 65 action.type === REVERSE_SEARCH_INPUT_TOGGLE && 66 state.ui.reverseSearchInputVisible 67 ) { 68 telemetry.recordEvent("reverse_search", "webconsole", action.access, { 69 functionality: "open", 70 }); 71 } else if (action.type === REVERSE_SEARCH_NEXT) { 72 telemetry.recordEvent("reverse_search", "webconsole", action.access, { 73 functionality: "navigate next", 74 }); 75 } else if (action.type === REVERSE_SEARCH_BACK) { 76 telemetry.recordEvent("reverse_search", "webconsole", action.access, { 77 functionality: "navigate previous", 78 }); 79 } 80 81 return res; 82 }; 83 } 84 85 function filterChange({ action, state, oldState, telemetry }) { 86 const oldFilterState = oldState.filters; 87 const filterState = state.filters; 88 const activeFilters = []; 89 const inactiveFilters = []; 90 for (const [key, value] of Object.entries(filterState)) { 91 if (value) { 92 activeFilters.push(key); 93 } else { 94 inactiveFilters.push(key); 95 } 96 } 97 98 let trigger; 99 if (action.type === FILTER_TOGGLE) { 100 trigger = action.filter; 101 } else if (action.type === DEFAULT_FILTERS_RESET) { 102 trigger = "reset"; 103 } else if (action.type === FILTER_TEXT_SET) { 104 if (oldFilterState.text !== "" && filterState.text !== "") { 105 return; 106 } 107 108 trigger = "text"; 109 } 110 111 telemetry.recordEvent("filters_changed", "webconsole", null, { 112 trigger, 113 active: activeFilters.join(","), 114 inactive: inactiveFilters.join(","), 115 }); 116 } 117 118 function messagesAdd({ action }) { 119 const { messages } = action; 120 for (const message of messages) { 121 if (message.level === "error" && message.source === "javascript") { 122 Glean.devtoolsConsole.javascriptErrorDisplayed[ 123 message.errorMessageName || "Unknown" 124 ].add(1); 125 } 126 } 127 } 128 129 module.exports = eventTelemetryMiddleware;