|
4 | 4 | | ---- | ----- | |
5 | 5 | | [](https://github.com/aiekick/LogToGraph/actions/workflows/win.yml) | [](https://github.com/aiekick/LogToGraph/actions/workflows/Linux.yml) | |
6 | 6 |
|
7 | | -MacOs is not officially maintained but i think he can compile on it. |
8 | | -So i let the cmake infos about MacOs in bottom of this ReadMe. |
| 7 | +MacOs is not officially maintained but should compile on it; the CMake notes for MacOs are at the bottom of this file. |
9 | 8 |
|
10 | | -## Goal : |
| 9 | +## Goal |
11 | 10 |
|
12 | | -LogToGraph have been designed to display numerical signals based logs as graph. |
| 11 | +LogToGraph turns text-based numerical logs into interactive signal graphs. |
13 | 12 |
|
14 | | -The kind of logs you have in mesuring systems like, profiler, electric system/simulator, etc... |
| 13 | +Typical inputs: profilers, electrical / simulation systems, embedded telemetry, scientific instrument logs — anything where each row carries a date, a signal name, and a value (numeric or status string). |
15 | 14 |
|
16 | | -This tool can be adapted to many log formats, since the log pattern matching is achieved by a lua script. |
| 15 | +The tool can be adapted to any log format because the row-to-signal mapping is implemented by a **Lua script you write inside the app**. |
17 | 16 |
|
18 | | -## How is working : |
| 17 | +## How it works |
19 | 18 |
|
20 | | -1) The tool will read your log row by row. |
21 | | -2) Each row will be put in the memory space of a scripting engine |
22 | | -3) The script will parse the row and will add a signal tick with infos (category, epoch time, signal name, signal value) |
23 | | -4) the tool will display all signal in graph |
| 19 | +1. The tool reads each log file row by row. |
| 20 | +2. Each row is handed to a Lua script's `parse(buffer)` function. |
| 21 | +3. The script extracts signal samples and feeds them back to the host via the `ltg:*` API (`ltg:addSignalValue`, `ltg:addSignalTag`, etc.). |
| 22 | +4. The host stores everything in a SQLite database and renders the resulting signals as interactive graphs. |
24 | 23 |
|
25 | | -with this tool you can : |
26 | | - - display many signals in separate graph |
27 | | - - display many signals grouped per graph group |
28 | | - - display all signals in a minimal view |
29 | | - - search for a signal name |
30 | | - - show the values of all signals at the timeframe hovered by the mouse |
31 | | - - show zone of signals (start / end) |
32 | | - - show a special tag for point event (like erreors by ex) |
33 | | - - show the changed signals values between two timeframe markers |
34 | | - - display the whole singals tick in a log view |
35 | | - - display the whole singals tick in a second log view (for compare with the first) |
36 | | - - display a code pane for let you test/design your script |
37 | | - - the project file is a sqlite database, so you can open it again without reparse or do treatment with other apps |
38 | | - - you can parse many log file at same time but with the same parsing file |
39 | | - |
40 | | -## Howto : Script Api |
| 24 | +The script — including the boilerplate `startFile` / `parse` / `endFile` callbacks — lives **inside the project file** (no external `.lua` file to keep around). The whole project is a single `.ltg` SQLite DB you can open with any SQLite tool. |
41 | 25 |
|
42 | | -```lua |
43 | | -function startFile() |
| 26 | +With this you can: |
| 27 | + |
| 28 | +- display many signals across separate graphs |
| 29 | +- group several signals on the same graph |
| 30 | +- display all signals in a minimal overview |
| 31 | +- search signals by name |
| 32 | +- show the values of all signals at the hovered timeframe |
| 33 | +- mark zones (start / end) and point events (tags) |
| 34 | +- diff signal values between two time markers |
| 35 | +- annotate delta times by middle-clicking on a curve |
| 36 | +- export-free workflow: the project file IS a SQLite DB, openable in any external tool for downstream treatment |
| 37 | +- analyse several log files at once with the same parsing script |
| 38 | + |
| 39 | +## Lua scripting workflow |
| 40 | + |
| 41 | +The in-app **Script** pane (in the Code window) is a small but real IDE: |
| 42 | + |
| 43 | +- **Autocomplete** on `.` / `:` — `ltg:` methods, `math.` / `string.` / `table.` / `os.`, plus your own globals (`function helpers.foo()`, etc.) refreshed on every edit. |
| 44 | +- **Signature help** on `(` — argument names and types for every documented function. Triggers on `ltg:addSignalValue(`, `math.sqrt(`, `string.match(`, etc. |
| 45 | +- **Error markers** — runtime errors surface on the offending line with the real Lua message as a tooltip. |
| 46 | +- **Hover-eval** — when paused, hovering an identifier shows its current value in the paused scope (VS-style). |
| 47 | +- **Per-project zoom + breakpoints** — `Ctrl+MouseWheel` zooms the editor; the zoom level and all breakpoints are persisted in the project XML. |
| 48 | +- **New-project template** — File → New starts you off with a documented boilerplate script (`startFile` / `parse` / `endFile` + the full `ltg:*` API listed as comments). |
| 49 | + |
| 50 | +### Debugger |
| 51 | + |
| 52 | +Toggle Debug in the Code pane toolbar to arm the script debugger. |
| 53 | + |
| 54 | +- **Single-click in the gutter** sets/removes a breakpoint. The dot is visible even when Debug is off (you can plan your breakpoints in advance) and stays inert until Debug is armed. |
| 55 | +- **Run / Continue / Step into / Step over / Step out / Pause / Stop** in the toolbar drive the worker. Step buttons jump the editor caret to the live execution line (VS-style); manual caret moves between pauses are preserved. |
| 56 | +- **Watcher pane** — typed expressions or right-click → "Watch <token>" in the editor. Re-evaluated in the paused scope on every pause. |
| 57 | +- **Stack tree / Scope / Calltrace panes** — call stack, current scope locals + upvalues, and full callstack with source positions. Tables are lazy-expanded. |
| 58 | + |
| 59 | +### Auto-bp + pause on error (opt-in) |
| 60 | + |
| 61 | +Settings → Debug → "Auto-bp + pause on error" (or the Code pane's Debug menu): when ON, every runtime error in the script pauses the worker **synchronously at the throw site** before the stack unwinds. The Lua call stack with locals and upvalues is inspectable, an automatic breakpoint is set at the error line for the next run, and the error message is shown both in the console and as the editor's red tooltip. |
| 62 | + |
| 63 | +Continue resumes the run normally; the error keeps propagating through pcall as if you hadn't paused. Stop aborts the run cleanly. |
| 64 | + |
| 65 | +This works for both C++ exceptions thrown by bindings (`ltg:stringToEpoch` on a bad date format) and pure-Lua errors (`string.match(nil, ...)`, `nil:method()`, bad arg types). |
| 66 | + |
| 67 | +### Debug settings (per-feature toggles) |
44 | 68 |
|
| 69 | +Settings → Debug, mirrored in the Code pane's Debug menu: |
| 70 | + |
| 71 | +- Recompile project script on edit (powers user-globals autocomplete; turn off for very large scripts) |
| 72 | +- Autocomplete popup |
| 73 | +- Signature help |
| 74 | +- Error markers |
| 75 | +- Hover eval tooltip |
| 76 | +- Auto-bp + pause on error |
| 77 | + |
| 78 | +## Lua scripting API |
| 79 | + |
| 80 | +The full reference is in [plugins/LuaScripting/README.md](plugins/LuaScripting/README.md). Quick overview: |
| 81 | + |
| 82 | +```lua |
| 83 | +function startFile(filepath) |
| 84 | + -- called once per log file, before parse() |
45 | 85 | end |
46 | 86 |
|
47 | 87 | function parse(buffer) |
| 88 | + -- called once per row with the row's text content |
| 89 | +end |
48 | 90 |
|
| 91 | +function endFile(filepath) |
| 92 | + -- called once per log file, after the last parse() |
49 | 93 | end |
| 94 | +``` |
| 95 | + |
| 96 | +Signal emission: |
| 97 | + |
| 98 | +```lua |
| 99 | +ltg:addSignalValue("category", "signal_name", epoch, value, "optional_desc") |
| 100 | +ltg:addSignalStatus("category", "signal_name", epoch, "running" or "stopped" or ...) |
| 101 | +ltg:addSignalStartZone("category", "signal_name", epoch, "label") |
| 102 | +ltg:addSignalEndZone("category", "signal_name", epoch, "label") |
| 103 | +ltg:addSignalTag(epoch, r, g, b, a, "name", "tooltip") -- point event, color is linear [0:1] |
| 104 | +``` |
| 105 | + |
| 106 | +Time conversion (ISO-like "YYYY-MM-DD HH:MM:SS,MS" or "YYYY-MM-DD HH:MM:SS.MS", hour offset as 2nd arg): |
| 107 | + |
| 108 | +```lua |
| 109 | +local epoch = ltg:stringToEpoch("2023-01-16 15:24:26,464", 0) |
| 110 | +local s = ltg:epochToString(epoch, 0) |
| 111 | +``` |
50 | 112 |
|
51 | | -function endFile() |
| 113 | +Regex (`boost::regex` engine, PCRE-like — supports `|`, `{m,n}`, lookahead, etc., much more expressive than Lua patterns): |
| 114 | + |
| 115 | +```lua |
| 116 | +local profilerPattern = ltg:regex([[<profiler section="([^"]*)" epoch_time="([^"]*)" name="([^"]*)" render_time_ms="([^"]*)">]]) |
52 | 117 |
|
| 118 | +function parse(buffer) |
| 119 | + local section, time, name, value = profilerPattern:match(buffer) |
| 120 | + if section then |
| 121 | + ltg:addSignalValue(section, name, tonumber(time), tonumber(value)) |
| 122 | + end |
53 | 123 | end |
54 | 124 | ``` |
55 | 125 |
|
56 | | -## Available Scripting Engine |
| 126 | +Console logging (visible in the in-app Messaging console): |
57 | 127 |
|
58 | | -LogToGraph can work with many plugins. |
| 128 | +```lua |
| 129 | +ltg:logInfo("...") ; ltg:logWarning("...") ; ltg:logError("...") ; ltg:logDebug("...") |
| 130 | +``` |
59 | 131 |
|
60 | | -- Lua |
61 | | -- maybe AngelScript inf ew times |
| 132 | +Row position (for progress / heuristics): |
62 | 133 |
|
63 | | -## Howto : Analyse of the log file in LogToGraph |
| 134 | +```lua |
| 135 | +ltg:getRowIndex() -- 0-based index within the current file |
| 136 | +ltg:getRowCount() -- total rows in the current file |
| 137 | +``` |
| 138 | + |
| 139 | +The Lua stdlib is curated for log-parsing: **base** (tostring / tonumber / pairs / pcall / setmetatable / ...), **string**, **math**, **table**, **os**, **jit**. `io` / `ffi` / `debug` / `package` / `coroutine` / `bit32` are NOT loaded — `io` and `ffi` are full sandbox escapes, `debug.sethook` would override the host's line hook, the rest are simply unused in a parsing context. |
64 | 140 |
|
65 | | -### Open a script and log file then analyse them |
| 141 | +## End-to-end walkthrough |
66 | 142 |
|
67 | | -1) open the app |
68 | | -2) in menu, click new |
69 | | -3) in the tool pane, you have three buttons |
70 | | -4) in the tool pane, select your lua script |
71 | | -5) in the tool pane, select your log file |
72 | | -6) in the tool pane, click on the analyse buttons |
| 143 | +### Open a log, write a script, analyse |
| 144 | + |
| 145 | +1. Launch the app. |
| 146 | +2. File → New Project. You land on the default boilerplate script with the full API documented in comments. |
| 147 | +3. ToolPane (left) → add one or more log files. |
| 148 | +4. Edit the Script pane to call `ltg:addSignalValue / addSignalStatus / addSignalTag` based on what each row looks like. Autocomplete + signature help guide you. |
| 149 | +5. ToolPane → click Analyse. The worker runs the script over every row of every file. |
| 150 | +6. Errors surface in the Console and on the editor's error markers; signals appear in the Graph pane. |
73 | 151 |
|
74 | 152 |  |
75 | 153 |
|
76 | | -### show graph of some signals, mouse over, log pane |
| 154 | +### Graph navigation |
77 | 155 |
|
78 | | -1) in the tool pane, expand some category |
79 | | -2) click on some signals |
80 | | -3) mouse over some signals to see infos of hovered timeframe |
81 | | -4) click on log pane title and explore it |
| 156 | +- **Mouse wheel** zooms in / out on a graph. |
| 157 | +- **Left drag** scrolls horizontally; all graphs are synchronized. |
| 158 | +- **Right drag** defines a custom time range. |
| 159 | +- **Right-click** opens a contextual menu (legend position, axis options, etc.). |
82 | 160 |
|
83 | | - |
| 161 | + |
84 | 162 |
|
85 | | -### group some signals on the same graph, modify signal color mode (auto rainbow or custom) |
| 163 | +### Show graph of selected signals, mouseover, log pane |
86 | 164 |
|
87 | | -1) in the group graph pane |
88 | | -2) on a signal row, select anpother group column. |
89 | | - each new comlumn except the gdef, will be group graph |
90 | | -3) click on a color button, and change the color of the signal. |
91 | | -4) then click back on the auto coloring nbutton in pane menu |
| 165 | +1. In the ToolPane expand a category. |
| 166 | +2. Click signal names to toggle their graphs on / off. |
| 167 | +3. Mouse over the curves to see the timeframe values in the Hovered List. |
| 168 | +4. Open the Log pane to scan the underlying ticks. |
92 | 169 |
|
93 | | - |
| 170 | + |
94 | 171 |
|
95 | | -### graph navigation |
| 172 | +### Group several signals on the same graph + recolor |
96 | 173 |
|
97 | | -1) mouse hover a graph |
98 | | -2) with the wheel button, zoom in |
99 | | -3) with the left mouse button, slide horizontally -you will see than all grpah are synchronized) |
100 | | -4) with the right mouse button, you can click and drag for define a custom time range |
101 | | -5) click right on it and a menu will appear, with it you can do many thing and by ex move the legend |
| 174 | +1. In the Group Graph pane, set the same group column on the rows you want grouped together. |
| 175 | +2. Click the color square next to a signal to override its color. |
| 176 | +3. Toggle the "auto coloring" in the pane menu to bring back the auto rainbow. |
102 | 177 |
|
103 | | - |
| 178 | + |
104 | 179 |
|
105 | | -### display a minimal view of all signals graph |
| 180 | +### All-signals minimal view |
106 | 181 |
|
107 | | -1) go in layout menu |
108 | | -2) select entry "all graph signals" |
109 | | -3) explore this new pane |
| 182 | +Layout menu → "all graph signals" — a compact wall of every signal at once. |
110 | 183 |
|
111 | 184 |  |
112 | 185 |
|
113 | | -### display a list of signal at the mouse hovered frametime |
| 186 | +### Hovered list at the mouse timeframe |
114 | 187 |
|
115 | | -1) go in layout menu |
116 | | -2) select entry "Signals Hovered List" |
117 | | -3) now go over signals with mouse and observe the "Signals Hovered List" pane change his values |
| 188 | +Layout menu → "Signals Hovered List" — every signal's value at the timeframe your mouse is over. |
118 | 189 |
|
119 | 190 |  |
120 | 191 |
|
121 | | -### display a diff list of signal between two frame time markers |
| 192 | +### Diff between two timeframe markers |
122 | 193 |
|
123 | | -1) go in layout menu |
124 | | -2) select entry "Signals Hovered Diff" |
125 | | -3) now mouse over a signal and press the key "f" like first, you will see a red vertical line, you can move it with mouse |
126 | | -3) move the mouse horizontally over a signal and press the key "s" like second, you will see a blue vertical line, you can move it with mouse |
127 | | -4) observe the pane "Signals Hovered Diff", you will see in it all signals who have change their value between the two markers |
128 | | -5) you can press the key "r" like reset, for remove the markers |
129 | | -6) you have a tip explaining this, in the graphs pane menu |
| 194 | +Layout menu → "Signals Hovered Diff", then over the graph press: |
| 195 | + |
| 196 | +- `f` — set the **first** marker (red vertical line) |
| 197 | +- `s` — set the **second** marker (blue vertical line) |
| 198 | +- `r` — reset |
| 199 | + |
| 200 | +The pane lists every signal whose value changed between the two markers. A tooltip in the Graph pane menu reminds you of the keys. |
130 | 201 |
|
131 | 202 |  |
132 | 203 |
|
133 | | -### measure delta time between two time marks |
| 204 | +### Delta-time annotations on a single graph |
134 | 205 |
|
135 | | -1) available only on alone graph |
136 | | -2) mouse hover a curve |
137 | | -3) when the cruve is thick, clik with the middle mouse button |
138 | | -4) then move the mouse on another part of the curve |
139 | | -5) when this new pos is thick too, click with the middle mouse ubtton agian |
140 | | -6) and you have a Annotation wiht the delta time. hte biggest unit is the day, the lowest the nano seconds. |
| 206 | +In a single-graph view, hover a curve until it thickens, **middle-click**, then move to another point on the curve and middle-click again. A delta-time annotation appears with the duration formatted from days down to nanoseconds. |
141 | 207 |
|
142 | | -for delete or see all your Annotations, open the layout menu, then click on Annotation Pane |
143 | | -then you have a list of all annotations per signal, then you can click on the cross on the left for delete what you want. |
| 208 | +Layout menu → "Annotation Pane" lists all annotations per signal and lets you delete them. |
144 | 209 |
|
145 | 210 |  |
146 | 211 |
|
147 | | -### save project file |
| 212 | +### Save / close project |
148 | 213 |
|
149 | | -1) got in menu then press on close item |
150 | | -2) a dialog appear in the center of the app |
151 | | -3) you can save the current proejct, save as a new project, continue without saving or cancel |
152 | | -4) the project is closed |
| 214 | +Project → Close (or app quit) opens a "save changes?" dialog: Save / Save As / Continue without saving / Cancel. The `.ltg` file is a SQLite DB containing the script, the parsed signals, your breakpoints, and the project settings. |
153 | 215 |
|
154 | | -you also have this dialog when you quit the app |
155 | | - |
156 | 216 |  |
157 | 217 |
|
158 | | -## Lua Parsing Api : |
| 218 | +## Supported scripting engines |
159 | 219 |
|
160 | | -```lua |
161 | | --- UserDatas ltg (LogToGraph valid only from LogToGraph) |
162 | | --- ltg:logInfo(infos_string) : will log the message in the in app console |
163 | | --- ltg:logWarning(infos_string) : will log the message in the in app console |
164 | | --- ltg:logError(infos_string) : will log the message in the in app console |
165 | | --- ltg:logDebug(infos_string) : will log the message in the in app console |
166 | | --- ltg:addSignalTag(date, r, g, b, a, name, help) : add a signal tag with date, color a name (color is linear [0:1]. the help will be displayed when mouse over the tag |
167 | | --- ltg:addSignalStatus(signal_category, signal_name, signal_epoch_time, signal_status) : will add a signal string status |
168 | | --- ltg:addSignalValue(signal_category, signal_name, signal_epoch_time, signal_value, description_string_optional) : will add a signal numerical value |
169 | | --- ltg:addSignalStartZone(signal_category, signal_name, signal_epoch_time, signal_string) : will add a signal start zone |
170 | | --- ltg:addSignalEndZone(signal_category, signal_name, signal_epoch_time, signal_string) : will add a signal end zone |
171 | | --- get/set epoch time from datetime in format "YYYY-MM-DD HH:MM:SS,MS" or "YYYY-MM-DD HH:MM:SS.MS" with hour offset in second param |
172 | | --- double ltg:stringToEpoch("2023-01-16 15:24:26,464", 0) |
173 | | --- string ltg:epochToString(18798798465465.546546, 0) |
174 | | -``` |
| 220 | +Currently: |
| 221 | + |
| 222 | +- **Lua** (LuaJIT 5.1 via [sol2](https://github.com/ThePhD/sol2) and [boost::regex](https://www.boost.org/doc/libs/release/libs/regex/) for the regex brick) — see [plugins/LuaScripting/README.md](plugins/LuaScripting/README.md). |
| 223 | + |
| 224 | +Planned: |
175 | 225 |
|
176 | | -## Limitations : |
| 226 | +- **AngelScript** — gated on the regex brick + debugger being solid (both are now). |
177 | 227 |
|
178 | | -1) The log file must be ascii file |
179 | | -2) You need opengl for using it, since the ui is a opengl based gui |
| 228 | +## Limitations |
180 | 229 |
|
181 | | -## Howto Build : |
| 230 | +1. Log files must be ASCII / UTF-8 text (no binary). |
| 231 | +2. OpenGL is required (the UI is OpenGL-based). |
182 | 232 |
|
183 | | -You need to use cMake. |
184 | | -For the 3 Os (Win, Linux, MacOs), the cMake usage is exactly the same, |
| 233 | +## Build |
185 | 234 |
|
186 | | -1) Choose a build directory. (called here my_build_directory for instance) and |
187 | | -2) Choose a Build Mode : "Release" / "MinSizeRel" / "RelWithDebInfo" / "Debug" (called here BuildMode for instance) |
188 | | -3) Run cMake in console : (the first for generate cmake build files, the second for build the binary) |
189 | | -```cpp |
| 235 | +You need CMake. The CMake usage is identical on Windows, Linux, and MacOS: |
| 236 | + |
| 237 | +1. Pick a build directory (`my_build_directory` here) and a build mode (`Release` / `MinSizeRel` / `RelWithDebInfo` / `Debug`). |
| 238 | +2. Generate + build: |
| 239 | + |
| 240 | +```sh |
190 | 241 | cmake -B my_build_directory -DCMAKE_BUILD_TYPE=BuildMode |
191 | 242 | cmake --build my_build_directory --config BuildMode |
192 | 243 | ``` |
193 | 244 |
|
194 | | -Some cMake version need Build mode define via the directive CMAKE_BUILD_TYPE or via --Config when we launch the build. |
195 | | -This is why i put the boths possibilities |
196 | | - |
197 | | -By the way you need before, to make sure, you have needed dependencies. |
| 245 | +Both `-DCMAKE_BUILD_TYPE=` and `--config` are provided because older CMake versions need one or the other. |
198 | 246 |
|
199 | | -### On Windows : |
| 247 | +Before that, make sure you have the dependencies installed. |
200 | 248 |
|
201 | | -You need to have the opengl library installed |
| 249 | +### On Windows |
202 | 250 |
|
203 | | -### On Linux : |
| 251 | +OpenGL libraries (system). |
204 | 252 |
|
205 | | -You need many lib : (X11, xrandr, xinerama, xcursor, mesa) |
| 253 | +### On Linux |
206 | 254 |
|
207 | | -If you are on debian you can run : |
| 255 | +X11, Xrandr, Xinerama, Xcursor, Mesa. On Debian-likes: |
208 | 256 |
|
209 | | -```cpp |
210 | | -sudo apt-get update |
| 257 | +```sh |
| 258 | +sudo apt-get update |
211 | 259 | sudo apt-get install libgl1-mesa-dev libx11-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev |
212 | 260 | ``` |
213 | 261 |
|
214 | | -### On MacOs : |
| 262 | +### On MacOS |
215 | 263 |
|
216 | | -you need many lib : opengl and cocoa framework |
| 264 | +OpenGL and Cocoa frameworks. |
0 commit comments