querysub 0.375.0 → 0.377.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 +2 -3
- package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +10 -5
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +21 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +28 -1
- package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +69 -21
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +2 -2
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +49 -43
- package/src/diagnostics/logs/IndexedLogs/{bufferMatcher.ts → bufferSearchFindMatcher.ts} +6 -1
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +3 -3
- package/src/diagnostics/logs/errorNotifications2/errorNotifications2.ts +7 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +0 -8
- package/scripts/postinstall.js +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.377.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",
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
"test-wat": "yarn typenode ./src/wat/watCompiler.ts",
|
|
17
17
|
"error-watch": "yarn typenode ./src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx",
|
|
18
18
|
"error-email": "yarn typenode ./src/diagnostics/logs/errorNotifications/errorDigestEntry.tsx",
|
|
19
|
-
"build-native": "cd src/diagnostics/logs/IndexedLogs && node-gyp rebuild"
|
|
20
|
-
"postinstall": "node scripts/postinstall.js"
|
|
19
|
+
"build-native": "cd src/diagnostics/logs/IndexedLogs && node-gyp rebuild"
|
|
21
20
|
},
|
|
22
21
|
"bin": {
|
|
23
22
|
"deploy": "./bin/deploy.js",
|
|
@@ -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 "./
|
|
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,21 @@
|
|
|
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
|
+
|
|
20
|
+
|
|
6
21
|
static napi_value PopulateUnits(napi_env env, napi_callback_info info) {
|
|
7
22
|
size_t argc = 2;
|
|
8
23
|
napi_value args[2];
|
|
@@ -75,6 +90,8 @@ static napi_value PopulateUnits(napi_env env, napi_callback_info info) {
|
|
|
75
90
|
(bufferData[i+2] << 16) |
|
|
76
91
|
(bufferData[i+3] << 24);
|
|
77
92
|
|
|
93
|
+
unit = RemapUnit(unit);
|
|
94
|
+
|
|
78
95
|
if (unit == 0) continue;
|
|
79
96
|
|
|
80
97
|
unitsArray[currentOffset] = unit;
|
|
@@ -184,6 +201,8 @@ static napi_value BuildHashTable(napi_env env, napi_callback_info info) {
|
|
|
184
201
|
// This reads 4 bytes starting at position i
|
|
185
202
|
uint32_t unit = *(uint32_t*)(blockData + i);
|
|
186
203
|
|
|
204
|
+
unit = RemapUnit(unit);
|
|
205
|
+
|
|
187
206
|
uint32_t maskedHash = GetMaskedHash(unit, mask);
|
|
188
207
|
uint32_t currentHead = hashTable[maskedHash];
|
|
189
208
|
|
|
@@ -291,6 +310,8 @@ static napi_value EstimateUniqueUnits(napi_env env, napi_callback_info info) {
|
|
|
291
310
|
// Read unit directly by casting pointer (little-endian architecture)
|
|
292
311
|
uint32_t unit = *(uint32_t*)(bufferData + i);
|
|
293
312
|
|
|
313
|
+
unit = RemapUnit(unit);
|
|
314
|
+
|
|
294
315
|
// Get masked hash with 0xFFFF mask (16-bit)
|
|
295
316
|
uint32_t maskedHash = GetMaskedHash(unit, 0xFFFF);
|
|
296
317
|
|
|
@@ -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,31 +3,79 @@
|
|
|
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";
|
|
10
10
|
import { testDisableCache } from "../../../-a-archives/archivesMemoryCache";
|
|
11
|
-
import { devDebugbreak } from "../../../config";
|
|
11
|
+
import { devDebugbreak, isPublic } 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 "./
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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("yarn build-native", {
|
|
55
|
+
cwd: __dirname
|
|
56
|
+
});
|
|
57
|
+
const cppFilePath = path.join(__dirname, "BufferIndexCPP.cpp");
|
|
58
|
+
const distPath = path.join(__dirname, "dist");
|
|
59
|
+
const versionFilePath = path.join(distPath, "BufferIndexCPP.version");
|
|
60
|
+
if (!fs.existsSync(distPath)) {
|
|
61
|
+
fs.mkdirSync(distPath, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
const cppFileContent = fs.readFileSync(cppFilePath, "utf-8");
|
|
64
|
+
const currentHash = crypto.createHash("sha256").update(cppFileContent).digest("hex");
|
|
65
|
+
fs.writeFileSync(versionFilePath, currentHash);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (!isPublic()) {
|
|
68
|
+
require("debugbreak")(2);
|
|
69
|
+
debugger;
|
|
70
|
+
console.error(`Error building C++ addon: ${e}`);
|
|
71
|
+
}
|
|
24
72
|
return undefined;
|
|
25
73
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
return require("./BufferIndexCPP") as typeof import("./BufferIndexCPP");
|
|
29
78
|
} catch (e) {
|
|
30
|
-
console.warn("C++ addon not available, falling back to TypeScript implementation", e);
|
|
31
79
|
return undefined;
|
|
32
80
|
}
|
|
33
81
|
});
|
|
@@ -107,14 +155,14 @@ export class BufferUnitIndex {
|
|
|
107
155
|
|
|
108
156
|
// IMPORTANT! The input data values should be sorted from newest to oldest.
|
|
109
157
|
@measureFnc
|
|
110
|
-
public static encode(allData: Buffer[], options: {
|
|
158
|
+
public static async encode(allData: Buffer[], options: {
|
|
111
159
|
type: number;
|
|
112
160
|
blockSize?: number;
|
|
113
161
|
targetUnitsPerBucket?: number;
|
|
114
|
-
}): {
|
|
162
|
+
}): Promise<{
|
|
115
163
|
blocks: Buffer;
|
|
116
164
|
index: Buffer;
|
|
117
|
-
} {
|
|
165
|
+
}> {
|
|
118
166
|
const type = options.type;
|
|
119
167
|
const BLOCK_SIZE = options.blockSize ?? DEFAULT_BLOCK_SIZE;
|
|
120
168
|
const TARGET_UNITS_PER_BUCKET = options.targetUnitsPerBucket ?? DEFAULT_TARGET_UNITS_PER_BUCKET;
|
|
@@ -199,8 +247,8 @@ export class BufferUnitIndex {
|
|
|
199
247
|
return Buffer.concat([blocksHeaderBuffer, ...compressedBlocks]);
|
|
200
248
|
}, `createFinalBlocksBuffer`);
|
|
201
249
|
|
|
202
|
-
const estimatedUniqueUnits = measureBlock(() => {
|
|
203
|
-
const cppAddon = getCppAddon();
|
|
250
|
+
const estimatedUniqueUnits = await measureBlock(async () => {
|
|
251
|
+
const cppAddon = await getCppAddon();
|
|
204
252
|
if (cppAddon) {
|
|
205
253
|
// Use C++ addon for performance
|
|
206
254
|
return cppAddon.estimateUniqueUnits(allData);
|
|
@@ -213,7 +261,7 @@ export class BufferUnitIndex {
|
|
|
213
261
|
|
|
214
262
|
for (const buffer of allData) {
|
|
215
263
|
for (let i = 0; i <= buffer.length - 4; i++) {
|
|
216
|
-
const unit = buffer.readUint32LE(i);
|
|
264
|
+
const unit = remapUnit(buffer.readUint32LE(i));
|
|
217
265
|
const maskedHash = getMaskedHash(unit, 0xFFFF);
|
|
218
266
|
|
|
219
267
|
if (seenMaskedHashes[maskedHash] === 0) {
|
|
@@ -251,8 +299,8 @@ export class BufferUnitIndex {
|
|
|
251
299
|
|
|
252
300
|
|
|
253
301
|
// Step 4: Build hash table with linked lists using Uint32Arrays for performance
|
|
254
|
-
const { hashTable, linkedListData, nodeCount, filledSlots } = measureBlock(() => {
|
|
255
|
-
const cppAddon = getCppAddon();
|
|
302
|
+
const { hashTable, linkedListData, nodeCount, filledSlots } = await measureBlock(async () => {
|
|
303
|
+
const cppAddon = await getCppAddon();
|
|
256
304
|
if (cppAddon) {
|
|
257
305
|
// Use C++ addon for performance
|
|
258
306
|
return cppAddon.buildHashTable(blocksUncompressed, hashTableCapacity, mask);
|
|
@@ -298,7 +346,7 @@ export class BufferUnitIndex {
|
|
|
298
346
|
|
|
299
347
|
// Iterate through all units and add them directly
|
|
300
348
|
for (let i = 0; i <= blockUncompressed.length - 4; i++) {
|
|
301
|
-
const unit = blockUncompressed.readUint32LE(i);
|
|
349
|
+
const unit = remapUnit(blockUncompressed.readUint32LE(i));
|
|
302
350
|
const maskedHash = getMaskedHash(unit, mask);
|
|
303
351
|
|
|
304
352
|
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 &&
|
|
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
|
-
|
|
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
|
package/scripts/postinstall.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// Only run build-native if we're being installed as a dependency in someone else's project
|
|
4
|
-
// Not when we're the root project adding new dependencies
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const { execSync } = require("child_process");
|
|
7
|
-
|
|
8
|
-
// Check if we're in node_modules (installed as a dependency)
|
|
9
|
-
const isInstalledAsDependency = __dirname.includes("node_modules");
|
|
10
|
-
|
|
11
|
-
if (isInstalledAsDependency) {
|
|
12
|
-
console.log("Running native build for querysub...");
|
|
13
|
-
try {
|
|
14
|
-
execSync("node-gyp rebuild", {
|
|
15
|
-
cwd: path.join(__dirname, "..", "src", "diagnostics", "logs", "IndexedLogs"),
|
|
16
|
-
stdio: "inherit"
|
|
17
|
-
});
|
|
18
|
-
} catch (err) {
|
|
19
|
-
console.log("Native build failed (this is okay, continuing...)");
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
-
console.log("Skipping native build (running in development)");
|
|
23
|
-
}
|