querysub 0.374.0 → 0.375.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 (33) 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/BufferIndexHelpers.ts +1 -1
  7. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +7 -7
  8. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +221 -220
  9. package/src/diagnostics/logs/IndexedLogs/LogViewerParams.ts +21 -0
  10. package/src/diagnostics/logs/IndexedLogs/bufferMatcher.ts +3 -3
  11. package/src/diagnostics/logs/diskLogger.ts +0 -38
  12. package/src/diagnostics/logs/errorNotifications2/errorNotifications2.ts +3 -0
  13. package/src/diagnostics/logs/injectFileLocationToConsole.ts +3 -0
  14. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +32 -22
  15. package/src/diagnostics/managementPages.tsx +0 -18
  16. package/test.ts +0 -5
  17. package/bin/error-email.js +0 -8
  18. package/bin/error-im.js +0 -8
  19. package/src/diagnostics/logs/FastArchiveAppendable.ts +0 -843
  20. package/src/diagnostics/logs/FastArchiveController.ts +0 -573
  21. package/src/diagnostics/logs/FastArchiveViewer.tsx +0 -1090
  22. package/src/diagnostics/logs/LogViewer2.tsx +0 -552
  23. package/src/diagnostics/logs/errorNotifications/ErrorDigestPage.tsx +0 -409
  24. package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +0 -756
  25. package/src/diagnostics/logs/errorNotifications/ErrorSuppressionUI.tsx +0 -280
  26. package/src/diagnostics/logs/errorNotifications/ErrorWarning.tsx +0 -254
  27. package/src/diagnostics/logs/errorNotifications/errorDigestEmail.tsx +0 -233
  28. package/src/diagnostics/logs/errorNotifications/errorDigestEntry.tsx +0 -14
  29. package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +0 -292
  30. package/src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx +0 -209
  31. package/src/diagnostics/logs/importLogsEntry.ts +0 -38
  32. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +0 -150
  33. package/src/diagnostics/logs/logViewerExtractField.ts +0 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.374.0",
3
+ "version": "0.375.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",
@@ -34,9 +34,7 @@
34
34
  "join": "./bin/join.js",
35
35
  "join-public": "./bin/join-public.js",
36
36
  "movelogs": "./bin/movelogs.js",
37
- "addsuperuser": "./bin/addsuperuser.js",
38
- "error-email": "./bin/error-email.js",
39
- "error-im": "./bin/error-im.js"
37
+ "addsuperuser": "./bin/addsuperuser.js"
40
38
  },
