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 +1 -1
- package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +10 -5
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +20 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +28 -1
- package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +61 -20
- 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/package.json
CHANGED
|
@@ -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,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 "./
|
|
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("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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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 &&
|
|
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
|