querysub 0.374.0 → 0.376.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package.json +2 -4
  2. package/src/deployManager/components/MachineDetailPage.tsx +2 -5
  3. package/src/deployManager/components/ServiceDetailPage.tsx +2 -5
  4. package/src/deployManager/machineApplyMainCode.ts +7 -0
  5. package/src/diagnostics/NodeViewer.tsx +4 -5
  6. package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +10 -5
  7. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +20 -0
  8. package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +29 -2
  9. package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +61 -20
  10. package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +2 -2
  11. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +7 -7
  12. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +250 -243
  13. package/src/diagnostics/logs/IndexedLogs/LogViewerParams.ts +21 -0
  14. package/src/diagnostics/logs/IndexedLogs/{bufferMatcher.ts → bufferSearchFindMatcher.ts} +9 -4
  15. package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +3 -3
  16. package/src/diagnostics/logs/diskLogger.ts +0 -38
  17. package/src/diagnostics/logs/errorNotifications2/errorNotifications2.ts +9 -0
  18. package/src/diagnostics/logs/injectFileLocationToConsole.ts +3 -0
  19. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +24 -22
  20. package/src/diagnostics/managementPages.tsx +0 -18
  21. package/test.ts +0 -5
  22. package/bin/error-email.js +0 -8
  23. package/bin/error-im.js +0 -8
  24. package/src/diagnostics/logs/FastArchiveAppendable.ts +0 -843
  25. package/src/diagnostics/logs/FastArchiveController.ts +0 -573
  26. package/src/diagnostics/logs/FastArchiveViewer.tsx +0 -1090
  27. package/src/diagnostics/logs/LogViewer2.tsx +0 -552
  28. package/src/diagnostics/logs/errorNotifications/ErrorDigestPage.tsx +0 -409
  29. package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +0 -756
  30. package/src/diagnostics/logs/errorNotifications/ErrorSuppressionUI.tsx +0 -280
  31. package/src/diagnostics/logs/errorNotifications/ErrorWarning.tsx +0 -254
  32. package/src/diagnostics/logs/errorNotifications/errorDigestEmail.tsx +0 -233
  33. package/src/diagnostics/logs/errorNotifications/errorDigestEntry.tsx +0 -14
  34. package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +0 -292
  35. package/src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx +0 -209
  36. package/src/diagnostics/logs/importLogsEntry.ts +0 -38
  37. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +0 -150
  38. package/src/diagnostics/logs/logViewerExtractField.ts +0 -36
