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