querysub 0.375.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.375.0",
3
+ "version": "0.376.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",
@@ -10,7 +10,7 @@ import { measureBlock, measureFnc, measureWrap } from "socket-function/src/profi
10
10
  import { formatNumber, formatTime } from "socket-function/src/formatting/format";
11
11
  import { magenta, yellow } from "socket-function/src/formatting/logColors";
12
12
  import { Unit, getAllUnits, Reader, createOffsetReader, SearchParams, IndexedLogResults } from "./BufferIndexHelpers";
13
- import { createMatchesPattern, getSearchUnits } from "./bufferMatcher";
13
+ import { createMatchesPattern, getSearchUnits } from "./bufferSearchFindMatcher";
14
14
  import { UnitSet } from "./BufferUnitSet";
15
15
  import { BufferUnitIndex } from "./BufferUnitIndex";
16
16
  import { BufferListStreamer } from "./BufferListStreamer";
@@ -178,13 +178,13 @@ export class BufferIndex {
178
178
 
179
179
  // IMPORTANT! The input data values should be sorted from newest to oldest.
180
180
  @measureFnc
181
- public static encodeAll(config: {
181
+ public static async encodeAll(config: {
182
182
  data: Buffer[];
183
- }): {
183
+ }): Promise<{
184
184
  data: Buffer;
185
185
  index: Buffer;
186
- } {
187
- let obj = BufferUnitIndex.encode(config.data, {
186
+ }> {
187
+ let obj = await BufferUnitIndex.encode(config.data, {
188
188
  type: BULK_TYPE,
189
189
  });
190
190
  return {
@@ -453,6 +453,11 @@ export class BufferIndex {
453
453
  results.remoteIndexesSearched += 1;
454
454
  results.remoteIndexSize += index.length;
455
455
  } else {
456
+ let dataLength = await dataReader.getLength();
457
+ if (dataLength < 32) {
458
+ // If it's a small file, nothing of value will be lost by ignoring it. And almost all of our errors are coming from extremely small files.
459
+ return;
460
+ }
456
461
  throw new Error(`Unknown type in index file: ${type}`);
457
462
  }
458
463
  }
@@ -3,6 +3,20 @@
3
3
  #include <string.h>
4
4
  #include <algorithm>
5
5
 
6
+ static uint32_t RemapUnit(uint32_t unit) {
7
+ uint8_t byte0 = (unit >> 0) & 0xFF;
8
+ uint8_t byte1 = (unit >> 8) & 0xFF;
9
+ uint8_t byte2 = (unit >> 16) & 0xFF;
10
+ uint8_t byte3 = (unit >> 24) & 0xFF;
11
+
12
+ if (byte0 >= 65 && byte0 <= 90) byte0 += 32;
13
+ if (byte1 >= 65 && byte1 <= 90) byte1 += 32;
14
+ if (byte2 >= 65 && byte2 <= 90) byte2 += 32;
15
+ if (byte3 >= 65 && byte3 <= 90) byte3 += 32;
16
+
17
+ return byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24);
18
+ }
19
+
6
20
  static napi_value PopulateUnits(napi_env env, napi_callback_info info) {
7
21
  size_t argc = 2;
8
22
  napi_value args[2];
@@ -75,6 +89,8 @@ static napi_value PopulateUnits(napi_env env, napi_callback_info info) {
75
89
  (bufferData[i+2] << 16) |
76
90
  (bufferData[i+3] << 24);
77
91
 
92
+ unit = RemapUnit(unit);
93
+
78
94
  if (unit == 0) continue;
79
95
 
80
96
  unitsArray[currentOffset] = unit;
@@ -184,6 +200,8 @@ static napi_value BuildHashTable(napi_env env, napi_callback_info info) {
184
200
  // This reads 4 bytes starting at position i
185
201
  uint32_t unit = *(uint32_t*)(blockData + i);
186
202
 
203
+ unit = RemapUnit(unit);
204
+
187
205
  uint32_t maskedHash = GetMaskedHash(unit, mask);
188
206
  uint32_t currentHead = hashTable[maskedHash];
189
207
 
@@ -291,6 +309,8 @@ static napi_value EstimateUniqueUnits(napi_env env, napi_callback_info info) {
291
309
  // Read unit directly by casting pointer (little-endian architecture)
292
310
  uint32_t unit = *(uint32_t*)(bufferData + i);
293
311
 
312
+ unit = RemapUnit(unit);
313
+
294
314
  // Get masked hash with 0xFFFF mask (16-bit)
295
315
  uint32_t maskedHash = GetMaskedHash(unit, 0xFFFF);
296
316
 
@@ -57,6 +57,33 @@ export function createOffsetReader(reader: Reader, offset: number): Reader {
57
57
  };
58
58
  }
59
59
 
60
+ export function remapUnit(unit: Unit): Unit {
61
+ let byte0 = (unit >> 0) & 0xFF;
62
+ let byte1 = (unit >> 8) & 0xFF;
63
+ let byte2 = (unit >> 16) & 0xFF;
64
+ let byte3 = (unit >> 24) & 0xFF;
65
+
66
+ if (byte0 >= 65 && byte0 <= 90) byte0 += 32;
67
+ if (byte1 >= 65 && byte1 <= 90) byte1 += 32;
68
+ if (byte2 >= 65 && byte2 <= 90) byte2 += 32;
69
+ if (byte3 >= 65 && byte3 <= 90) byte3 += 32;
70
+
71
+ return (byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24)) >>> 0;
72
+ }
73
+ export function remapSearchBuffer(buffer: Buffer) {
74
+ let newBuffer = Buffer.alloc(buffer.length);
75
+ buffer.copy(newBuffer);
76
+ buffer = newBuffer;
77
+ for (let i = 0; i < buffer.length; i++) {
78
+ let byte = buffer[i];
79
+ if (byte >= 65 && byte <= 90) {
80
+ buffer[i] = byte + 32;
81
+ } else {
82
+ buffer[i] = byte;
83
+ }
84
+ }
85
+ return buffer;
86
+ }
60
87
 
61
88
  export const getAllUnits = measureWrap(function getAllUnits(config: {
62
89
  buffer: Buffer;
@@ -71,7 +98,7 @@ export const getAllUnits = measureWrap(function getAllUnits(config: {
71
98
  const result: UnitRef[] = [];
72
99
  // For each byte position, create a unit from that position and the next 3 bytes
73
100
  for (let i = 0; i <= buffer.length - 4; i++) {
74
- const unit = buffer.readUint32LE(i);
101
+ const unit = remapUnit(buffer.readUint32LE(i));
75
102
  if (!unit) continue;
76
103
 
77
104
  result.push({
@@ -3,7 +3,7 @@
3
3
  import { LZ4 } from "../../../storage/LZ4";
4
4
  import { measureBlock, measureFnc } from "socket-function/src/profiling/measure";
5
5
  import { Zip } from "../../../zip";
6
- import { BufferReader, Reader, SearchParams, IndexedLogResults, Unit } from "./BufferIndexHelpers";
6
+ import { BufferReader, Reader, SearchParams, IndexedLogResults, Unit, remapUnit } from "./BufferIndexHelpers";
7
7
  import { formatNumber, formatPercent } from "socket-function/src/formatting/format";
8
8
  import { lazy } from "socket-function/src/caching";
9
9
  import { list, sort } from "socket-function/src/misc";
@@ -11,23 +11,64 @@ import { testDisableCache } from "../../../-a-archives/archivesMemoryCache";
11
11
  import { devDebugbreak } from "../../../config";
12
12
  import { BufferUnitIndexParallelSearchCount, DEFAULT_BLOCK_SIZE, DEFAULT_TARGET_UNITS_PER_BUCKET } from "./BufferIndexLogsOptimizationConstants";
13
13
  import { runInParallel } from "socket-function/src/batching";
14
- import { createMatchesPattern } from "./bufferMatcher";
14
+ import { createMatchesPattern } from "./bufferSearchFindMatcher";
15
+ import * as path from "path";
16
+ import * as fs from "fs";
17
+ import { runPromise } from "socket-function/src/runPromise";
18
+ import * as crypto from "crypto";
15
19
 
16
20
  const USE_COMPRESSION = true;
17
21
 
22
+ const getCppAddon = lazy(async () => {
23
+ if (typeof process === "undefined" || !process.versions || !process.versions.node) {
24
+ return undefined;
25
+ }
18
26
 
19
- // Lazy-load the C++ addon (only loaded when actually needed, not in client-side code)
20
- let getCppAddon = lazy(() => {
21
- try {
22
- // Check if we're in Node.js environment
23
- if (typeof process === "undefined" || !process.versions || !process.versions.node) {
27
+ const checkNeedsBuild = (): boolean => {
28
+ const cppFilePath = path.join(__dirname, "BufferIndexCPP.cpp");
29
+ const distPath = path.join(__dirname, "dist");
30
+ const versionFilePath = path.join(distPath, "BufferIndexCPP.version");
31
+ const buildPath = path.join(__dirname, "build");
32
+
33
+ if (!fs.existsSync(buildPath)) {
34
+ return true;
35
+ }
36
+ if (!fs.existsSync(versionFilePath)) {
37
+ return true;
38
+ }
39
+ try {
40
+ const cppFileContent = fs.readFileSync(cppFilePath, "utf-8");
41
+ const currentHash = crypto.createHash("sha256").update(cppFileContent).digest("hex");
42
+ const storedHash = fs.readFileSync(versionFilePath, "utf-8").trim();
43
+ if (storedHash !== currentHash) {
44
+ return true;
45
+ }
46
+ } catch (e) {
47
+ return true;
48
+ }
49
+ return false;
50
+ };
51
+
52
+ if (checkNeedsBuild()) {
53
+ try {
54
+ await runPromise("node-gyp rebuild");
55
+ const cppFilePath = path.join(__dirname, "BufferIndexCPP.cpp");
56
+ const distPath = path.join(__dirname, "dist");
57
+ const versionFilePath = path.join(distPath, "BufferIndexCPP.version");
58
+ if (!fs.existsSync(distPath)) {
59
+ fs.mkdirSync(distPath, { recursive: true });
60
+ }
61
+ const cppFileContent = fs.readFileSync(cppFilePath, "utf-8");
62
+ const currentHash = crypto.createHash("sha256").update(cppFileContent).digest("hex");
63
+ fs.writeFileSync(versionFilePath, currentHash);
64
+ } catch (e) {
24
65
  return undefined;
25
66
  }
26
- // Try to require the C++ addon
27
- const addon = require("./BufferIndexCPP") as typeof import("./BufferIndexCPP");
28
- return addon;
67
+ }
68
+
69
+ try {
70
+ return require("./BufferIndexCPP") as typeof import("./BufferIndexCPP");
29
71
  } catch (e) {
30
- console.warn("C++ addon not available, falling back to TypeScript implementation", e);
31
72
  return undefined;
32
73
  }
33
74
  });
@@ -107,14 +148,14 @@ export class BufferUnitIndex {
107
148
 
108
149
  // IMPORTANT! The input data values should be sorted from newest to oldest.
109
150
  @measureFnc
110
- public static encode(allData: Buffer[], options: {
151
+ public static async encode(allData: Buffer[], options: {
111
152
  type: number;
112
153
  blockSize?: number;
113
154
  targetUnitsPerBucket?: number;
114
- }): {
155
+ }): Promise<{
115
156
  blocks: Buffer;
116
157
  index: Buffer;
117
- } {
158
+ }> {
118
159
  const type = options.type;
119
160
  const BLOCK_SIZE = options.blockSize ?? DEFAULT_BLOCK_SIZE;
120
161
  const TARGET_UNITS_PER_BUCKET = options.targetUnitsPerBucket ?? DEFAULT_TARGET_UNITS_PER_BUCKET;
@@ -199,8 +240,8 @@ export class BufferUnitIndex {
199
240
  return Buffer.concat([blocksHeaderBuffer, ...compressedBlocks]);
200
241
  }, `createFinalBlocksBuffer`);
201
242
 
202
- const estimatedUniqueUnits = measureBlock(() => {
203
- const cppAddon = getCppAddon();
243
+ const estimatedUniqueUnits = await measureBlock(async () => {
244
+ const cppAddon = await getCppAddon();
204
245
  if (cppAddon) {
205
246
  // Use C++ addon for performance
206
247
  return cppAddon.estimateUniqueUnits(allData);
@@ -213,7 +254,7 @@ export class BufferUnitIndex {
213
254
 
214
255
  for (const buffer of allData) {
215
256
  for (let i = 0; i <= buffer.length - 4; i++) {
216
- const unit = buffer.readUint32LE(i);
257
+ const unit = remapUnit(buffer.readUint32LE(i));
217
258
  const maskedHash = getMaskedHash(unit, 0xFFFF);
218
259
 
219
260
  if (seenMaskedHashes[maskedHash] === 0) {
@@ -251,8 +292,8 @@ export class BufferUnitIndex {
251
292
 
252
293
 
253
294
  // Step 4: Build hash table with linked lists using Uint32Arrays for performance
254
- const { hashTable, linkedListData, nodeCount, filledSlots } = measureBlock(() => {
255
- const cppAddon = getCppAddon();
295
+ const { hashTable, linkedListData, nodeCount, filledSlots } = await measureBlock(async () => {
296
+ const cppAddon = await getCppAddon();
256
297
  if (cppAddon) {
257
298
  // Use C++ addon for performance
258
299
  return cppAddon.buildHashTable(blocksUncompressed, hashTableCapacity, mask);
@@ -298,7 +339,7 @@ export class BufferUnitIndex {
298
339
 
299
340
  // Iterate through all units and add them directly
300
341
  for (let i = 0; i <= blockUncompressed.length - 4; i++) {
301
- const unit = blockUncompressed.readUint32LE(i);
342
+ const unit = remapUnit(blockUncompressed.readUint32LE(i));
302
343
  const maskedHash = getMaskedHash(unit, mask);
303
344
 
304
345
  const currentHead = hashTable[maskedHash];
@@ -1,7 +1,7 @@
1
1
  import { formatPercent, formatNumber } from "socket-function/src/formatting/format";
2
2
  import { red } from "socket-function/src/formatting/logColors";
3
3
  import { measureFnc } from "socket-function/src/profiling/measure";
4
- import { Unit } from "./BufferIndexHelpers";
4
+ import { Unit, remapUnit } from "./BufferIndexHelpers";
5
5
 
6
6
  export class UnitSet {
7
7
  // Hash-based set for checking unit membership (no positions stored)
@@ -58,7 +58,7 @@ export class UnitSet {
58
58
  const buffer = block[bufferIndex];
59
59
  // Extract units directly
60
60
  for (let i = 0; i <= buffer.length - 4; i++) {
61
- const unit = buffer.readUint32LE(i);
61
+ const unit = remapUnit(buffer.readUint32LE(i));
62
62
  if (!unit) continue;
63
63
 
64
64
  totalInserts++;
@@ -283,8 +283,8 @@ export class LogViewer3 extends qreact.Component {
283
283
  forceReadProduction: readProductionLogsURL.value,
284
284
  },
285
285
  onResult: (match: LogDatum) => {
286
- console.log("onResult", match);
287
286
  results.push(match);
287
+ sort(results, x => -x.time);
288
288
  void updateResults();
289
289
  },
290
290
  onResults: (loggerStats: IndexedLogResults) => {
@@ -433,6 +433,52 @@ export class LogViewer3 extends qreact.Component {
433
433
  );
434
434
  }
435
435
 
436
+ renderForceMoveLogs() {
437
+ return <><Button
438
+ onClick={async () => {
439
+ Querysub.commitLocal(() => {
440
+ this.state.forceMoveStartTime = Date.now();
441
+ this.state.forceMoveEndTime = undefined;
442
+ });
443
+
444
+ let forceMoveInterval = setInterval(() => {
445
+ this.forceUpdate();
446
+ }, 100);
447
+
448
+ try {
449
+ let loggers = await getLoggers2Async();
450
+ for (let logger of Object.values(loggers)) {
451
+ await logger.clientForceMoveLogsToPublic();
452
+ }
453
+ await this.loadPaths();
454
+ } finally {
455
+ if (forceMoveInterval) {
456
+ clearInterval(forceMoveInterval);
457
+ }
458
+
459
+ Querysub.commitLocal(() => {
460
+ this.state.forceMoveEndTime = Date.now();
461
+ });
462
+ }
463
+ }}
464
+ hue={180}
465
+ >
466
+ Force Move Logs to Public
467
+ </Button>
468
+ {(() => {
469
+ if (this.state.forceMoveStartTime !== undefined && this.state.forceMoveEndTime === undefined) {
470
+ const elapsed = Date.now() - this.state.forceMoveStartTime;
471
+ return <div>Moving logs... {formatTime(elapsed)}</div>;
472
+ }
473
+ if (this.state.forceMoveStartTime !== undefined && this.state.forceMoveEndTime !== undefined) {
474
+ const duration = this.state.forceMoveEndTime - this.state.forceMoveStartTime;
475
+ return <div>Moved logs in {formatTime(duration)}</div>;
476
+ }
477
+ return undefined;
478
+ })()}
479
+ </>;
480
+ }
481
+
436
482
  renderPendingLogWarnings() {
437
483
  const paths = this.getPaths();
438
484
  const now = Date.now();
@@ -499,48 +545,7 @@ export class LogViewer3 extends qreact.Component {
499
545
  <span>is not moving logs to remote storage. {formatNumber(warning.count)} files ({formatNumber(warning.totalSize)}B) are {formatTime(now - warning.oldestTime)} old</span>
500
546
  </div>
501
547
  ))}
502
- {!isPublic() && !readProductionLogsURL.value && <Button
503
- onClick={async () => {
504
- Querysub.commitLocal(() => {
505
- this.state.forceMoveStartTime = Date.now();
506
- this.state.forceMoveEndTime = undefined;
507
- });
508
-
509
- let forceMoveInterval = setInterval(() => {
510
- this.forceUpdate();
511
- }, 100);
512
-
513
- try {
514
- let loggers = await getLoggers2Async();
515
- for (let logger of Object.values(loggers)) {
516
- await logger.clientForceMoveLogsToPublic();
517
- }
518
- await this.loadPaths();
519
- } finally {
520
- if (forceMoveInterval) {
521
- clearInterval(forceMoveInterval);
522
- }
523
-
524
- Querysub.commitLocal(() => {
525
- this.state.forceMoveEndTime = Date.now();
526
- });
527
- }
528
- }}
529
- hue={180}
530
- >
531
- Force Move Logs to Public
532
- </Button>}
533
- {(() => {
534
- if (this.state.forceMoveStartTime !== undefined && this.state.forceMoveEndTime === undefined) {
535
- const elapsed = Date.now() - this.state.forceMoveStartTime;
536
- return <div>Moving logs... {formatTime(elapsed)}</div>;
537
- }
538
- if (this.state.forceMoveStartTime !== undefined && this.state.forceMoveEndTime !== undefined) {
539
- const duration = this.state.forceMoveEndTime - this.state.forceMoveStartTime;
540
- return <div>Moved logs in {formatTime(duration)}</div>;
541
- }
542
- return undefined;
543
- })()}
548
+ {!isPublic() && !readProductionLogsURL.value && this.renderForceMoveLogs()}
544
549
  </>
545
550
  )}
546
551
  </div>
@@ -709,6 +714,7 @@ export class LogViewer3 extends qreact.Component {
709
714
  number
710
715
  url={limitURL}
711
716
  />
717
+ {!isPublic() && this.renderForceMoveLogs()}
712
718
  </div>
713
719
 
714
720
  <div className={css.hbox(10)}>
@@ -1,5 +1,5 @@
1
1
  import { measureWrap } from "socket-function/src/profiling/measure";
2
- import { Unit, getAllUnits } from "./BufferIndexHelpers";
2
+ import { Unit, getAllUnits, remapSearchBuffer } from "./BufferIndexHelpers";
3
3
 
4
4
  const WILD_CARD_BYTE = 42;
5
5
  const WILD_CARD_CHAR = "*";
@@ -54,6 +54,8 @@ function parseMatchStructure(pattern: Buffer): MatchStructure {
54
54
  }
55
55
  // inside is and, outside is outer
56
56
  export function getSearchUnits(pattern: Buffer, disableSpecialCharacters: boolean): Unit[][] {
57
+ pattern = remapSearchBuffer(pattern);
58
+
57
59
  if (disableSpecialCharacters || !pattern.includes(SEARCH_OR_BYTE) && !pattern.includes(SEARCH_AND_BYTE) && !pattern.includes(WILD_CARD_BYTE)) {
58
60
  return [getAllUnits({ buffer: pattern, bufferIndex: 0, block: 0 }).map(u => u.unit)];
59
61
  }
@@ -107,9 +109,11 @@ function getSimplerStructure(structure: MatchStructure): Buffer[][] {
107
109
  // side must appear in order somewhere within buffer.
108
110
  // Returns a function that matches buffers against the pre-processed pattern.
109
111
  export function createMatchesPattern(pattern: Buffer, disableSpecialCharacters: boolean): (buffer: Buffer) => boolean {
112
+ pattern = remapSearchBuffer(pattern);
110
113
 
111
114
  if (disableSpecialCharacters || !pattern.includes(SEARCH_OR_BYTE) && !pattern.includes(SEARCH_AND_BYTE) && !pattern.includes(WILD_CARD_BYTE)) {
112
115
  return measureWrap(function matchesPattern(buffer: Buffer): boolean {
116
+ buffer = remapSearchBuffer(buffer);
113
117
  return buffer.indexOf(pattern) !== -1;
114
118
  }, "BufferIndex|matchesPatternExact");
115
119
  }
@@ -120,6 +124,7 @@ export function createMatchesPattern(pattern: Buffer, disableSpecialCharacters:
120
124
  let hasAnyWildcard = pattern.includes(WILD_CARD_BYTE);
121
125
 
122
126
  return measureWrap(function matchesPattern(buffer: Buffer): boolean {
127
+ buffer = remapSearchBuffer(buffer);
123
128
  // 1) First, use simplerStructure to exclude any false cases
124
129
  // simplerStructure is Buffer[][] where outer array is OR, inner array is AND
125
130
  let anyOrClausePassed = false;
@@ -147,7 +147,7 @@ export async function moveLogsToPublic(config: {
147
147
  }));
148
148
  if (buffers.length === 0) continue;
149
149
 
150
- console.log(magenta(`Merging and moving ${group.length} log files backblaze`));
150
+ console.log(magenta(`Merging and moving ${group.length} log files backblaze (${blue(config.loggerName)})`));
151
151
 
152
152
  let allBuffers: Buffer[][] = [];
153
153
 
@@ -188,7 +188,7 @@ export async function moveLogsToPublic(config: {
188
188
  for (let buffer of group) {
189
189
  uncompressedSize += buffer.length;
190
190
  }
191
- let obj = BufferIndex.encodeAll({
191
+ let obj = await BufferIndex.encodeAll({
192
192
  data: group,
193
193
  });
194
194
  encoded.push({
@@ -221,7 +221,7 @@ export async function moveLogsToPublic(config: {
221
221
  await localLogs.del(path.fullPath + indexExtension);
222
222
  }));
223
223
 
224
- console.log(green(`(${i + 1}/${groups.length}) Wrote ${encoded.length} log files to public (${formatNumber(encoded.reduce((acc, x) => acc + x.uncompressedSize, 0))}B compressed to ${formatNumber(encoded.reduce((acc, x) => acc + x.compressedSize, 0))}B + ${formatNumber(encoded.reduce((acc, x) => acc + x.index.length, 0))}B index) in ${formatTime(Date.now() - time)}`));
224
+ console.log(green(`(${i + 1}/${groups.length}) Wrote ${encoded.length} log files to public (${formatNumber(encoded.reduce((acc, x) => acc + x.uncompressedSize, 0))}B compressed to ${formatNumber(encoded.reduce((acc, x) => acc + x.compressedSize, 0))}B + ${formatNumber(encoded.reduce((acc, x) => acc + x.index.length, 0))}B index) in ${formatTime(Date.now() - time)}`) + ` (${blue(config.loggerName)})`);
225
225
  }
226
226
 
227
227
  // Clean up orphaned index files (index files without corresponding data files)
@@ -1,3 +1,9 @@
1
1
 
2
2
  //todonext
3
- // FIRST, finish up our logs stuff, which is just about done...
3
+
4
+ // single service, no history search, discord messaging, suppression and suppression page
5
+ // - Storing suppression history just in memory? (although suppression values, obviously, on disk)
6
+ // - receive all errors, and service will do suppression
7
+
8
+ // Start with page itself showing errors and suppressing them, for debugging/testing
9
+ // - Ai to automatically create suppression searches, and combine existing ones, etc
@@ -24,7 +24,6 @@ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs shou
24
24
  2) Create lot of remote server logs
25
25
  - Via our refresh loop
26
26
 
27
-
28
27
  3) Verify search is still fast, and works correctly!
29
28
  - Try to get a rare value in that is in the logs, but is hard to find
30
29
  Good rare search. Checks for sending emails, which we do very rarely. If we pack in 10GB of logs after this, it will really stress our indexing system.
@@ -32,13 +31,6 @@ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs shou
32
31
  https://127-0-0-1.querysubtest.com:7007/?hot&readPublicLogs&showingmanagement&machineview=services&managementpage=LogViewer3&searchText=Sending%20email&selectedFields=%7B%22path%22%3Atrue%7D
33
32
 
34
33
 
35
-
36
- Remove old error digest/notification code
37
- - We don't need email digests anymore. I think discord messaging is enough
38
- Remove all old LogViewer/FastArchiveAppendable code
39
- - Make sure to find all links and update them as well
40
-
41
-
42
34
 
43
35
  Rewrite error notification code
44
36
  - Single service, which talks to all machines