1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {globalConfig} from 'common/global_config'; 18import {CoarseVersion} from 'trace/coarse_version'; 19import {Parser} from 'trace/parser'; 20import {TraceType} from 'trace/trace_type'; 21 22/* eslint-disable no-undef */ 23export class Analytics { 24 private static BUGANIZER_OPENED = 'buganizer_opened'; 25 private static CROSS_TOOL_SYNC = 'cross_tool_sync'; 26 private static DARK_MODE_ENABLED = 'dark_mode_enabled'; 27 private static DOCUMENTATION_OPENED = 'documentation_opened'; 28 private static EXPANDED_TIMELINE_OPENED = 'expanded_timeline_opened'; 29 private static GLOBAL_EXCEPTION = 'global_exception'; 30 private static HIERARCHY_SETTINGS = 'hierarchy_settings'; 31 private static NAVIGATION_ZOOM_EVENT = 'navigation_zoom'; 32 private static PROPERTIES_SETTINGS = 'properties_settings'; 33 private static PROXY_ERROR = 'proxy_error'; 34 private static PROXY_SERVER_NOT_FOUND = 'proxy_server_not_found'; 35 private static PROXY_NO_FILES_FOUND = 'proxy_no_files_found'; 36 private static TP_QUERY_EXECUTION_TIME = 'tp_query_execution_time'; 37 private static TP_QUERY_REQUESTED = 'tp_query_requested'; 38 private static TP_QUERY_FAILED = 'tp_query_failed'; 39 private static TP_QUERY_SAVED = 'tp_query_saved'; 40 private static RECT_SETTINGS = 'rect_settings'; 41 private static REFRESH_DUMPS = 'refresh_dumps'; 42 private static TIME_BOOKMARK = 'time_bookmark'; 43 private static TIME_COPIED = 'time_copied'; 44 private static TIME_INPUT = 'time_input'; 45 private static TRACE_TAB_SWITCHED = 'trace_tab_switched'; 46 private static TRACE_TIMELINE_DESELECTED = 'trace_timeline_deselected'; 47 private static TRACING_LOADED_EVENT = 'tracing_trace_loaded'; 48 private static TRACING_COLLECT_DUMP = 'tracing_collect_dump'; 49 private static TRACING_COLLECT_TRACE = 'tracing_collect_trace'; 50 private static TRACING_OPEN_FROM_ABT = 'tracing_from_abt'; 51 private static USER_WARNING = 'user_warning'; 52 53 static Error = class { 54 static logGlobalException(description: string) { 55 Analytics.doLogEvent(Analytics.GLOBAL_EXCEPTION, { 56 description, 57 } as Gtag.CustomParams); 58 } 59 static logProxyError(description: string) { 60 Analytics.doLogEvent(Analytics.PROXY_ERROR, { 61 description, 62 } as Gtag.CustomParams); 63 } 64 }; 65 66 static Help = class { 67 static logDocumentationOpened() { 68 Analytics.doLogEvent(Analytics.DOCUMENTATION_OPENED); 69 } 70 71 static logBuganizerOpened() { 72 Analytics.doLogEvent(Analytics.BUGANIZER_OPENED); 73 } 74 }; 75 76 static Navigation = class { 77 static logExpandedTimelineOpened() { 78 Analytics.doLogEvent(Analytics.EXPANDED_TIMELINE_OPENED); 79 } 80 81 static logHierarchySettingsChanged( 82 option: string, 83 value: boolean, 84 traceType: string, 85 ) { 86 Analytics.doLogEvent(Analytics.HIERARCHY_SETTINGS, { 87 option, 88 value, 89 traceType, 90 } as Gtag.CustomParams); 91 } 92 93 static logPropertiesSettingsChanged( 94 option: string, 95 value: boolean, 96 traceType: string, 97 ) { 98 Analytics.doLogEvent(Analytics.PROPERTIES_SETTINGS, { 99 option, 100 value, 101 traceType, 102 } as Gtag.CustomParams); 103 } 104 105 static logRectSettingsChanged( 106 option: string, 107 value: string | number | boolean, 108 traceType: string, 109 ) { 110 Analytics.doLogEvent(Analytics.RECT_SETTINGS, { 111 option, 112 value, 113 traceType, 114 } as Gtag.CustomParams); 115 } 116 117 static logTabSwitched(tabTraceType: string) { 118 Analytics.doLogEvent(Analytics.TRACE_TAB_SWITCHED, { 119 type: tabTraceType, 120 } as Gtag.CustomParams); 121 } 122 123 static logTimeCopied(type: 'ns' | 'human') { 124 Analytics.doLogEvent(Analytics.TIME_COPIED, { 125 type, 126 } as Gtag.CustomParams); 127 } 128 129 static logTimeInput(type: 'ns' | 'human') { 130 Analytics.doLogEvent(Analytics.TIME_INPUT, { 131 type, 132 } as Gtag.CustomParams); 133 } 134 135 static logTimeBookmark() { 136 Analytics.doLogEvent(Analytics.TIME_BOOKMARK); 137 } 138 139 static logTraceTimelineDeselected(type: string) { 140 Analytics.doLogEvent(Analytics.TRACE_TIMELINE_DESELECTED, { 141 type, 142 } as Gtag.CustomParams); 143 } 144 145 static logZoom( 146 type: 'scroll' | 'button' | 'reset' | 'key', 147 component: 'rects' | 'timeline', 148 direction?: 'in' | 'out', 149 ) { 150 Analytics.doLogEvent(Analytics.NAVIGATION_ZOOM_EVENT, { 151 direction, 152 component, 153 type, 154 } as Gtag.CustomParams); 155 } 156 }; 157 158 static Proxy = class { 159 static logServerNotFound() { 160 Analytics.doLogEvent(Analytics.PROXY_SERVER_NOT_FOUND); 161 } 162 163 static logNoFilesFound() { 164 Analytics.doLogEvent(Analytics.PROXY_NO_FILES_FOUND); 165 } 166 }; 167 168 static Settings = class { 169 static logDarkModeEnabled() { 170 Analytics.doLogEvent(Analytics.DARK_MODE_ENABLED); 171 } 172 static logCrossToolSync(value: boolean) { 173 Analytics.doLogEvent(Analytics.CROSS_TOOL_SYNC, { 174 value, 175 } as Gtag.CustomParams); 176 } 177 }; 178 179 static TraceSearch = class { 180 static logQueryExecutionTime(value: number) { 181 Analytics.doLogEvent(Analytics.TP_QUERY_EXECUTION_TIME, { 182 value, 183 } as Gtag.CustomParams); 184 } 185 static logQueryFailure() { 186 Analytics.doLogEvent(Analytics.TP_QUERY_FAILED); 187 } 188 static logQueryRequested(type: 'new' | 'saved' | 'recent') { 189 Analytics.doLogEvent(Analytics.TP_QUERY_REQUESTED, { 190 type, 191 } as Gtag.CustomParams); 192 } 193 static logQuerySaved() { 194 Analytics.doLogEvent(Analytics.TP_QUERY_SAVED); 195 } 196 }; 197 198 static Tracing = class { 199 static logTraceLoaded(parser: Parser<object>) { 200 Analytics.doLogEvent(Analytics.TRACING_LOADED_EVENT, { 201 type: TraceType[parser.getTraceType()], 202 coarse_version: CoarseVersion[parser.getCoarseVersion()], 203 } as Gtag.CustomParams); 204 } 205 206 static logCollectDumps(requestedDumps: string[]) { 207 requestedDumps.forEach((dumpType) => { 208 Analytics.doLogEvent(Analytics.TRACING_COLLECT_DUMP, { 209 type: dumpType, 210 } as Gtag.CustomParams); 211 }); 212 } 213 214 static logCollectTraces(requestedTraces: string[]) { 215 requestedTraces.forEach((traceType) => { 216 Analytics.doLogEvent(Analytics.TRACING_COLLECT_TRACE, { 217 type: traceType, 218 } as Gtag.CustomParams); 219 }); 220 } 221 222 static logOpenFromABT() { 223 Analytics.doLogEvent(Analytics.TRACING_OPEN_FROM_ABT); 224 } 225 226 static logRefreshDumps() { 227 Analytics.doLogEvent(Analytics.REFRESH_DUMPS); 228 } 229 }; 230 231 static UserNotification = class { 232 static logUserWarning(description: string, message: string) { 233 Analytics.doLogEvent(Analytics.USER_WARNING, { 234 description, 235 message, 236 } as Gtag.CustomParams); 237 } 238 }; 239 240 private static doLogEvent( 241 eventName: Gtag.EventNames | (string & {}), 242 eventParams?: Gtag.ControlParams | Gtag.EventParams | Gtag.CustomParams, 243 ) { 244 if (globalConfig.MODE === 'PROD') { 245 gtag('event', eventName, eventParams); 246 } 247 } 248} 249