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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.342.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
 
@@ -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/${sourceInfo.sourceFileName}`;
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.values()) {
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 | >= ${formatNumber(failingFiles)} lines | ${warningCount} warn${corruptErrors + corruptWarnings > 0 ? ` | ${corruptErrors + corruptWarnings} corrupt` : ""} | ${suppressedErrors + suppressedWarnings} suppressed | ${formatTime(digestInfo.scanDuration)} | ${formatNumber(digestInfo.totalCompressedBytes)} / ${formatNumber(digestInfo.totalUncompressedBytes)} | ${formatNumber(digestInfo.totalFiles)} log files`,
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 { runDigestLoop } from "./errorDigests";
1
+ import { Querysub } from "../../../4-querysub/QuerysubController";
2
+ import { runDigest, runDigestLoop } from "./errorDigests";
2
3
 
3
4
  async function main() {
4
- await runDigestLoop();
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(
@@ -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({ structuredClone: true }));
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
  }