• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(): string[] {
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(): void {
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) {
83          this.selectMetricEl.textContent = '';
84        }
85      });
86    }
87    this.initMetricDataHandle();
88    this.initMetricSelectOption();
89  }
90
91  initMetric(queryItem: MetricQueryItem): void {
92    this.initMetricData(queryItem).then(() => {
93      this.metricProgressLoad!.loading = false;
94    });
95  }
96
97  async initMetricData(queryItem: MetricQueryItem): Promise<void> {
98    let spacesNumber = 4;
99    let metricQuery = queryItem.metricQuery;
100    let queryList = await metricQuery();
101    info('current Metric Data size is: ', queryList!.length);
102    let metric = queryItem.metricResultHandle;
103    let resultData = metric(queryList);
104    this.responseJson!.textContent = PluginConvertUtils.BeanToCmdTxtWithObjName(resultData, true,
105      queryItem.metricName, spacesNumber);
106  }
107
108  attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
109    switch (name) {
110      case 'metric':
111        if (this.selectMetricEl) {
112          this.selectMetricEl.textContent = newValue;
113        }
114        break;
115      case 'metricResult':
116        if (this.selectMetricEl) {
117          this.selectMetricEl.textContent = newValue;
118        }
119        break;
120    }
121  }
122
123  runClickListener = (): void => {
124    SpStatisticsHttpUtil.addOrdinaryVisitAction({
125      event: 'metrics',
126      action: 'metrics',
127    });
128    this.metricProgressLoad!.loading = true;
129    let selectedIndex = this.selectMetricEl!.selectedIndex;
130    let value = this.selectMetricEl!.options[selectedIndex].value;
131    let resultQuery = this.metricOptionalSelects?.filter((item) => {
132      return item.metricName === value;
133    });
134    if (!resultQuery || resultQuery.length === 0) {
135      return;
136    }
137    this.initMetric(resultQuery[0]);
138  };
139
140  connectedCallback(): void {
141    // Run metric button to add listener
142    this.runButtonEl?.addEventListener('click', this.runClickListener);
143  }
144
145  disconnectedCallback(): void {
146    this.runButtonEl?.removeEventListener('click', this.runClickListener);
147  }
148
149  initMetricSelectOption(): void {
150    for (let index = 0 ; index < this.metricOptionalSelects!.length ; index++) {
151      let htmlElement = document.createElement('option');
152      if (this.metricOptionalSelects) {
153        htmlElement.textContent = this.metricOptionalSelects[index].metricName;
154        this.selectMetricEl?.appendChild(htmlElement);
155      }
156    }
157  }
158
159  initMetricDataHandle(): void {
160    this.metricOptionalSelects = [
161      {
162        metricName: 'trace_mem',
163        metricQuery: queryTraceMemory,
164        metricResultHandle: initMemoryStrategy,
165      },
166      {
167        metricName: 'trace_mem_top10',
168        metricQuery: queryTraceMemoryTop,
169        metricResultHandle: initMemoryStrategy,
170      },
171      {
172        metricName: 'trace_mem_unagg',
173        metricQuery: queryTraceMemoryUnAgg,
174        metricResultHandle: initMemoryAggStrategy,
175      },
176      {
177        metricName: 'trace_task_names',
178        metricQuery: queryTraceTaskName,
179        metricResultHandle: initTraceTaskStrategy,
180      },
181      {
182        metricName: 'trace_stats',
183        metricQuery: querySelectTraceStats,
184        metricResultHandle: initTraceStateStrategy,
185      },
186      {
187        metricName: 'trace_metadata',
188        metricQuery: queryTraceMetaData,
189        metricResultHandle: initMetaDataStrategy,
190      },
191      {
192        metricName: 'sys_calls',
193        metricQuery: querySystemCalls,
194        metricResultHandle: initSysCallsStrategy,
195      },
196    ];
197  }
198
199  initHtml(): string {
200    return `
201        <style>
202        :host{
203            width: 100%;
204            height: 100%;
205            background-color: var(--dark-background5,#F6F6F6);
206            margin: 0;
207            padding: 0;
208            font-size:16px;
209        }
210        .metric{
211            display: flex;
212            flex-direction: column;
213            position: absolute;
214            top: 0;
215            bottom: 0;
216            left: 0;
217            right: 0;
218            background-color: var(--dark-background5,#F6F6F6);
219        }
220        .metric-select{
221            color: #121212;
222            border-radius: 16px;
223            background-color: var(--dark-background3,#FFFFFF);
224            padding: 1% 2%;
225            margin: 2% 2.5% 0 2.5%;
226            grid-row-gap: 30px;
227        }
228        .request{
229            min-height: 15vh;
230            overflow: auto;
231            position: relative;
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        button{
251            border-radius: 16px;
252            flex-grow: 1;
253            background-color: #0A59F7;
254            height: 32px;
255            width: 96px;
256            font-size: 0.875em;
257            color: var(--dark-background3,#FFFFFF);
258            text-align: center;
259            line-height: 20px;
260            font-weight: 400;
261            border:0 solid;
262            margin-left: 2%;
263            opacity: 0.6;
264            cursor:pointer;
265        }
266        .response{
267            flex-grow: 1;
268            margin-bottom: 1%;
269        }
270        .response-json{
271            background-color: var(--dark-background3,#FFFFFF);
272            border-radius: 16px;
273            display: table-cell;
274            font-family: Helvetica,serif;
275            color: var(--dark-color1,#212121);
276            font-size:0.875em;
277            line-height: 20px;
278            font-weight: 400;
279            text-align: left;
280            height: 90%;
281            width: 100%;
282            border: none;
283            outline:none;
284            resize:none;
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-thumb{
297          background-color: var(--dark-background7,rgba(0,0,0,0.1));
298          border-radius: 6px;
299        }
300        .sp-load-metric{
301            width: 95%;
302            bottom: 0;
303        }
304        ::-webkit-scrollbar{
305          background-color: var(--dark-background3,#FFFFFF);
306          width: 8px;
307        }
308        </style>
309        <div class="metric">
310            <div class="metric-select request">
311                <p>Select a metric</p>
312                <select class="sql-select">
313                </select>
314                <button class="sql-select-button">&nbsp;&nbsp; Run &nbsp;&nbsp;</button>
315                <lit-progress-bar class="sp-load-metric"></lit-progress-bar>
316            </div>
317            <div class="metric-select response">
318                 <textarea class="response-json" readonly>
319                 </textarea>
320            </div>
321        </div>
322        `;
323  }
324}
325
326export interface MetricQueryItem {
327  metricName: string;
328  metricQuery: Function;
329  metricResultHandle: Function;
330}
331