querysub 0.342.0 → 0.344.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.
- package/package.json +3 -2
- package/src/2-proxy/PathValueProxyWatcher.ts +2 -5
- package/src/3-path-functions/PathFunctionRunner.ts +1 -2
- package/src/3-path-functions/PathFunctionRunnerMain.ts +1 -1
- package/src/4-dom/qreact.tsx +1 -1
- package/src/diagnostics/logs/diskLogger.ts +11 -0
- package/src/diagnostics/logs/errorNotifications/errorDigestEmail.tsx +65 -6
- package/src/diagnostics/logs/errorNotifications/errorDigestEntry.tsx +9 -2
- package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +1 -1
- package/src/misc/cloneHelpers.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.344.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"test": "yarn typenode ./test.ts",
|
|
16
16
|
"test3": "yarn typenode ./src/test/test.tsx --local",
|
|
17
17
|
"test2": "yarn typenode ./src/4-dom/qreactTest.tsx --local",
|
|
18
|
-
"error-watch": "yarn typenode ./src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx"
|
|
18
|
+
"error-watch": "yarn typenode ./src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx",
|
|
19
|
+
"error-email": "yarn typenode ./src/diagnostics/logs/errorNotifications/errorDigestEntry.tsx"
|
|
19
20
|
},
|
|
20
21
|
"bin": {
|
|
21
22
|
"deploy": "./bin/deploy.js",
|
|
@@ -1071,7 +1071,7 @@ export class PathValueProxyWatcher {
|
|
|
1071
1071
|
let runLeeway = MAX_ACCEPTED_CHANGE_AGE * 0.8;
|
|
1072
1072
|
let runCutoffTime = Date.now() - runLeeway;
|
|
1073
1073
|
if (options.runAtTime && options.runAtTime.time < runCutoffTime) {
|
|
1074
|
-
let message = `MAX_CHANGE_AGE_EXCEEDED! Cannot run watcher at time ${options.runAtTime.time} because it is older than the cutOff time of ${runCutoffTime}. Writing this far in the past would break things, and might be rejected by other authorities due to being too old.`;
|
|
1074
|
+
let message = `MAX_CHANGE_AGE_EXCEEDED! Cannot run watcher ${options.debugName} at time ${options.runAtTime.time} because it is older than the cutOff time of ${runCutoffTime}. Writing this far in the past would break things, and might be rejected by other authorities due to being too old.`;
|
|
1075
1075
|
console.error(red(message));
|
|
1076
1076
|
// NOTE: We could also adjust the to be more recent, to allow it to be commited anyway,
|
|
1077
1077
|
// in a slightly different state than originally expected.
|
|
@@ -1181,9 +1181,6 @@ export class PathValueProxyWatcher {
|
|
|
1181
1181
|
};
|
|
1182
1182
|
const getReadyToCommit = () => {
|
|
1183
1183
|
let blocked = isProxyBlockedByOrder(watcher);
|
|
1184
|
-
if (blocked) {
|
|
1185
|
-
console.info(`Proxy ${watcher.debugName} is blocked by order`);
|
|
1186
|
-
}
|
|
1187
1184
|
return (
|
|
1188
1185
|
watcher.lastUnsyncedAccesses.size === 0
|
|
1189
1186
|
&& watcher.lastUnsyncedParentAccesses.size === 0
|
|
@@ -2419,7 +2416,7 @@ const finishProxyAndTriggerNext = runInSerial(
|
|
|
2419
2416
|
let next = proxiesOrdered[index];
|
|
2420
2417
|
// Only trigger if it's the first entry and therefore it won't be blocked by the previous proxy, or, of course, if it's from a timeout, In which case, it won't be blocked anyway.
|
|
2421
2418
|
if (next && (index === 0 || fromTimeout)) {
|
|
2422
|
-
console.info(`Triggering next proxy in order: ${next.debugName}`, next.options.baseFunction || next.options.watchFunction);
|
|
2419
|
+
//console.info(`Triggering next proxy in order: ${next.debugName}`, next.options.baseFunction || next.options.watchFunction);
|
|
2423
2420
|
next.explicitlyTrigger({
|
|
2424
2421
|
newParentsSynced: new Set(),
|
|
2425
2422
|
pathSources: new Set(),
|
|
@@ -520,7 +520,6 @@ export class PathFunctionRunner {
|
|
|
520
520
|
runCount++;
|
|
521
521
|
if (PathFunctionRunner.DEBUG_CALLS) {
|
|
522
522
|
console.log(`Evaluating (try count ${runCount}) ${getDebugName(callPath, functionSpec, true)}`);
|
|
523
|
-
console.log(` RUNNING AT REAL TIME ${debugTime(proxyWatcher.getTriggeredWatcher().currentReadTime || callPath.runAtTime)}`);
|
|
524
523
|
}
|
|
525
524
|
if (PathFunctionRunner.DEBUG_CALL_TRIGGERS && runCount > PathFunctionRunner.DEBUG_WATCHES_THRESHOLD) {
|
|
526
525
|
// NOTE: If this happens a few times during initial loading it is fine. If it happens a lot... and with values MUCH
|
|
@@ -672,7 +671,7 @@ export class PathFunctionRunner {
|
|
|
672
671
|
}
|
|
673
672
|
|
|
674
673
|
if (PathFunctionRunner.DEBUG_CALLS) {
|
|
675
|
-
console.log(`FINISHED${nooped ? " (skipped)" : ""} ${getDebugName(callPath, functionSpec, true)}, writes: ${finalWrites?.length}`);
|
|
674
|
+
console.log(`FINISHED${nooped ? " (skipped)" : ""} ${getDebugName(callPath, functionSpec, true)}, writes: ${finalWrites?.length}, took ${blue(formatTime(Date.now() - startTime))}`);
|
|
676
675
|
}
|
|
677
676
|
|
|
678
677
|
let wallTime = Date.now() - startTime;
|
|
@@ -30,7 +30,7 @@ async function main() {
|
|
|
30
30
|
//ActionsHistory.LOG_ACTION_HISTORY = "runner";
|
|
31
31
|
|
|
32
32
|
// ClientWatcher.DEBUG_READS = true;
|
|
33
|
-
ClientWatcher.DEBUG_WRITES = true;
|
|
33
|
+
//ClientWatcher.DEBUG_WRITES = true;
|
|
34
34
|
// ClientWatcher.DEBUG_TRIGGERS = "heavy";
|
|
35
35
|
// authorityStorage.DEBUG_UNWATCH = true;
|
|
36
36
|
|
package/src/4-dom/qreact.tsx
CHANGED
|
@@ -2436,7 +2436,7 @@ export function getSourceVSCodeLink(element: DOMNode | undefined) {
|
|
|
2436
2436
|
Command palette: You can trigger VS Code commands using vscode://file/{file}?command={commandId}.
|
|
2437
2437
|
Extensions: Some VS Code extensions may add support for additional URL parameters.
|
|
2438
2438
|
*/
|
|
2439
|
-
let path = `cursor://file
|
|
2439
|
+
let path = `cursor://file${new URL(sourceInfo.sourceFileName).pathname}`;
|
|
2440
2440
|
if (sourceInfo.lineNumber) {
|
|
2441
2441
|
path += `:${sourceInfo.lineNumber}:${sourceInfo.columnNumber}`;
|
|
2442
2442
|
path += `?selection=${sourceInfo.lineNumber},${sourceInfo.columnNumber}`;
|
|
@@ -40,10 +40,21 @@ export type LogDatum = Record<string, unknown> & {
|
|
|
40
40
|
export function getLogHash(obj: LogDatum) {
|
|
41
41
|
return getPathStr2(obj.__threadId || "", obj.time.toString());
|
|
42
42
|
}
|
|
43
|
+
const errorMessageFileRegex = /\n at .+?\(([^:]+):\d+:\d+\)/;
|
|
44
|
+
|
|
43
45
|
export function getLogFile(obj: LogDatum) {
|
|
44
46
|
let logType = obj.param0 || "";
|
|
45
47
|
if (obj.__FILE__) {
|
|
46
48
|
logType = String(obj.__FILE__);
|
|
49
|
+
// /root/machine-services/*/git/
|
|
50
|
+
if (logType.startsWith("/root/machine-services/")) {
|
|
51
|
+
logType = logType.split("/").slice(4).join("/");
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
let match = logType.match(errorMessageFileRegex);
|
|
55
|
+
if (match) {
|
|
56
|
+
logType = match[1];
|
|
57
|
+
}
|
|
47
58
|
}
|
|
48
59
|
if (obj[LOG_LINE_LIMIT_ID]) {
|
|
49
60
|
logType += "::" + String(obj[LOG_LINE_LIMIT_ID]);
|
|
@@ -23,6 +23,14 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
let errors: {
|
|
26
|
+
file: string;
|
|
27
|
+
errorsInFile: number;
|
|
28
|
+
warningsInFile: number;
|
|
29
|
+
message: string;
|
|
30
|
+
messageTime: string;
|
|
31
|
+
}[] = [];
|
|
32
|
+
let warnings: {
|
|
33
|
+
file: string;
|
|
26
34
|
errorsInFile: number;
|
|
27
35
|
warningsInFile: number;
|
|
28
36
|
message: string;
|
|
@@ -38,6 +46,8 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
38
46
|
let corruptWarning = "";
|
|
39
47
|
|
|
40
48
|
let failingFiles = 0;
|
|
49
|
+
let errorFiles = 0;
|
|
50
|
+
let warningFiles = 0;
|
|
41
51
|
|
|
42
52
|
for (let value of digestInfo.histogram.values()) {
|
|
43
53
|
errorCount += value.unsuppressedErrors;
|
|
@@ -52,25 +62,44 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
52
62
|
if (value.firstCorruptWarning && !corruptWarning) {
|
|
53
63
|
corruptWarning = value.firstCorruptWarning;
|
|
54
64
|
}
|
|
55
|
-
if (value.unsuppressedErrors > 0) {
|
|
56
|
-
failingFiles++;
|
|
57
|
-
}
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
for (let value of digestInfo.byFile
|
|
67
|
+
for (let [file, value] of digestInfo.byFile) {
|
|
61
68
|
for (let error of value.latestErrors.slice(-MAX_COUNT_PER_FILE)) {
|
|
62
69
|
errors.push({
|
|
70
|
+
file,
|
|
63
71
|
errorsInFile: value.errors,
|
|
64
72
|
warningsInFile: value.warnings,
|
|
65
73
|
message: `${error.param0} (${error.__NAME__})`,
|
|
66
74
|
messageTime: formatDateTime(error.time),
|
|
67
75
|
});
|
|
68
76
|
}
|
|
77
|
+
|
|
78
|
+
for (let warning of value.latestWarnings.slice(-MAX_COUNT_PER_FILE)) {
|
|
79
|
+
warnings.push({
|
|
80
|
+
file,
|
|
81
|
+
errorsInFile: value.errors,
|
|
82
|
+
warningsInFile: value.warnings,
|
|
83
|
+
message: `${warning.param0} (${warning.__NAME__})`,
|
|
84
|
+
messageTime: formatDateTime(warning.time),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (value.errors > 0) {
|
|
89
|
+
failingFiles++;
|
|
90
|
+
errorFiles++;
|
|
91
|
+
}
|
|
92
|
+
if (value.warnings > 0) {
|
|
93
|
+
warningFiles++;
|
|
94
|
+
}
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
sort(errors, x => -x.errorsInFile);
|
|
72
98
|
errors = errors.slice(0, MAX_COUNT);
|
|
73
99
|
|
|
100
|
+
sort(warnings, x => -x.warningsInFile);
|
|
101
|
+
warnings = warnings.slice(0, MAX_COUNT);
|
|
102
|
+
|
|
74
103
|
let link = createLink([
|
|
75
104
|
showingManagementURL.getOverride(true),
|
|
76
105
|
managementPageURL.getOverride("ErrorDigestPage"),
|
|
@@ -81,7 +110,7 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
81
110
|
await sendEmail({
|
|
82
111
|
to: notifyEmails,
|
|
83
112
|
fromPrefix: "error-digest",
|
|
84
|
-
subject: `${errorCount} err |
|
|
113
|
+
subject: `${errorCount} err | ~${formatNumber(failingFiles)} lines | ${warningCount} warn${corruptErrors + corruptWarnings > 0 ? ` | ${corruptErrors + corruptWarnings} corrupt` : ""} | ${suppressedErrors + suppressedWarnings} hid | ${formatTime(digestInfo.scanDuration)} | ${formatNumber(digestInfo.totalUncompressedBytes)} | ${formatNumber(digestInfo.totalFiles)} log files`,
|
|
85
114
|
contents: <div>
|
|
86
115
|
<h2>Error Summary</h2>
|
|
87
116
|
<ul style="list-style-type: none; padding-left: 0;">
|
|
@@ -89,12 +118,14 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
89
118
|
<strong style="color: #dc3545;">Errors:</strong>
|
|
90
119
|
<span style="background-color: #dc3545; color: white; padding: 2px 6px; border-radius: 3px; font-weight: bold; margin-left: 8px;">{errorCount}</span>
|
|
91
120
|
<span style="color: #dc3545;"> unsuppressed</span>
|
|
121
|
+
<span style="color: #6c757d; margin-left: 8px;">({formatNumber(errorFiles)} files)</span>
|
|
92
122
|
{suppressedErrors > 0 && <span>, <span style="color: #6c757d;">{formatNumber(suppressedErrors)} suppressed</span></span>}
|
|
93
123
|
</li>
|
|
94
124
|
<li>
|
|
95
125
|
<strong style="color: #fd7e14;">Warnings:</strong>
|
|
96
126
|
<span style="background-color: #fd7e14; color: white; padding: 2px 6px; border-radius: 3px; font-weight: bold; margin-left: 8px;">{warningCount}</span>
|
|
97
127
|
<span style="color: #fd7e14;"> unsuppressed</span>
|
|
128
|
+
<span style="color: #6c757d; margin-left: 8px;">({formatNumber(warningFiles)} files)</span>
|
|
98
129
|
{suppressedWarnings > 0 && <span>, <span style="color: #6c757d;">{formatNumber(suppressedWarnings)} suppressed</span></span>}
|
|
99
130
|
</li>
|
|
100
131
|
</ul>
|
|
@@ -147,11 +178,12 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
147
178
|
<a href={link} style="display: block; margin-bottom: 20px; padding: 10px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; text-align: center;">View live logs</a>
|
|
148
179
|
|
|
149
180
|
{errors.length > 0 && <div>
|
|
150
|
-
<h2 style="color: #495057;">Recent Errors (<span style="color: #dc3545; font-weight: bold;">{errors.length}</span> shown)</h2>
|
|
181
|
+
<h2 style="color: #495057;">Recent Errors (<span style="color: #dc3545; font-weight: bold;">{errors.length}</span> files shown, <span style="color: #dc3545; font-weight: bold;">{errors.reduce((acc, error) => acc + error.errorsInFile, 0)}</span> errors)</h2>
|
|
151
182
|
<table style="border-collapse: collapse; width: 100%; margin-top: 10px;">
|
|
152
183
|
<thead>
|
|
153
184
|
<tr style="background-color: #495057; color: white;">
|
|
154
185
|
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">Time</th>
|
|
186
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">File</th>
|
|
155
187
|
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">Message</th>
|
|
156
188
|
<th style="border: 1px solid #6c757d; padding: 8px; text-align: right; background-color: #dc3545;">Errors in File</th>
|
|
157
189
|
<th style="border: 1px solid #6c757d; padding: 8px; text-align: right; background-color: #fd7e14;">Warnings in File</th>
|
|
@@ -161,6 +193,7 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
161
193
|
{errors.map((error, index) => (
|
|
162
194
|
<tr key={index} style={`background-color: ${index % 2 === 0 ? "#f8f9fa" : "white"}`}>
|
|
163
195
|
<td style="border: 1px solid #ddd; padding: 8px;">{error.messageTime}</td>
|
|
196
|
+
<td style="border: 1px solid #ddd; padding: 8px; font-family: monospace; font-size: 12px;">{error.file}</td>
|
|
164
197
|
<td style="border: 1px solid #ddd; padding: 8px;">{error.message}</td>
|
|
165
198
|
<td style="border: 1px solid #ddd; padding: 8px; text-align: right; background-color: #f8d7da; color: #721c24; font-weight: bold;">{error.errorsInFile}</td>
|
|
166
199
|
<td style="border: 1px solid #ddd; padding: 8px; text-align: right; background-color: #fff3cd; color: #856404; font-weight: bold;">{error.warningsInFile}</td>
|
|
@@ -169,6 +202,32 @@ export async function sendErrorDigestEmail(digestInfo: ErrorDigestInfo) {
|
|
|
169
202
|
</tbody>
|
|
170
203
|
</table>
|
|
171
204
|
</div>}
|
|
205
|
+
|
|
206
|
+
{warnings.length > 0 && <div style="margin-top: 20px;">
|
|
207
|
+
<h2 style="color: #495057;">Recent Warnings (<span style="color: #fd7e14; font-weight: bold;">{warnings.length}</span> files shown, <span style="color: #fd7e14; font-weight: bold;">{warnings.reduce((acc, warning) => acc + warning.warningsInFile, 0)}</span> warnings)</h2>
|
|
208
|
+
<table style="border-collapse: collapse; width: 100%; margin-top: 10px;">
|
|
209
|
+
<thead>
|
|
210
|
+
<tr style="background-color: #495057; color: white;">
|
|
211
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">Time</th>
|
|
212
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">File</th>
|
|
213
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: left;">Message</th>
|
|
214
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: right; background-color: #dc3545;">Errors in File</th>
|
|
215
|
+
<th style="border: 1px solid #6c757d; padding: 8px; text-align: right; background-color: #fd7e14;">Warnings in File</th>
|
|
216
|
+
</tr>
|
|
217
|
+
</thead>
|
|
218
|
+
<tbody>
|
|
219
|
+
{warnings.map((warning, index) => (
|
|
220
|
+
<tr key={index} style={`background-color: ${index % 2 === 0 ? "#f8f9fa" : "white"}`}>
|
|
221
|
+
<td style="border: 1px solid #ddd; padding: 8px;">{warning.messageTime}</td>
|
|
222
|
+
<td style="border: 1px solid #ddd; padding: 8px; font-family: monospace; font-size: 12px;">{warning.file}</td>
|
|
223
|
+
<td style="border: 1px solid #ddd; padding: 8px;">{warning.message}</td>
|
|
224
|
+
<td style="border: 1px solid #ddd; padding: 8px; text-align: right; background-color: #f8d7da; color: #721c24; font-weight: bold;">{warning.errorsInFile}</td>
|
|
225
|
+
<td style="border: 1px solid #ddd; padding: 8px; text-align: right; background-color: #fff3cd; color: #856404; font-weight: bold;">{warning.warningsInFile}</td>
|
|
226
|
+
</tr>
|
|
227
|
+
))}
|
|
228
|
+
</tbody>
|
|
229
|
+
</table>
|
|
230
|
+
</div>}
|
|
172
231
|
</div>,
|
|
173
232
|
});
|
|
174
233
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Querysub } from "../../../4-querysub/QuerysubController";
|
|
2
|
+
import { runDigest, runDigestLoop } from "./errorDigests";
|
|
2
3
|
|
|
3
4
|
async function main() {
|
|
4
|
-
|
|
5
|
+
if (process.argv.includes("--now")) {
|
|
6
|
+
await Querysub.hostService("error-digests-now");
|
|
7
|
+
|
|
8
|
+
await runDigest();
|
|
9
|
+
} else {
|
|
10
|
+
await runDigestLoop();
|
|
11
|
+
}
|
|
5
12
|
}
|
|
6
13
|
// The digest loop should never exit, and if it does, we probably want to terminate ourselves so that the service manager will restart us, hopefully putting us back in a good state.
|
|
7
14
|
main().catch(console.error).finally(() => process.exit());
|
|
@@ -92,7 +92,7 @@ function getClosest(value: number, choices: number[]) {
|
|
|
92
92
|
return closest;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
async function runDigest() {
|
|
95
|
+
export async function runDigest() {
|
|
96
96
|
console.log("Running error digest gathering");
|
|
97
97
|
// Find the previous day
|
|
98
98
|
let endTime = getClosest(
|
package/src/misc/cloneHelpers.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import cborx from "cbor-x";
|
|
2
2
|
import { lazy } from "socket-function/src/caching";
|
|
3
|
-
const cborxInstance = lazy(() => new cborx.Encoder({
|
|
3
|
+
const cborxInstance = lazy(() => new cborx.Encoder({
|
|
4
|
+
structuredClone: true,
|
|
5
|
+
|
|
6
|
+
}));
|
|
4
7
|
export function deepCloneCborx<T>(value: T): T {
|
|
5
8
|
return decodeCborx(encodeCborx(value));
|
|
6
9
|
}
|