41
39
  "dependencies": {
42
40
  "@types/fs-ext": "^2.0.3",
@@ -7,10 +7,10 @@ import { formatNumber, formatVeryNiceDateTime } from "socket-function/src/format
7
7
  import { sort } from "socket-function/src/misc";
8
8
  import { ATag, Anchor } from "../../library-components/ATag";
9
9
  import { ShowMore } from "../../library-components/ShowMore";
10
- import { filterParam } from "../../diagnostics/logs/FastArchiveViewer";
11
10
  import { managementPageURL } from "../../diagnostics/managementPages";
12
11
  import { t } from "../../2-proxy/schema2";
13
12
  import { Querysub } from "../../4-querysub/QuerysubController";
13
+ import { getLogViewerParams } from "../../diagnostics/logs/IndexedLogs/LogViewerParams";
14
14
 
15
15
  export class MachineDetailPage extends qreact.Component {
16
16
  render() {
@@ -105,10 +105,7 @@ export class MachineDetailPage extends qreact.Component {
105
105
  <div>
106
106
  Apply Node ID: {machine.applyNodeId}
107
107
  </div>
108
- <ATag values={[
109
- managementPageURL.getOverride("LogViewer2"),
110
- filterParam.getOverride(`__machineId = ${machineInfo.machineId}`),
111
- ]}>
108
+ <ATag values={getLogViewerParams({ __machineId: machineInfo.machineId })}>
112
109
  Machine Logs
113
110
  </ATag>
114
111
  </div>
@@ -20,8 +20,8 @@ import { PrimitiveDisplay } from "../../diagnostics/logs/ObjectDisplay";
20
20
  import { parseAnsiColors, rgbToHsl } from "../../diagnostics/logs/ansiFormat";
21
21
  import { RenderGitRefInfo, UpdateServiceButtons, bigEmoji, buttonStyle } from "./deployButtons";
22
22
  import { TypedConfigEditor } from "../../library-components/TypedConfigEditor";
23
- import { filterParam } from "../../diagnostics/logs/FastArchiveViewer";
24
23
  import { managementPageURL } from "../../diagnostics/managementPages";
24
+ import { getLogViewerParams } from "../../diagnostics/logs/IndexedLogs/LogViewerParams";
25
25
 
26
26
 
27
27
 
@@ -401,10 +401,7 @@ export class ServiceDetailPage extends qreact.Component {
401
401
  {isWatching ? "Stop Watching Output" : "Watch Screen Output"}
402
402
  </div>
403
403
 
404
- <ATag values={[
405
- managementPageURL.getOverride("LogViewer2"),
406
- filterParam.getOverride(`__machineId = ${machineId}`),
407
- ]}>
404
+ <ATag values={getLogViewerParams({ __machineId: machineId })}>
408
405
  Machine Logs
409
406
  </ATag>
410
407
  </div>
@@ -866,6 +866,13 @@ export async function machineApplyMain() {
866
866
  if (await quickIsOutdated()) {
867
867
  console.log(magenta("Likely outdated, resyncing now"));
868
868
  await resyncServices();
869
+ } else {
870
+ let config = await machineInfos.get(getOwnMachineId());
871
+ if (config) {
872
+ config.heartbeat = Date.now();
873
+ console.log(magenta(`Updating heartbeat for ${getOwnMachineId()} to ${config.heartbeat}`));
874
+ await machineInfos.set(getOwnMachineId(), config);
875
+ }
869
876
  }
870
877
  });
871
878
 
@@ -36,8 +36,8 @@ import { SocketRegistered } from "socket-function/SocketFunctionTypes";
36
36
  import { ATag } from "../library-components/ATag";
37
37
  import { getSyncedController } from "../library-components/SyncedController";
38
38
  import child_process from "child_process";
39
- import { filterParam } from "./logs/FastArchiveViewer";
40
39
  import { getHTTPSKeyCert } from "../-e-certs/certAuthority";
40
+ import { getLogViewerParams } from "./logs/IndexedLogs/LogViewerParams";
41
41
 
42
42
 
43
43
  type NodeData = {
@@ -296,10 +296,9 @@ export class NodeViewer extends qreact.Component {
296
296
  if (str.startsWith("http")) return formatValue(obj);
297
297
 
298
298
  return (
299
- <ATag values={[
300
- managementPageURL.getOverride("LogViewer2"),
301
- filterParam.getOverride(`__nodeId = ${str}`),
302
- ]}>
299
+ <ATag values={getLogViewerParams({
300
+ __nodeId: str,
301
+ })}>
303
302
  Logs
304
303
  </ATag>
305
304
  );
@@ -16,7 +16,7 @@ export type SearchParams = {
16
16
  findBuffer: Buffer;
17
17
  pathOverrides?: TimeFilePathWithSize[];
18
18
  only?: "local" | "public";
19
- forceReadPublic?: boolean;
19
+ forceReadProduction?: boolean;
20
20
  };
21
21
 
22
22
  export type Unit = number;
@@ -272,10 +272,10 @@ export class IndexedLogs<T> {
272
272
  startTime: number;
273
273
  endTime: number;
274
274
  only?: "local" | "public";
275
- forceReadPublic?: boolean;
275
+ forceReadProduction?: boolean;
276
276
  }): Promise<TimeFilePathWithSize[]> {
277
277
  let finalPaths: TimeFilePathWithSize[] = [];
278
- if (config.forceReadPublic && !isPublic()) {
278
+ if (config.forceReadProduction && !isPublic()) {
279
279
  let machineNodes = await this.getMachineNodes();
280
280
  if (machineNodes.length === 0) throw new Error(`Cannot find any public nodes to read from`);
281
281
  return await IndexedLogShimController.nodes[machineNodes[0]].getPaths({
@@ -352,7 +352,7 @@ export class IndexedLogs<T> {
352
352
  onResults?: (results: IndexedLogResults) => Promise<boolean>;
353
353
  }): Promise<IndexedLogResults> {
354
354
 
355
- if (config.params.forceReadPublic && !isPublic()) {
355
+ if (config.params.forceReadProduction && !isPublic()) {
356
356
  let machineNodes = await this.getMachineNodes();
357
357
  if (machineNodes.length === 0) throw new Error(`Cannot find any public nodes to read from`);
358
358
  return await this.clientFind({
@@ -649,7 +649,7 @@ export class IndexedLogs<T> {
649
649
  startTime: number;
650
650
  endTime: number;
651
651
  only?: "local" | "public";
652
- forceReadPublic?: boolean;
652
+ forceReadProduction?: boolean;
653
653
 
654
654
  }): Promise<TimeFilePathWithSize[]> {
655
655
  let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
@@ -658,7 +658,7 @@ export class IndexedLogs<T> {
658
658
  startTime: config.startTime,
659
659
  endTime: config.endTime,
660
660
  only: config.only,
661
- forceReadPublic: config.forceReadPublic,
661
+ forceReadProduction: config.forceReadProduction,
662
662
  });
663
663
  }
664
664
  public onFindResult(config: {
@@ -778,7 +778,7 @@ class IndexedLogShim {
778
778
  startTime: number;
779
779
  endTime: number;
780
780
  only?: "local" | "public";
781
- forceReadPublic?: boolean;
781
+ forceReadProduction?: boolean;
782
782
  }): Promise<TimeFilePathWithSize[]> {
783
783
  let indexedLogs = loggerByName.get(config.indexedLogsName);
784
784
  if (!indexedLogs) throw new Error(`Indexed logs ${config.indexedLogsName} not found`);
@@ -786,7 +786,7 @@ class IndexedLogShim {
786
786
  startTime: config.startTime,
787
787
  endTime: config.endTime,
788
788
  only: config.only,
789
- forceReadPublic: config.forceReadPublic,
789
+ forceReadProduction: config.forceReadProduction,
790
790
  });
791
791
  }
792
792
 
@@ -26,11 +26,10 @@ import { IndexedLogResults, createEmptyIndexedLogResults, mergeIndexedLogResults
26
26
  import { TimeFilePath } from "./TimeFileTree";
27
27
  import { isPublic } from "../../../config";
28
28
  import { Zip } from "../../../zip";
29
+ import { readProductionLogsURL, searchTextURL } from "./LogViewerParams";
29
30
 
30
- let searchText = new URLParam("searchText", "");
31
31
  let excludePendingResults = new URLParam("excludePendingResults", false);
32
32
  let limitURL = new URLParam("limit", 100);
33
- let readPublicLogs = new URLParam("readPublicLogs", false);
34
33
 
35
34
  let savedPathsURL = new URLParam("savedPaths", "");
36
35
  let selectedFieldsURL = new URLParam("selectedFields", {} as Record<string, boolean>);
@@ -105,6 +104,218 @@ export class LogViewer3 extends qreact.Component {
105
104
  await this.loadPaths();
106
105
  }
107
106
 
107
+ async loadPaths() {
108
+ if (savedPathsURL.value) {
109
+ return;
110
+ }
111
+
112
+ Querysub.commitLocal(() => {
113
+ this.state.loadingPaths = true;
114
+ this.state.results = [];
115
+ this.state.stats = undefined;
116
+ });
117
+
118
+ let loggers = await getLoggers2Async();
119
+ let selectedLoggers: typeof loggers.logLogs[] = [];
120
+ Querysub.localRead(() => {
121
+ if (this.state.enableLogs) selectedLoggers.push(loggers.logLogs);
122
+ if (this.state.enableInfos) selectedLoggers.push(loggers.infoLogs);
123
+ if (this.state.enableWarnings) selectedLoggers.push(loggers.warnLogs);
124
+ if (this.state.enableErrors) selectedLoggers.push(loggers.errorLogs);
125
+ });
126
+
127
+ if (selectedLoggers.length === 0) {
128
+ console.error("No log sources selected");
129
+ Querysub.commitLocal(() => {
130
+ this.state.loadingPaths = false;
131
+ });
132
+ return;
133
+ }
134
+
135
+ let allPaths: TimeFilePathWithSize[] = [];
136
+ let range = Querysub.localRead(() => getTimeRange());
137
+
138
+ await Promise.all(selectedLoggers.map(async (logger) => {
139
+ let paths = await logger.clientGetPaths({
140
+ startTime: range.startTime,
141
+ endTime: range.endTime,
142
+ only: excludePendingResults.value ? "public" : undefined,
143
+ forceReadProduction: readProductionLogsURL.value,
144
+ });
145
+ allPaths.push(...paths);
146
+ }));
147
+ sort(allPaths, x => -x.startTime);
148
+
149
+ Querysub.commitLocal(() => {
150
+ this.state.paths = allPaths;
151
+ this.state.loadingPaths = false;
152
+ });
153
+ return allPaths;
154
+ }
155
+
156
+ async updateToLatestResults() {
157
+ let prevPaths = this.getPaths();
158
+ let newPaths = await this.loadPaths();
159
+ Querysub.commitLocal(() => {
160
+ function getHash(path: TimeFilePath): string {
161
+ return path.threadId + "_" + path.machineId;
162
+ }
163
+ let keep = new Set(prevPaths.map(getHash));
164
+ this.state.paths = newPaths?.filter(x => keep.has(getHash(x))) || [];
165
+ });
166
+ await this.search();
167
+ }
168
+
169
+ cancel = async () => {
170
+ this.searchSequenceNumber++;
171
+ let loggers = await getLoggers2Async();
172
+ for (let logger of Object.values(loggers)) {
173
+ logger.clientCancelAllCallbacks();
174
+ }
175
+ Querysub.commitLocal(() => {
176
+ this.state.searching = false;
177
+ this.state.hasSearched = false;
178
+ });
179
+ };
180
+
181
+
182
+ search = async () => {
183
+ await this.cancel();
184
+ Querysub.commitLocal(() => {
185
+ this.state.searching = true;
186
+ this.state.results = [];
187
+ this.state.stats = undefined;
188
+ this.state.searchingLogs = false;
189
+ this.state.searchingInfos = false;
190
+ this.state.searchingWarnings = false;
191
+ this.state.searchingErrors = false;
192
+ });
193
+
194
+
195
+ let loggers = await getLoggers2Async();
196
+
197
+ let selectedLoggers: typeof loggers.logLogs[] = [];
198
+ Querysub.localRead(() => {
199
+ if (this.state.enableLogs) {
200
+ selectedLoggers.push(loggers.logLogs);
201
+ this.state.searchingLogs = true;
202
+ }
203
+ if (this.state.enableInfos) {
204
+ selectedLoggers.push(loggers.infoLogs);
205
+ this.state.searchingInfos = true;
206
+ }
207
+ if (this.state.enableWarnings) {
208
+ selectedLoggers.push(loggers.warnLogs);
209
+ this.state.searchingWarnings = true;
210
+ }
211
+ if (this.state.enableErrors) {
212
+ selectedLoggers.push(loggers.errorLogs);
213
+ this.state.searchingErrors = true;
214
+ }
215
+ });
216
+
217
+ this.searchSequenceNumber++;
218
+ let currentSequenceNumber = this.searchSequenceNumber;
219
+
220
+ let startTime = Date.now();
221
+
222
+ let hasPaths = Querysub.localRead(() => this.getPaths().length > 0);
223
+ let getFilesTime = 0;
224
+ if (!hasPaths) {
225
+ let startTime = Date.now();
226
+ await this.loadPaths();
227
+ getFilesTime = Date.now() - startTime;
228
+ }
229
+
230
+
231
+ if (selectedLoggers.length === 0) {
232
+ console.error("No log sources selected");
233
+ Querysub.commitLocal(() => {
234
+ this.state.searching = false;
235
+ });
236
+ return;
237
+ }
238
+
239
+ let searchBuffer = Querysub.localRead(() => Buffer.from(searchTextURL.value, "utf8"));
240
+ let results: LogDatum[] = [];
241
+ let stats: IndexedLogResults = createEmptyIndexedLogResults();
242
+ stats.fileFindTime += getFilesTime;
243
+
244
+ let paths = Querysub.localRead(() => this.getPaths());
245
+
246
+ let range = Querysub.localRead(() => getTimeRange());
247
+
248
+ let updateResults = throttleFunction(100, () => {
249
+ if (this.searchSequenceNumber !== currentSequenceNumber) return;
250
+ Querysub.commitLocal(() => {
251
+ this.state.results = results;
252
+ });
253
+ });
254
+
255
+ let loggerResults = new Map<typeof loggers.logLogs, IndexedLogResults>();
256
+
257
+ let updateStats = () => {
258
+ if (this.searchSequenceNumber !== currentSequenceNumber) return;
259
+
260
+ let mergedStats: IndexedLogResults = createEmptyIndexedLogResults();
261
+
262
+ for (let loggerResult of loggerResults.values()) {
263
+ mergedStats = mergeIndexedLogResults(mergedStats, loggerResult);
264
+ }
265
+
266
+ mergedStats.totalSearchTime = Date.now() - startTime;
267
+
268
+ Querysub.commitLocal(() => {
269
+ this.state.stats = mergedStats;
270
+ });
271
+ };
272
+
273
+ await Promise.all(selectedLoggers.map(async (logger) => {
274
+ let done = false;
275
+ let result = await errorToUndefined(logger.clientFind({
276
+ params: {
277
+ startTime: range.startTime,
278
+ endTime: range.endTime,
279
+ limit: limitURL.value,
280
+ findBuffer: searchBuffer,
281
+ pathOverrides: paths,
282
+ only: excludePendingResults.value ? "local" : undefined,
283
+ forceReadProduction: readProductionLogsURL.value,
284
+ },
285
+ onResult: (match: LogDatum) => {
286
+ console.log("onResult", match);
287
+ results.push(match);
288
+ void updateResults();
289
+ },
290
+ onResults: (loggerStats: IndexedLogResults) => {
291
+ if (done) return;
292
+ loggerResults.set(logger, loggerStats);
293
+ updateStats();
294
+ },
295
+ }));
296
+ done = true;
297
+
298
+ if (result) {
299
+ loggerResults.set(logger, result);
300
+ updateStats();
301
+ }
302
+
303
+ Querysub.commitLocal(() => {
304
+ if (logger === loggers.logLogs) this.state.searchingLogs = false;
305
+ if (logger === loggers.infoLogs) this.state.searchingInfos = false;
306
+ if (logger === loggers.warnLogs) this.state.searchingWarnings = false;
307
+ if (logger === loggers.errorLogs) this.state.searchingErrors = false;
308
+ });
309
+ }));
310
+
311
+
312
+ Querysub.commitLocal(() => {
313
+ this.state.results = results;
314
+ this.state.searching = false;
315
+ this.state.hasSearched = true;
316
+ });
317
+ };
318
+
108
319
  renderSearchStats() {
109
320
  const stats = this.state.stats;
110
321
  if (!stats) return undefined;
@@ -288,7 +499,7 @@ export class LogViewer3 extends qreact.Component {
288
499
  <span>is not moving logs to remote storage. {formatNumber(warning.count)} files ({formatNumber(warning.totalSize)}B) are {formatTime(now - warning.oldestTime)} old</span>
289
500
  </div>
290
501
  ))}
291
- {!isPublic() && !readPublicLogs.value && <Button
502
+ {!isPublic() && !readProductionLogsURL.value && <Button
292
503
  onClick={async () => {
293
504
  Querysub.commitLocal(() => {
294
505
  this.state.forceMoveStartTime = Date.now();
@@ -336,217 +547,6 @@ export class LogViewer3 extends qreact.Component {
336
547
  );
337
548
  }
338
549
 
339
- async loadPaths() {
340
- if (savedPathsURL.value) {
341
- return;
342
- }
343
-
344
- Querysub.commitLocal(() => {
345
- this.state.loadingPaths = true;
346
- this.state.results = [];
347
- this.state.stats = undefined;
348
- });
349
-
350
- let loggers = await getLoggers2Async();
351
- let selectedLoggers: typeof loggers.logLogs[] = [];
352
- Querysub.localRead(() => {
353
- if (this.state.enableLogs) selectedLoggers.push(loggers.logLogs);
354
- if (this.state.enableInfos) selectedLoggers.push(loggers.infoLogs);
355
- if (this.state.enableWarnings) selectedLoggers.push(loggers.warnLogs);
356
- if (this.state.enableErrors) selectedLoggers.push(loggers.errorLogs);
357
- });
358
-
359
- if (selectedLoggers.length === 0) {
360
- console.error("No log sources selected");
361
- Querysub.commitLocal(() => {
362
- this.state.loadingPaths = false;
363
- });
364
- return;
365
- }
366
-
367
- let allPaths: TimeFilePathWithSize[] = [];
368
- let range = Querysub.localRead(() => getTimeRange());
369
-
370
- await Promise.all(selectedLoggers.map(async (logger) => {
371
- let paths = await logger.clientGetPaths({
372
- startTime: range.startTime,
373
- endTime: range.endTime,
374
- only: excludePendingResults.value ? "public" : undefined,
375
- forceReadPublic: readPublicLogs.value,
376
- });
377
- allPaths.push(...paths);
378
- }));
379
- sort(allPaths, x => -x.startTime);
380
-
381
- Querysub.commitLocal(() => {
382
- this.state.paths = allPaths;
383
- this.state.loadingPaths = false;
384
- });
385
- return allPaths;
386
- }
387
-
388
- async updateToLatestResults() {
389
- let prevPaths = this.getPaths();
390
- let newPaths = await this.loadPaths();
391
- Querysub.commitLocal(() => {
392
- function getHash(path: TimeFilePath): string {
393
- return path.threadId + "_" + path.machineId;
394
- }
395
- let keep = new Set(prevPaths.map(getHash));
396
- this.state.paths = newPaths?.filter(x => keep.has(getHash(x))) || [];
397
- });
398
- await this.search();
399
- }
400
-
401
- cancel = async () => {
402
- this.searchSequenceNumber++;
403
- let loggers = await getLoggers2Async();
404
- for (let logger of Object.values(loggers)) {
405
- logger.clientCancelAllCallbacks();
406
- }
407
- Querysub.commitLocal(() => {
408
- this.state.searching = false;
409
- this.state.hasSearched = false;
410
- });
411
- };
412
-
413
-
414
- search = async () => {
415
- await this.cancel();
416
- Querysub.commitLocal(() => {
417
- this.state.searching = true;
418
- this.state.results = [];
419
- this.state.stats = undefined;
420
- this.state.searchingLogs = false;
421
- this.state.searchingInfos = false;
422
- this.state.searchingWarnings = false;
423
- this.state.searchingErrors = false;
424
- });
425
-
426
-
427
- let loggers = await getLoggers2Async();
428
-
429
- let selectedLoggers: typeof loggers.logLogs[] = [];
430
- Querysub.localRead(() => {
431
- if (this.state.enableLogs) {
432
- selectedLoggers.push(loggers.logLogs);
433
- this.state.searchingLogs = true;
434
- }
435
- if (this.state.enableInfos) {
436
- selectedLoggers.push(loggers.infoLogs);
437
- this.state.searchingInfos = true;
438
- }
439
- if (this.state.enableWarnings) {
440
- selectedLoggers.push(loggers.warnLogs);
441
- this.state.searchingWarnings = true;
442
- }
443
- if (this.state.enableErrors) {
444
- selectedLoggers.push(loggers.errorLogs);
445
- this.state.searchingErrors = true;
446
- }
447
- });
448
-
449
- this.searchSequenceNumber++;
450
- let currentSequenceNumber = this.searchSequenceNumber;
451
-
452
- let startTime = Date.now();
453
-
454
- let hasPaths = Querysub.localRead(() => this.getPaths().length > 0);
455
- let getFilesTime = 0;
456
- if (!hasPaths) {
457
- let startTime = Date.now();
458
- await this.loadPaths();
459
- getFilesTime = Date.now() - startTime;
460
- }
461
-
462
-
463
- if (selectedLoggers.length === 0) {
464
- console.error("No log sources selected");
465
- Querysub.commitLocal(() => {
466
- this.state.searching = false;
467
- });
468
- return;
469
- }
470
-
471
- let searchBuffer = Querysub.localRead(() => Buffer.from(searchText.value, "utf8"));
472
- let results: LogDatum[] = [];
473
- let stats: IndexedLogResults = createEmptyIndexedLogResults();
474
- stats.fileFindTime += getFilesTime;
475
-
476
- let paths = Querysub.localRead(() => this.getPaths());
477
-
478
- let range = Querysub.localRead(() => getTimeRange());
479
-
480
- let updateResults = throttleFunction(100, () => {
481
- if (this.searchSequenceNumber !== currentSequenceNumber) return;
482
- Querysub.commitLocal(() => {
483
- this.state.results = results;
484
- });
485
- });
486
-
487
- let loggerResults = new Map<typeof loggers.logLogs, IndexedLogResults>();
488
-
489
- let updateStats = () => {
490
- if (this.searchSequenceNumber !== currentSequenceNumber) return;
491
-
492
- let mergedStats: IndexedLogResults = createEmptyIndexedLogResults();
493
-
494
- for (let loggerResult of loggerResults.values()) {
495
- mergedStats = mergeIndexedLogResults(mergedStats, loggerResult);
496
- }
497
-
498
- mergedStats.totalSearchTime = Date.now() - startTime;
499
-
500
- Querysub.commitLocal(() => {
501
- this.state.stats = mergedStats;
502
- });
503
- };
504
-
505
- await Promise.all(selectedLoggers.map(async (logger) => {
506
- let done = false;
507
- let result = await errorToUndefined(logger.clientFind({
508
- params: {
509
- startTime: range.startTime,
510
- endTime: range.endTime,
511
- limit: limitURL.value,
512
- findBuffer: searchBuffer,
513
- pathOverrides: paths,
514
- only: excludePendingResults.value ? "local" : undefined,
515
- forceReadPublic: readPublicLogs.value,
516
- },
517
- onResult: (match: LogDatum) => {
518
- console.log("onResult", match);
519
- results.push(match);
520
- void updateResults();
521
- },
522
- onResults: (loggerStats: IndexedLogResults) => {
523
- if (done) return;
524
- loggerResults.set(logger, loggerStats);
525
- updateStats();
526
- },
527
- }));
528
- done = true;
529
-
530
- if (result) {
531
- loggerResults.set(logger, result);
532
- updateStats();
533
- }
534
-
535
- Querysub.commitLocal(() => {
536
- if (logger === loggers.logLogs) this.state.searchingLogs = false;
537
- if (logger === loggers.infoLogs) this.state.searchingInfos = false;
538
- if (logger === loggers.warnLogs) this.state.searchingWarnings = false;
539
- if (logger === loggers.errorLogs) this.state.searchingErrors = false;
540
- });
541
- }));
542
-
543
-
544
- Querysub.commitLocal(() => {
545
- this.state.results = results;
546
- this.state.searching = false;
547
- this.state.hasSearched = true;
548
- });
549
- };
550
550
 
551
551
  renderResults() {
552
552
  let fieldNames = new Set<string>();
@@ -695,8 +695,8 @@ export class LogViewer3 extends qreact.Component {
695
695
  />
696
696
  {!isPublic() && <InputLabelURL
697
697
  checkbox
698
- label="Read Public Logs"
699
- url={readPublicLogs}
698
+ label="Read Production Logs"
699
+ url={readProductionLogsURL}
700
700
  onChangeValue={(newValue) => {
701
701
  if (newValue) {
702
702
  savedPathsURL.value = "";
@@ -754,7 +754,7 @@ export class LogViewer3 extends qreact.Component {
754
754
  </Button>
755
755
  <TimeRangeSelector />
756
756
  </div>
757
- {!isPublic() && readPublicLogs.value && <div className={css.fontSize(40).pad2(12, 6).hsl(280, 40, 50).colorhsl(0, 0, 100).boldStyle}>
757
+ {!isPublic() && readProductionLogsURL.value && <div className={css.fontSize(40).pad2(12, 6).hsl(280, 40, 50).colorhsl(0, 0, 100).boldStyle}>
758
758
  Reading public logs
759
759
  </div>}
760
760
 
@@ -763,10 +763,10 @@ export class LogViewer3 extends qreact.Component {
763
763
  flavor="large"
764
764
  fillWidth
765
765
  focusOnMount
766
- url={searchText}
766
+ url={searchTextURL}
767
767
  onKeyDown={(e) => {
768
768
  if (e.key === "Enter") {
769
- searchText.value = e.currentTarget.value;
769
+ searchTextURL.value = e.currentTarget.value;
770
770
  void this.search();
771
771
  }
772
772
  }}
@@ -776,6 +776,7 @@ export class LogViewer3 extends qreact.Component {
776
776
  flavor="large"
777
777
  onClick={() => void this.loadPaths()}
778
778
  hue={this.state.paths.length ? 200 : 120}
779
+ className={css + (this.state.loadingPaths && css.opacity(0.5))}
779
780
  >
780
781
  {this.getPaths().length && "Reset Files" || "Preview Files"}
781
782
  </Button>
@@ -835,7 +836,7 @@ export class LogViewer3 extends qreact.Component {
835
836
  >
836
837
  {savedPathsURL.value ? `Clear Frozen Files (${this.getPaths().length})` : `Freeze Files (${this.state.paths.length})`}
837
838
  </Button>
838
- {!savedPathsURL.value && (
839
+ {savedPathsURL.value && (
839
840
  <div className={css.pad2(8, 4).hsl(40, 60, 50).colorhsl(40, 0, 100)}>
840
841
  Files frozen in memory. Click Preview Files to refresh.
841
842
  </div>