1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BaseElement, element } from '../../base-ui/BaseElement.js'; 17 18import { 19 querySelectTraceStats, querySystemCalls, 20 queryTraceMemory, 21 queryTraceMemoryTop, 22 queryTraceMemoryUnAgg, 23 queryTraceMetaData, 24 queryTraceTaskName, 25} from '../database/SqlLite.js'; 26 27import '../../base-ui/table/lit-table.js'; 28import { initMemoryAggStrategy } from './metrics/MemAggStrategy.js'; 29import { initMemoryStrategy } from './metrics/MemStrategy.js'; 30import { initTraceStateStrategy } from './metrics/TraceStatsStrategy.js'; 31import { initTraceTaskStrategy } from './metrics/TraceTaskStrategy.js'; 32import { initMetaDataStrategy } from './metrics/MetaDataStrategy.js'; 33import { PluginConvertUtils } from './setting/utils/PluginConvertUtils.js'; 34import { info } from '../../log/Log.js'; 35import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; 36import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; 37import { initSysCallsStrategy } from './metrics/SysCallsStrategy.js'; 38 39@element('sp-metrics') 40export class SpMetrics extends BaseElement { 41 private _metric?: string; 42 private _metricResult?: string; 43 private selectMetricEl: HTMLSelectElement | undefined; 44 private runButtonEl: HTMLButtonElement | undefined | null; 45 private responseJson: HTMLPreElement | undefined | null; 46 private metricOptionalSelects: Array<MetricQueryItem> | undefined; 47 private metricProgressLoad: LitProgressBar | undefined; 48 49 static get observedAttributes() { 50 return ['metric', 'metricResult']; 51 } 52 53 get metric(): string { 54 return this.getAttribute('metric') || ''; 55 } 56 57 set metric(value: string) { 58 this._metric = value; 59 } 60 61 get metricResult(): string { 62 return this.getAttribute('metricResult') || ''; 63 } 64 65 set metricResult(value: string) { 66 this._metricResult = value; 67 this.setAttribute('metricResult', value); 68 } 69 70 reset() { 71 this.selectMetricEl!.selectedIndex = 0; 72 this.responseJson!.textContent = ''; 73 } 74 75 initElements(): void { 76 this.metricProgressLoad = this.shadowRoot?.querySelector('.sp-load-metric') as LitProgressBar; 77 this.selectMetricEl = this.shadowRoot?.querySelector('.sql-select') as HTMLSelectElement; 78 this.runButtonEl = this.shadowRoot?.querySelector('.sql-select-button') as HTMLButtonElement; 79 this.responseJson = this.shadowRoot?.querySelector('.response-json') as HTMLPreElement; 80 if (this.selectMetricEl) { 81 this.selectMetricEl.addEventListener('selectionchange', () => { 82 if (this.selectMetricEl) this.selectMetricEl.textContent = ''; 83 }); 84 } 85 this.initMetricDataHandle(); 86 this.initMetricSelectOption(); 87 } 88 89 async initMetric(queryItem: MetricQueryItem) { 90 this.initMetricData(queryItem).then((item) => { 91 this.metricProgressLoad!.loading = false; 92 }); 93 } 94 95 async initMetricData(queryItem: MetricQueryItem) { 96 let metricQuery = queryItem.metricQuery; 97 let queryList = await metricQuery(); 98 info('current Metric Data size is: ', queryList!.length); 99 let metric = queryItem.metricResultHandle; 100 let resultData = metric(queryList); 101 let jsonText = PluginConvertUtils.BeanToCmdTxtWithObjName(resultData, true, queryItem.metricName, 4); 102 this.responseJson!.textContent = jsonText; 103 } 104 105 attributeChangedCallback(name: string, oldValue: string, newValue: string) { 106 switch (name) { 107 case 'metric': 108 if (this.selectMetricEl) this.selectMetricEl.textContent = newValue; 109 break; 110 case 'metricResult': 111 if (this.selectMetricEl) this.selectMetricEl.textContent = newValue; 112 break; 113 } 114 } 115 116 runClickListener = () => { 117 SpStatisticsHttpUtil.addOrdinaryVisitAction({ 118 event: 'metrics', 119 action: 'metrics', 120 }); 121 this.metricProgressLoad!.loading = true; 122 let selectedIndex = this.selectMetricEl!.selectedIndex; 123 let value = this.selectMetricEl!.options[selectedIndex].value; 124 let resultQuery = this.metricOptionalSelects?.filter((item) => { 125 return item.metricName == value; 126 }); 127 if (!resultQuery || resultQuery.length < 1) return; 128 this.initMetric(resultQuery[0]); 129 }; 130 131 connectedCallback() { 132 // Run metric button to add listener 133 this.runButtonEl?.addEventListener('click', this.runClickListener); 134 } 135 136 disconnectedCallback() { 137 this.runButtonEl?.removeEventListener('click', this.runClickListener); 138 } 139 140 initMetricSelectOption() { 141 for (let index = 0; index < this.metricOptionalSelects!.length; index++) { 142 let htmlElement = document.createElement('option'); 143 if (this.metricOptionalSelects) { 144 htmlElement.textContent = this.metricOptionalSelects[index].metricName; 145 this.selectMetricEl?.appendChild(htmlElement); 146 } 147 } 148 } 149 150 initMetricDataHandle() { 151 this.metricOptionalSelects = [ 152 { 153 metricName: 'trace_mem', 154 metricQuery: queryTraceMemory, 155 metricResultHandle: initMemoryStrategy, 156 }, 157 { 158 metricName: 'trace_mem_top10', 159 metricQuery: queryTraceMemoryTop, 160 metricResultHandle: initMemoryStrategy, 161 }, 162 { 163 metricName: 'trace_mem_unagg', 164 metricQuery: queryTraceMemoryUnAgg, 165 metricResultHandle: initMemoryAggStrategy, 166 }, 167 { 168 metricName: 'trace_task_names', 169 metricQuery: queryTraceTaskName, 170 metricResultHandle: initTraceTaskStrategy, 171 }, 172 { 173 metricName: 'trace_stats', 174 metricQuery: querySelectTraceStats, 175 metricResultHandle: initTraceStateStrategy, 176 }, 177 { 178 metricName: 'trace_metadata', 179 metricQuery: queryTraceMetaData, 180 metricResultHandle: initMetaDataStrategy, 181 }, 182 { 183 metricName: 'sys_calls', 184 metricQuery: querySystemCalls, 185 metricResultHandle: initSysCallsStrategy, 186 }, 187 ]; 188 } 189 190 initHtml(): string { 191 return ` 192 <style> 193 194 :host{ 195 width: 100%; 196 height: 100%; 197 background-color: var(--dark-background5,#F6F6F6); 198 margin: 0; 199 padding: 0; 200 font-size:16px; 201 } 202 203 .metric{ 204 display: flex; 205 flex-direction: column; 206 position: absolute; 207 top: 0; 208 bottom: 0; 209 left: 0; 210 right: 0; 211 background-color: var(--dark-background5,#F6F6F6); 212 } 213 214 .metric-select{ 215 color: #121212; 216 border-radius: 16px; 217 background-color: var(--dark-background3,#FFFFFF); 218 padding: 1% 2%; 219 margin: 2% 2.5% 0 2.5%; 220 grid-row-gap: 30px; 221 } 222 223 .request{ 224 min-height: 15vh; 225 overflow: auto; 226 position: relative; 227 } 228 229 .sql-select{ 230 font-family: Helvetica,serif; 231 color: var(--dark-color1,#212121); 232 font-size:0.875em; 233 line-height: 16px; 234 font-weight: 400; 235 text-align: left; 236 width: 50%; 237 height: 32px; 238 flex-wrap: wrap; 239 margin-top: 1%; 240 border: 1px solid var(--dark-color1,#4D4D4D); 241 border-radius: 16px; 242 padding: 5px 10px 5px 10px; 243 -webkit-appearance: none; 244 background: url('img/down.png') no-repeat 98% center var(--dark-background3,#FFFFFF); 245 } 246 247 button{ 248 border-radius: 16px; 249 flex-grow: 1; 250 background-color: #0A59F7; 251 height: 32px; 252 width: 96px; 253 font-size: 0.875em; 254 color: var(--dark-background3,#FFFFFF); 255 text-align: center; 256 line-height: 20px; 257 font-weight: 400; 258 border:0 solid; 259 margin-left: 2%; 260 opacity: 0.6; 261 cursor:pointer; 262 } 263 264 .response{ 265 flex-grow: 1; 266 margin-bottom: 1%; 267 } 268 269 .response-json{ 270 background-color: var(--dark-background3,#FFFFFF); 271 border-radius: 16px; 272 display: table-cell; 273 font-family: Helvetica,serif; 274 color: var(--dark-color1,#212121); 275 font-size:0.875em; 276 line-height: 20px; 277 font-weight: 400; 278 text-align: left; 279 height: 90%; 280 width: 100%; 281 border: none; 282 outline:none; 283 resize:none; 284 } 285 286 p{ 287 display: table-cell; 288 padding: 20% 0; 289 color: #999999; 290 font-size:0.875em; 291 line-height: 20px; 292 font-weight: 400; 293 text-align: left; 294 width: 100%; 295 } 296 ::-webkit-scrollbar 297 { 298 width: 8px; 299 background-color: var(--dark-background3,#FFFFFF); 300 } 301 ::-webkit-scrollbar-thumb 302 { 303 border-radius: 6px; 304 background-color: var(--dark-background7,rgba(0,0,0,0.1)); 305 } 306 .sp-load-metric{ 307 width: 95%; 308 bottom: 0; 309 } 310 311 </style> 312 313 <div class="metric"> 314 <div class="metric-select request"> 315 <p>Select a metric</p> 316 <select class="sql-select"> 317 </select> 318 <button class="sql-select-button"> Run </button> 319 <lit-progress-bar class="sp-load-metric"></lit-progress-bar> 320 </div> 321 <div class="metric-select response"> 322 <textarea class="response-json" readonly> 323 </textarea> 324 </div> 325 </div> 326 `; 327 } 328} 329 330export interface MetricQueryItem { 331 metricName: string; 332 metricQuery: Function; 333 metricResultHandle: Function; 334} 335