• 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() {
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">&nbsp;&nbsp; Run &nbsp;&nbsp;</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