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