@@ -1,409 +0,0 @@
1
- module.noserverhotreload = false;
2
- module.hotreload = true;
3
-
4
-
5
- import { SocketFunction } from "socket-function/SocketFunction";
6
- import { qreact } from "../../../4-dom/qreact";
7
- import { getSyncedController } from "../../../library-components/SyncedController";
8
- import { ErrorDigestController, errorDigestHistory, ErrorDigestInfo } from "./errorDigests";
9
- import { isManagementUser } from "../../../-0-hooks/hooks";
10
- import { assertIsManagementUser } from "../../managementPages";
11
- import { URLParam } from "../../../library-components/URLParam";
12
- import { tabURL } from "../../../library-components/urlResetGroups";
13
- import { Anchor, ATag } from "../../../library-components/ATag";
14
- import { css } from "../../../4-dom/css";
15
- import { list, sort } from "socket-function/src/misc";
16
- import { formatDateTime, formatVeryNiceDateTime, formatNumber } from "socket-function/src/formatting/format";
17
- import { Table } from "../../../5-diagnostics/Table";
18
- import { Histogram } from "../../../library-components/Histogram";
19
- import { TabbedUI } from "../../../library-components/TabbedUI";
20
- import { LogDatum } from "../diskLogger";
21
- import { t } from "../../../2-proxy/schema2";
22
- import { getErrorLogsLink } from "./ErrorWarning";
23
-
24
- export const digestKeyURL = new URLParam("digestKey", "");
25
- export const fileDetailTabURL = new URLParam("fileDetailTab", "errors");
26
-
27
- export class ErrorDigestPage extends qreact.Component {
28
- state = t.state({
29
- selectedFile: t.string("")
30
- });
31
- render() {
32
- // Get the current tab mode
33
- let currentTab = tabURL.value;
34
- let selectedDigestKey = digestKeyURL.value;
35
-
36
- if (currentTab === "detail" && selectedDigestKey) {
37
- return this.renderDigestDetail(selectedDigestKey);
38
- }
39
-
40
- return this.renderDigestList();
41
- }
42
-
43
- renderDigestList() {
44
- let controller = ErrorDigestController(SocketFunction.browserNodeId());
45
-
46
- let keys = controller.getDigestKeys();
47
-
48
- if (!keys || keys.length === 0) {
49
- return (
50
- <div className={css.vbox(16).pad2(24)}>
51
- <div className={css.fontSize(24).fontWeight(600)}>
52
- Error Digest History
53
- </div>
54
- <div>No digest data available</div>
55
- </div>
56
- );
57
- }
58
-
59
- // Sort lexicographically (highest = newest) and take latest 100
60
- let sortedKeys = sort(keys as string[], key => key).reverse().slice(0, 100);
61
-
62
- return (
63
- <div className={css.vbox(16).paddingTop(24).paddingLeft(24).fillHeight.fillWidth}>
64
- <div className={css.fontSize(24).fontWeight(600)}>
65
- Error Digest History
66
- </div>
67
- <div className={css.fontSize(14).color("gray")}>
68
- Showing latest {Math.min(sortedKeys.length, 100)} digests (sorted by creation time, newest first)
69
- </div>
70
-
71
- <div className={css.vbox(8).overflowAuto.fillWidth}>
72
- {sortedKeys.map(key => (
73
- <ATag
74
- key={key}
75
- values={[
76
- tabURL.getOverride("detail"),
77
- digestKeyURL.getOverride(key)
78
- ]}
79
- className={css.pad2(12).hsla(0, 0, 0, 0.1).pointer.hslahover(0, 0, 0, 0.15)}
80
- >
81
- {formatVeryNiceDateTime(+key.split(".")[0])}
82
- </ATag>
83
- ))}
84
- </div>
85
- </div>
86
- );
87
- }
88
-
89
- renderDigestDetail(digestKey: string) {
90
- let controller = ErrorDigestController(SocketFunction.browserNodeId());
91
-
92
- let digestData = controller.getDigest(digestKey);
93
-
94
- if (!digestData) {
95
- return (
96
- <div className={css.vbox(16).pad2(24)}>
97
- <div className={css.hbox(16)}>
98
- <ATag
99
- values={[
100
- tabURL.getOverride(""),
101
- digestKeyURL.getOverride("")
102
- ]}
103
- >
104
- ← Back to Digest List
105
- </ATag>
106
- </div>
107
- <div>Loading digest data...</div>
108
- </div>
109
- );
110
- }
111
-
112
- // If a file is selected, show file details
113
- if (this.state.selectedFile) {
114
- return this.renderFileDetail(digestData, digestKey);
115
- }
116
-
117
- return (
118
- <div className={css.vbox(24).pad2(24).fillHeight.overflowAuto}>
119
- {/* Header */}
120
- <div className={css.hbox(16).alignItems("center")}>
121
- <ATag
122
- values={[
123
- tabURL.getOverride(""),
124
- digestKeyURL.getOverride("")
125
- ]}
126
- >
127
- ← Back to Digest List
128
- </ATag>
129
- <div className={css.fontSize(24).fontWeight(600)}>
130
- Digest: {formatVeryNiceDateTime(+digestKey.split(".")[0])}
131
- </div>
132
- </div>
133
-
134
- <Anchor
135
- className={css.fontSize(24)}
136
- values={getErrorLogsLink({
137
- startTime: digestData.startTime,
138
- endTime: digestData.endTime,
139
- })}
140
- >
141
- View live logs
142
- </Anchor>
143
-
144
- {/* Metadata Section */}
145
- {this.renderMetadata(digestData)}
146
-
147
- {/* Charts Section */}
148
- {this.renderCharts(digestData)}
149
-
150
- {/* Files Table */}
151
- {this.renderFilesTable(digestData)}
152
- </div>
153
- );
154
- }
155
-
156
- renderMetadata(digestData: ErrorDigestInfo) {
157
- return (
158
- <div className={css.vbox(16)}>
159
- <div className={css.fontSize(20).fontWeight(600)}>Metadata</div>
160
- <div className={css.hbox(32).wrap}>
161
- <div className={css.vbox(4)}>
162
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Compressed Bytes</div>
163
- <div className={css.fontSize(16).fontWeight(500)}>
164
- {formatNumber(digestData.totalCompressedBytes)}
165
- </div>
166
- </div>
167
- <div className={css.vbox(4)}>
168
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Uncompressed Bytes</div>
169
- <div className={css.fontSize(16).fontWeight(500)}>
170
- {formatNumber(digestData.totalUncompressedBytes)}
171
- </div>
172
- </div>
173
- <div className={css.vbox(4)}>
174
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Total Files</div>
175
- <div className={css.fontSize(16).fontWeight(500)}>
176
- {formatNumber(digestData.totalFiles)}
177
- </div>
178
- </div>
179
- <div className={css.vbox(4)}>
180
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Scan Duration</div>
181
- <div className={css.fontSize(16).fontWeight(500)}>
182
- {formatNumber(digestData.scanDuration)}ms
183
- </div>
184
- </div>
185
- <div className={css.vbox(4)}>
186
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Start Time</div>
187
- <div className={css.fontSize(16).fontWeight(500)}>
188
- {formatVeryNiceDateTime(digestData.startTime)}
189
- </div>
190
- </div>
191
- <div className={css.vbox(4)}>
192
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>End Time</div>
193
- <div className={css.fontSize(16).fontWeight(500)}>
194
- {formatVeryNiceDateTime(digestData.endTime)}
195
- </div>
196
- </div>
197
- </div>
198
- </div>
199
- );
200
- }
201
-
202
- renderCharts(digestData: ErrorDigestInfo) {
203
- // Convert histogram data to chart data
204
- let unsuppressedErrorsData: { x: number; y: number }[] = [];
205
- let unsuppressedWarningsData: { x: number; y: number }[] = [];
206
- let corruptData: { x: number; y: number }[] = [];
207
- let suppressedData: { x: number; y: number }[] = [];
208
-
209
- for (let [time, data] of digestData.histogram.entries()) {
210
- unsuppressedErrorsData.push({ x: time, y: data.unsuppressedErrors });
211
- unsuppressedWarningsData.push({ x: time, y: data.unsuppressedWarnings });
212
- corruptData.push({ x: time, y: data.corruptErrors + data.corruptWarnings });
213
- suppressedData.push({ x: time, y: data.suppressedErrors + data.suppressedWarnings });
214
- }
215
-
216
- return (
217
- <div className={css.vbox(16)}>
218
- <div className={css.fontSize(20).fontWeight(600)}>Error Distribution Over Time</div>
219
- <div className={css.vbox(16)}>
220
- <div className={css.hbox(16).wrap}>
221
- <div className={css.fillWidth.minWidth(400).height(300)}>
222
- <Histogram
223
- title="Unsuppressed Errors"
224
- values={unsuppressedErrorsData}
225
- xColumn={{
226
- title: "Time",
227
- format: (value) => formatDateTime(value)
228
- }}
229
- yColumn={{ title: "Count" }}
230
- />
231
- </div>
232
- <div className={css.fillWidth.minWidth(400).height(300)}>
233
- <Histogram
234
- title="Unsuppressed Warnings"
235
- values={unsuppressedWarningsData}
236
- xColumn={{
237
- title: "Time",
238
- format: (value) => formatDateTime(value)
239
- }}
240
- yColumn={{ title: "Count" }}
241
- />
242
- </div>
243
- </div>
244
- <div className={css.hbox(16).wrap}>
245
- <div className={css.fillWidth.minWidth(400).height(300)}>
246
- <Histogram
247
- title="Corrupt Errors + Warnings"
248
- values={corruptData}
249
- xColumn={{
250
- title: "Time",
251
- format: (value) => formatDateTime(value)
252
- }}
253
- yColumn={{ title: "Count" }}
254
- />
255
- </div>
256
- <div className={css.fillWidth.minWidth(400).height(300)}>
257
- <Histogram
258
- title="Suppressed Errors + Warnings"
259
- values={suppressedData}
260
- xColumn={{
261
- title: "Time",
262
- format: (value) => formatDateTime(value)
263
- }}
264
- yColumn={{ title: "Count" }}
265
- />
266
- </div>
267
- </div>
268
- </div>
269
- </div>
270
- );
271
- }
272
-
273
- renderFilesTable(digestData: ErrorDigestInfo) {
274
- // Convert byFile map to table rows
275
- let fileRows = Array.from(digestData.byFile.entries()).map(([fileName, fileData]) => {
276
- let latestError = fileData.latestErrors[fileData.latestErrors.length - 1];
277
- let latestWarning = fileData.latestWarnings[fileData.latestWarnings.length - 1];
278
- let latestLog = latestError ?? latestWarning;
279
-
280
- return {
281
- fileName,
282
- errorCount: fileData.errors,
283
- warningCount: fileData.warnings,
284
- latestMessage: latestLog?.param0 ?? "No messages",
285
- latestTime: latestLog?.time ?? 0
286
- };
287
- });
288
-
289
- // Sort by error count descending
290
- fileRows = sort(fileRows, row => row.errorCount).reverse();
291
-
292
- return (
293
- <div className={css.vbox(16)}>
294
- <div className={css.fontSize(20).fontWeight(600)}>Files ({fileRows.length} files)</div>
295
- <Table
296
- columns={{
297
- fileName: { title: "File Name" },
298
- errorCount: { title: "Errors" },
299
- warningCount: { title: "Warnings" },
300
- latestMessage: {
301
- title: "Latest Message",
302
- formatter: (value: any) => String(value).slice(0, 100) + (String(value).length > 100 ? "..." : "")
303
- }
304
- }}
305
- rows={fileRows}
306
- getRowAttributes={(row: any) => ({
307
- className: css.cursor("pointer").hslhover(210, 20, 95),
308
- onClick: () => {
309
- this.state.selectedFile = row.fileName;
310
- }
311
- })}
312
- />
313
- </div>
314
- );
315
- }
316
-
317
- renderFileDetail(digestData: ErrorDigestInfo, digestKey: string) {
318
- let selectedFileName = this.state.selectedFile;
319
- let fileData = digestData.byFile.get(selectedFileName);
320
-
321
- if (!fileData) {
322
- return (
323
- <div className={css.vbox(16).pad2(24)}>
324
- <div>File not found</div>
325
- </div>
326
- );
327
- }
328
-
329
- return (
330
- <div className={css.vbox(24).pad2(24).fillHeight}>
331
- {/* Header with back button */}
332
- <div className={css.hbox(16).alignItems("center")}>
333
- <ATag
334
- clickOverride={() => {
335
- this.state.selectedFile = "";
336
- }}
337
- className={css.cursor("pointer")}
338
- >
339
- ← Back to Files Table
340
- </ATag>
341
- <div className={css.fontSize(20).fontWeight(600)}>
342
- {selectedFileName}
343
- </div>
344
- </div>
345
-
346
- {/* File stats */}
347
- <div className={css.hbox(32)}>
348
- <div className={css.vbox(4)}>
349
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Errors</div>
350
- <div className={css.fontSize(16).fontWeight(500)}>{fileData.errors}</div>
351
- </div>
352
- <div className={css.vbox(4)}>
353
- <div className={css.fontSize(14).colorhsl(0, 0, 60)}>Warnings</div>
354
- <div className={css.fontSize(16).fontWeight(500)}>{fileData.warnings}</div>
355
- </div>
356
- </div>
357
-
358
- {/* Tabbed interface for errors/warnings */}
359
- <div className={css.fillHeight.overflowHidden}>
360
- <TabbedUI
361
- tab={fileDetailTabURL}
362
- tabs={[
363
- {
364
- value: "errors",
365
- title: `Errors (${fileData.errors})`,
366
- contents: this.renderLogEntries(fileData.latestErrors, "errors")
367
- },
368
- {
369
- value: "warnings",
370
- title: `Warnings (${fileData.warnings})`,
371
- contents: this.renderLogEntries(fileData.latestWarnings, "warnings")
372
- }
373
- ]}
374
- />
375
- </div>
376
- </div>
377
- );
378
- }
379
-
380
- renderLogEntries(logs: LogDatum[], type: "errors" | "warnings") {
381
- if (logs.length === 0) {
382
- return <div className={css.colorhsl(0, 0, 60)}>No {type} found</div>;
383
- }
384
-
385
- let tableRows = logs.map((log, index) => ({
386
- index: logs.length - index,
387
- time: formatVeryNiceDateTime(log.time),
388
- message: log.param0 ?? "No message",
389
- threadId: log.__threadId ?? "Unknown",
390
- name: log.__NAME__ ?? "Unknown"
391
- }));
392
-
393
- return (
394
- <div className={css.fillHeight.overflowAuto}>
395
- <Table
396
- columns={{
397
- index: { title: "#" },
398
- time: { title: "Time" },
399
- name: { title: "Source" },
400
- threadId: { title: "Thread" },
401
- message: { title: "Message" }
402
- }}
403
- rows={tableRows}
404
- initialLimit={50}
405
- />
406
- </div>
407
- );
408
- }
409
- }