• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15import { LogViewer as RootComponent } from './components/log-viewer';
16import { LogViewerState } from './shared/state';
17import { LogSourceEvent } from '../src/shared/interfaces';
18import { LogSource } from '../src/log-source';
19import { LogStore } from './log-store';
20
21import '@material/web/button/filled-button.js';
22import '@material/web/button/outlined-button.js';
23import '@material/web/checkbox/checkbox.js';
24import '@material/web/field/outlined-field.js';
25import '@material/web/textfield/outlined-text-field.js';
26import '@material/web/textfield/filled-text-field.js';
27import '@material/web/icon/icon.js';
28import '@material/web/iconbutton/icon-button.js';
29import '@material/web/menu/menu.js';
30import '@material/web/menu/menu-item.js';
31
32// Shoelace imports
33import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
34
35/**
36 * Create an instance of log-viewer
37 * @param logSources - collection of sources from where logs originate
38 * @param root - HTML component to append log-viewer to
39 * @param state - handles state between sessions, defaults to localStorage
40 * @param logStore - stores and handles management of all logs
41 * @param columnOrder - defines column order between severity and message
42 *   undefined fields are appended between defined order and message.
43 */
44export function createLogViewer(
45  logSources: LogSource | LogSource[],
46  root: HTMLElement,
47  state?: LogViewerState,
48  logStore: LogStore = new LogStore(),
49  columnOrder: string[] = ['log_source', 'time', 'timestamp'],
50) {
51  const logViewer = new RootComponent(state, columnOrder);
52  root.appendChild(logViewer);
53  let lastUpdateTimeoutId: NodeJS.Timeout;
54  logStore.setColumnOrder(columnOrder);
55
56  const logEntryListener = (event: LogSourceEvent) => {
57    if (event.type === 'log-entry') {
58      const logEntry = event.data;
59      logStore.addLogEntry(logEntry);
60      logViewer.logs = logStore.getLogs();
61      if (lastUpdateTimeoutId) {
62        clearTimeout(lastUpdateTimeoutId);
63      }
64
65      // Call requestUpdate at most once every 100 milliseconds.
66      lastUpdateTimeoutId = setTimeout(() => {
67        const updatedLogs = [...logStore.getLogs()];
68        logViewer.logs = updatedLogs;
69      }, 100);
70    }
71  };
72
73  const sourcesArray = Array.isArray(logSources) ? logSources : [logSources];
74
75  sourcesArray.forEach((logSource: LogSource) => {
76    // Add the event listener to the LogSource instance
77    logSource.addEventListener('log-entry', logEntryListener);
78  });
79
80  // Method to destroy and unsubscribe
81  return () => {
82    if (logViewer.parentNode) {
83      logViewer.parentNode.removeChild(logViewer);
84    }
85
86    sourcesArray.forEach((logSource: LogSource) => {
87      logSource.removeEventListener('log-entry', logEntryListener);
88    });
89  };
90}
91