Line data Source code
1 : import * as React from 'react';
2 : import * as styles from './trace_log_panel.module.css';
3 :
4 : import { LogRecord } from '../platform/logger/log_buffer.js';
5 : import { useLogger } from '../platform/logger/logger_provider.js';
6 : import { TraceLogViewer } from './trace_log_viewer.js';
7 : import { TabHeader } from './tab_header.js';
8 :
9 : /// Track the number of log records on a trace, updating as records stream in. Returns 0 when the
10 : /// trace has no id. Drives the right-aligned "N of M rows" indicator.
11 1 : function useTraceLogCount(traceId: number | null): number {
12 1 : const logger = useLogger();
13 1 : const [count, setCount] = React.useState(0);
14 1 : React.useEffect(() => {
15 1 : if (traceId == null) {
16 0 : setCount(0);
17 0 : return;
18 0 : }
19 1 : setCount(logger.buffer.collectTraceLogs(traceId).length);
20 1 : const observer = (_record: LogRecord) => setCount(prev => prev + 1);
21 1 : logger.buffer.subscribeTrace(traceId, observer);
22 1 : return () => logger.buffer.unsubscribeTrace(traceId, observer);
23 1 : }, [traceId, logger]);
24 1 : return count;
25 1 : }
26 :
27 : interface TraceLogPanelProps {
28 : traceId: number | null;
29 : title: string;
30 : /// Scrollless preview mode: the viewer auto-expands to fit its rows and caps at this many. Used
31 : /// by the feed server card. When unset the viewer fills its parent's height and scrolls.
32 : maxRows?: number;
33 : /// When set, the header opens the corresponding Details log tab.
34 : onHeaderClick?: () => void;
35 : }
36 :
37 : /// One trace-log surface. Independent logs use separate vertical tabs, so this component no
38 : /// longer owns source selection; it only renders the selected trace and its row count.
39 1 : export const TraceLogPanel: React.FC<TraceLogPanelProps> = (props) => {
40 1 : const totalLogRows = useTraceLogCount(props.traceId);
41 1 : const shownLogRows = props.maxRows != null ? Math.min(totalLogRows, props.maxRows) : totalLogRows;
42 1 : const truncated = props.maxRows != null && totalLogRows > props.maxRows;
43 1 : const logCountDetail = truncated
44 0 : ? `${shownLogRows} of ${totalLogRows} rows`
45 1 : : `${totalLogRows} ${totalLogRows === 1 ? 'row' : 'rows'}`;
46 :
47 1 : return (
48 1 : <>
49 1 : <TabHeader
50 1 : title={props.title}
51 1 : detail={logCountDetail}
52 1 : onClick={props.onHeaderClick}
53 1 : detailIsLink={truncated}
54 1 : />
55 1 : {props.traceId == null ? (
56 0 : <div className={styles.log_empty}>No logs available</div>
57 1 : ) : props.maxRows != null ? (
58 1 : <TraceLogViewer traceId={props.traceId ?? undefined} maxRows={props.maxRows} />
59 : ) : (
60 0 : <div className={styles.log_viewer_fill}>
61 0 : <TraceLogViewer traceId={props.traceId ?? undefined} fill />
62 0 : </div>
63 : )}
64 1 : </>
65 : );
66 1 : };
|