• 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';
17import { SelectionParam } from '../../../../bean/BoxSelection';
18import { LogStruct } from '../../../../database/ui-worker/ProcedureWorkerLog';
19import { ColorUtils } from '../../base/ColorUtils';
20import { LitTable } from '../../../../../base-ui/table/lit-table';
21import { LitIcon } from '../../../../../base-ui/icon/LitIcon';
22import { TabPaneHiLogSummaryHtml } from './TabPaneHiLogSummary.html';
23import { NUM_30, NUM_40 } from '../../../../bean/NumBean';
24import { queryLogAllData } from '../../../../database/sql/SqlLite.sql';
25
26@element('tab-hi-log-summary')
27export class TabPaneHiLogSummary extends BaseElement {
28  private logSummaryTable: HTMLDivElement | undefined | null;
29  private summaryDownLoadTbl: LitTable | undefined | null;
30  private systemLogSource: LogStruct[] = [];
31  private logTreeNodes: LogTreeNode[] = [];
32  private expansionDiv: HTMLDivElement | undefined | null;
33  private expansionUpIcon: LitIcon | undefined | null;
34  private expansionDownIcon: LitIcon | undefined | null;
35  private expandedNodeList: Set<number> = new Set();
36  private logLevel: string[] = ['Debug', 'Info', 'Warn', 'Error', 'Fatal'];
37  private selectTreeDepth: number = 0;
38  private currentSelection: SelectionParam | undefined;
39
40  set data(systemLogDetailParam: SelectionParam) {
41    if (systemLogDetailParam === this.currentSelection) {
42      return;
43    }
44    this.currentSelection = systemLogDetailParam;
45    this.systemLogSource = [];
46    this.expandedNodeList.clear();
47    this.expansionUpIcon!.name = 'up';
48    this.expansionDownIcon!.name = 'down';
49    this.logSummaryTable!.innerHTML = '';
50    this.summaryDownLoadTbl!.recycleDataSource = [];
51    // @ts-ignore
52    let oneDayTime = (window as unknown).recordEndNS - 86400000000000;
53    if (systemLogDetailParam.hiLogs.length > 0) {
54      queryLogAllData(oneDayTime, systemLogDetailParam.leftNs, systemLogDetailParam.rightNs).then((res) => {
55        this.systemLogSource = res;
56        if (this.systemLogSource?.length !== 0 && systemLogDetailParam) {
57          this.refreshRowNodeTable();
58        }
59      });
60    }
61  }
62
63  initElements(): void {
64    this.logSummaryTable = this.shadowRoot?.querySelector<HTMLDivElement>('#tab-summary');
65    this.summaryDownLoadTbl = this.shadowRoot?.querySelector<LitTable>('#tb-hilog-summary');
66    this.expansionDiv = this.shadowRoot?.querySelector<HTMLDivElement>('.expansion-div');
67    this.expansionUpIcon = this.shadowRoot?.querySelector<LitIcon>('.expansion-up-icon');
68    this.expansionDownIcon = this.shadowRoot?.querySelector<LitIcon>('.expansion-down-icon');
69    let summaryTreeLevel: string[] = ['Level', '/Process', '/Tag', '/Message'];
70    this.shadowRoot?.querySelectorAll<HTMLLabelElement>('.head-label').forEach((summaryTreeHead): void => {
71      summaryTreeHead.addEventListener('click', (): void => {
72        this.selectTreeDepth = summaryTreeLevel.indexOf(summaryTreeHead.textContent!);
73        this.expandedNodeList.clear();
74        this.refreshSelectDepth(this.logTreeNodes);
75        this.refreshRowNodeTable(true);
76      });
77    });
78    this.logSummaryTable!.onscroll = (): void => {
79      let logTreeTableEl = this.shadowRoot?.querySelector<HTMLDivElement>('.log-tree-table');
80      if (logTreeTableEl) {
81        logTreeTableEl.scrollTop = this.logSummaryTable?.scrollTop || 0;
82      }
83    };
84  }
85
86  initHtml(): string {
87    return TabPaneHiLogSummaryHtml;
88  }
89
90  connectedCallback(): void {
91    super.connectedCallback();
92    new ResizeObserver((): void => {
93      this.parentElement!.style.overflow = 'hidden';
94      this.refreshRowNodeTable();
95    }).observe(this.parentElement!);
96    this.expansionDiv?.addEventListener('click', this.expansionClickEvent);
97  }
98
99  disconnectedCallback(): void {
100    super.disconnectedCallback();
101    this.expansionDiv?.removeEventListener('click', this.expansionClickEvent);
102  }
103
104  expansionClickEvent = (): void => {
105    this.expandedNodeList.clear();
106    if (this.expansionUpIcon?.name === 'down') {
107      this.selectTreeDepth = 0;
108      this.expansionUpIcon!.name = 'up';
109      this.expansionDownIcon!.name = 'down';
110    } else {
111      this.selectTreeDepth = 4;
112      this.expansionUpIcon!.name = 'down';
113      this.expansionDownIcon!.name = 'up';
114    }
115    this.refreshSelectDepth(this.logTreeNodes);
116    this.refreshRowNodeTable(true);
117  };
118
119  private refreshSelectDepth(logTreeNodes: LogTreeNode[]): void {
120    logTreeNodes.forEach((item): void => {
121      if (item.depth < this.selectTreeDepth) {
122        this.expandedNodeList.add(item.id);
123        if (item.children.length > 0) {
124          this.refreshSelectDepth(item.children);
125        }
126      }
127    });
128  }
129
130  private createRowNodeTableEL(
131    rowNodeList: LogTreeNode[],
132    tableTreeEl: HTMLDivElement,
133    tableCountEl: HTMLDivElement,
134    rowColor: string = ''
135  ): void {
136    let unitPadding: number = 20;
137    let leftPadding: number = 5;
138    rowNodeList.forEach((rowNode): void => {
139      let tableTreeRowEl: HTMLElement = document.createElement('tr');
140      tableTreeRowEl.className = 'tree-row-tr';
141      tableTreeRowEl.title = rowNode.logName + '';
142      let leftSpacingEl: HTMLElement = document.createElement('td');
143      leftSpacingEl.style.paddingLeft = `${rowNode.depth * unitPadding + leftPadding}px`;
144      tableTreeRowEl.appendChild(leftSpacingEl);
145      this.addToggleIconEl(rowNode, tableTreeRowEl);
146      let rowNodeTextEL: HTMLElement = document.createElement('td');
147      rowNodeTextEL.textContent = rowNode.logName + '';
148      rowNodeTextEL.className = 'row-name-td';
149      tableTreeRowEl.appendChild(rowNodeTextEL);
150      tableTreeEl.appendChild(tableTreeRowEl);
151      let tableCountRowEl: HTMLElement = document.createElement('tr');
152      tableCountRowEl.title = rowNode.count.toString();
153      let countEL: HTMLElement = document.createElement('td');
154      countEL.textContent = rowNode.count.toString();
155      countEL.className = 'count-column-td';
156      if (rowNode.depth === 0) {
157        rowNodeTextEL.style.color = ColorUtils.getHilogColor(rowNode.logName!);
158        countEL.style.color = ColorUtils.getHilogColor(rowNode.logName!);
159      } else {
160        rowNodeTextEL.style.color = rowColor;
161        countEL.style.color = rowColor;
162      }
163      tableCountRowEl.appendChild(countEL);
164      tableCountEl.appendChild(tableCountRowEl);
165      if (rowNode.children && this.expandedNodeList.has(rowNode.id)) {
166        this.createRowNodeTableEL(rowNode.children, tableTreeEl, tableCountEl, countEL.style.color);
167      }
168    });
169  }
170
171  private addToggleIconEl(rowNode: LogTreeNode, tableRowEl: HTMLElement): void {
172    let toggleIconEl: HTMLElement = document.createElement('td');
173    let expandIcon = document.createElement('lit-icon');
174    expandIcon.classList.add('tree-icon');
175    if (rowNode.children && rowNode.children.length > 0) {
176      toggleIconEl.appendChild(expandIcon);
177      // @ts-ignore
178      expandIcon.name = this.expandedNodeList.has(rowNode.id) ? 'minus-square' : 'plus-square';
179      toggleIconEl.classList.add('expand-icon');
180      toggleIconEl.addEventListener('click', (): void => {
181        let scrollTop = this.logSummaryTable?.scrollTop ?? 0;
182        this.changeNode(rowNode.id);
183        this.logSummaryTable!.scrollTop = scrollTop;
184      });
185    }
186    tableRowEl.appendChild(toggleIconEl);
187  }
188
189  private changeNode(currentNode: number): void {
190    if (this.expandedNodeList.has(currentNode)) {
191      this.expandedNodeList.delete(currentNode);
192    } else {
193      this.expandedNodeList.add(currentNode);
194    }
195    this.refreshRowNodeTable();
196  }
197
198  private refreshRowNodeTable(useCacheRefresh: boolean = false): void {
199    this.logSummaryTable!.innerHTML = '';
200    if (this.logSummaryTable && this.parentElement) {
201      this.logSummaryTable.style.height = `${this.parentElement!.clientHeight - NUM_30}px`;
202    }
203    if (!useCacheRefresh) {
204      this.logTreeNodes = this.buildTreeTblNodes(this.systemLogSource);
205      if (this.logTreeNodes.length > 0) {
206        this.summaryDownLoadTbl!.recycleDataSource = this.logTreeNodes;
207      } else {
208        this.summaryDownLoadTbl!.recycleDataSource = [];
209      }
210    }
211    let tableFragmentEl: DocumentFragment = document.createDocumentFragment();
212    let tableTreeEl: HTMLDivElement = document.createElement('div');
213    tableTreeEl.className = 'log-tree-table';
214    let tableCountEl: HTMLDivElement = document.createElement('div');
215    if (this.parentElement) {
216      tableTreeEl.style.height = `${this.parentElement!.clientHeight - NUM_40}px`;
217    }
218    this.createRowNodeTableEL(this.logTreeNodes, tableTreeEl, tableCountEl, '');
219    let emptyTr = document.createElement('tr');
220    emptyTr.className = 'tree-row-tr';
221    tableTreeEl?.appendChild(emptyTr);
222    let emptyCountTr = document.createElement('tr');
223    emptyCountTr.className = 'tree-row-tr';
224    tableCountEl?.appendChild(emptyCountTr);
225    tableFragmentEl.appendChild(tableTreeEl);
226    tableFragmentEl.appendChild(tableCountEl);
227    this.logSummaryTable!.appendChild(tableFragmentEl);
228  }
229
230  private buildTreeTblNodes(logTreeNodes: LogStruct[]): LogTreeNode[] {
231    let id = 0;
232    let root: LogTreeNode = { id: id, depth: 0, children: [], logName: 'All', count: 0 };
233    logTreeNodes.forEach((item) => {
234      id++;
235      let levelNode = root.children.find((node) => node.logName === item.level);
236      if (levelNode) {
237        levelNode.count++;
238      } else {
239        id++;
240        levelNode = { id: id, depth: 0, children: [], logName: item.level, count: 1 };
241        root.children.push(levelNode);
242      }
243      let processNode = levelNode.children.find((node) => node.logName === item.processName);
244      if (processNode) {
245        processNode.count++;
246      } else {
247        id++;
248        processNode = { id: id, depth: 1, children: [], logName: item.processName, count: 1 };
249        levelNode.children.push(processNode);
250      }
251      let tagNode = processNode.children.find((node) => node.logName === item.tag);
252      if (tagNode) {
253        tagNode.count++;
254      } else {
255        id++;
256        tagNode = { id: id, depth: 2, children: [], logName: item.tag, count: 1 };
257        processNode.children.push(tagNode);
258      }
259      let messageNode = tagNode.children.find((node) => node.logName === item.context);
260      if (messageNode) {
261        messageNode.count++;
262      } else {
263        id++;
264        tagNode.children.push({ id: id, depth: 3, children: [], logName: item.context, count: 1 });
265      }
266      root.count++;
267    });
268    return root.children.sort((leftData, rightData) => {
269      return this.logLevel.indexOf(leftData.logName!) - this.logLevel.indexOf(rightData.logName!);
270    });
271  }
272}
273
274export interface LogTreeNode {
275  id: number;
276  depth: number;
277  children: LogTreeNode[];
278  logName: string | undefined;
279  count: number;
280}
281