FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
fersLogStore.ts
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
3
4import { create } from 'zustand';
5
6export type FersLogLevel =
7 | 'TRACE'
8 | 'DEBUG'
9 | 'INFO'
10 | 'WARNING'
11 | 'ERROR'
12 | 'FATAL'
13 | 'OFF'
14 | 'UNKNOWN';
15
16export type FersLogEntry = {
17 sequence: number;
18 level: FersLogLevel;
19 line: string;
20};
21
22export type ConfigurableFersLogLevel = Exclude<FersLogLevel, 'UNKNOWN'>;
23
24type FersLogStore = {
25 entries: FersLogEntry[];
26 droppedCount: number;
27 maxLines: number;
28 logLevel: ConfigurableFersLogLevel;
29 isOpen: boolean;
30 appendLog: (entry: FersLogEntry) => void;
31 clearLogs: () => void;
32 setMaxLines: (maxLines: number) => void;
33 setLogLevel: (logLevel: ConfigurableFersLogLevel) => void;
34 setOpen: (isOpen: boolean) => void;
35 toggleOpen: () => void;
36};
37
38export const DEFAULT_LOG_MAX_LINES = 2000;
39export const MIN_LOG_MAX_LINES = 100;
40export const MAX_LOG_MAX_LINES = 20_000;
41export const DEFAULT_LOG_LEVEL: ConfigurableFersLogLevel = 'INFO';
42export const LOG_LEVEL_OPTIONS: ConfigurableFersLogLevel[] = [
43 'TRACE',
44 'DEBUG',
45 'INFO',
46 'WARNING',
47 'ERROR',
48 'FATAL',
49 'OFF',
50];
51
52export const isConfigurableFersLogLevel = (
53 level: FersLogLevel
54): level is ConfigurableFersLogLevel =>
55 LOG_LEVEL_OPTIONS.some((option) => option === level);
56
57export const clampLogMaxLines = (maxLines: number) => {
58 if (!Number.isFinite(maxLines)) {
59 return DEFAULT_LOG_MAX_LINES;
60 }
61
62 return Math.max(
63 MIN_LOG_MAX_LINES,
64 Math.min(MAX_LOG_MAX_LINES, Math.floor(maxLines))
65 );
66};
67
68const trimEntries = (
69 entries: FersLogEntry[],
70 maxLines: number
71): { entries: FersLogEntry[]; dropped: number } => {
72 if (entries.length <= maxLines) {
73 return { entries, dropped: 0 };
74 }
75
76 return {
77 entries: entries.slice(entries.length - maxLines),
78 dropped: entries.length - maxLines,
79 };
80};
81
82export const useFersLogStore = create<FersLogStore>()((set) => ({
83 entries: [],
84 droppedCount: 0,
85 maxLines: DEFAULT_LOG_MAX_LINES,
86 logLevel: DEFAULT_LOG_LEVEL,
87 isOpen: false,
88 appendLog: (entry) =>
89 set((state) => {
90 const trimmed = trimEntries(
91 [...state.entries, entry],
92 state.maxLines
93 );
94
95 return {
96 entries: trimmed.entries,
97 droppedCount: state.droppedCount + trimmed.dropped,
98 };
99 }),
100 clearLogs: () => set({ entries: [], droppedCount: 0 }),
101 setMaxLines: (maxLines) =>
102 set((state) => {
103 const nextMaxLines = clampLogMaxLines(maxLines);
104 const trimmed = trimEntries(state.entries, nextMaxLines);
105
106 return {
107 maxLines: nextMaxLines,
108 entries: trimmed.entries,
109 droppedCount: state.droppedCount + trimmed.dropped,
110 };
111 }),
112 setLogLevel: (logLevel) => set({ logLevel }),
113 setOpen: (isOpen) => set({ isOpen }),
114 toggleOpen: () => set((state) => ({ isOpen: !state.isOpen })),
115}));