logixia 1.12.4 → 1.12.6
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/README.md +80 -27
- package/dist/.tsbuildinfo +1 -1
- package/dist/async-context-CSHWoHMB.js +88 -0
- package/dist/async-context-CSHWoHMB.js.map +1 -0
- package/dist/async-context-CwBNMm2E.mjs +68 -0
- package/dist/async-context-CwBNMm2E.mjs.map +1 -0
- package/dist/azure-monitor.transport-CG7ClkYj.d.ts +62 -0
- package/dist/azure-monitor.transport-CG7ClkYj.d.ts.map +1 -0
- package/dist/azure-monitor.transport-CHnjVRF-.mjs +152 -0
- package/dist/azure-monitor.transport-CHnjVRF-.mjs.map +1 -0
- package/dist/azure-monitor.transport-Cm74kXZS.d.mts +62 -0
- package/dist/azure-monitor.transport-Cm74kXZS.d.mts.map +1 -0
- package/dist/azure-monitor.transport-CrvfHd9C.js +157 -0
- package/dist/azure-monitor.transport-CrvfHd9C.js.map +1 -0
- package/dist/azure.d.mts +3 -0
- package/dist/azure.d.ts +3 -0
- package/dist/azure.js +6 -0
- package/dist/azure.mjs +6 -0
- package/dist/batch-buffer-BY-mRWIK.js +170 -0
- package/dist/batch-buffer-BY-mRWIK.js.map +1 -0
- package/dist/batch-buffer-PGvSgbmd.mjs +132 -0
- package/dist/batch-buffer-PGvSgbmd.mjs.map +1 -0
- package/dist/browser.d.mts +427 -0
- package/dist/browser.d.mts.map +1 -0
- package/dist/browser.d.ts +427 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +590 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.mjs +586 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/chunk-DLSkYcPk.mjs +7 -0
- package/dist/chunk-nOFOJqeH.js +30 -0
- package/dist/cloudwatch.d.mts +3 -0
- package/dist/cloudwatch.d.ts +3 -0
- package/dist/cloudwatch.js +6 -0
- package/dist/cloudwatch.mjs +6 -0
- package/dist/cloudwatch.transport-CGHY4buE.d.mts +81 -0
- package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +1 -0
- package/dist/cloudwatch.transport-DK_8cKd3.d.ts +81 -0
- package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +1 -0
- package/dist/cloudwatch.transport-pNBNWJLt.js +370 -0
- package/dist/cloudwatch.transport-pNBNWJLt.js.map +1 -0
- package/dist/cloudwatch.transport-yBwm4OeO.mjs +360 -0
- package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +1 -0
- package/dist/coerce.utils-BN980Y9V.js +44 -0
- package/dist/coerce.utils-BN980Y9V.js.map +1 -0
- package/dist/coerce.utils-Dxv4_ikC.mjs +38 -0
- package/dist/coerce.utils-Dxv4_ikC.mjs.map +1 -0
- package/dist/correlation.d.mts +238 -0
- package/dist/correlation.d.mts.map +1 -0
- package/dist/correlation.d.ts +238 -0
- package/dist/correlation.d.ts.map +1 -0
- package/dist/correlation.js +272 -0
- package/dist/correlation.js.map +1 -0
- package/dist/correlation.mjs +261 -0
- package/dist/correlation.mjs.map +1 -0
- package/dist/gcp.d.mts +3 -0
- package/dist/gcp.d.ts +3 -0
- package/dist/gcp.js +6 -0
- package/dist/gcp.mjs +6 -0
- package/dist/gcp.transport-BJuNRFe_.mjs +192 -0
- package/dist/gcp.transport-BJuNRFe_.mjs.map +1 -0
- package/dist/gcp.transport-BOhkVKlI.d.ts +71 -0
- package/dist/gcp.transport-BOhkVKlI.d.ts.map +1 -0
- package/dist/gcp.transport-Bi6CUqZR.d.mts +71 -0
- package/dist/gcp.transport-Bi6CUqZR.d.mts.map +1 -0
- package/dist/gcp.transport-SHdtc1n0.js +198 -0
- package/dist/gcp.transport-SHdtc1n0.js.map +1 -0
- package/dist/{index-CwFww7VC.d.ts → index-BPKwwERo.d.mts} +18 -174
- package/dist/index-BPKwwERo.d.mts.map +1 -0
- package/dist/{index-DnyeaoZU.d.mts → index-C1X-TE5I.d.ts} +18 -174
- package/dist/index-C1X-TE5I.d.ts.map +1 -0
- package/dist/index.d.mts +41 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +40 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +87 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -132
- package/dist/index.mjs.map +1 -1
- package/dist/internal-log-BUJYMZbE.js +70 -0
- package/dist/internal-log-BUJYMZbE.js.map +1 -0
- package/dist/internal-log-Cm8SOWSV.mjs +52 -0
- package/dist/internal-log-Cm8SOWSV.mjs.map +1 -0
- package/dist/{logitron-logger.module-BIGTm2V6.mjs → logitron-logger.module-Bs3XYZgF.mjs} +266 -166
- package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +1 -0
- package/dist/{logitron-logger.module-BTxDpK6u.js → logitron-logger.module-BsDZR5BH.js} +297 -203
- package/dist/logitron-logger.module-BsDZR5BH.js.map +1 -0
- package/dist/{logitron-logger.module-BmT-ewin.d.ts → logitron-logger.module-CxT1F6Cm.d.ts} +23 -10
- package/dist/logitron-logger.module-CxT1F6Cm.d.ts.map +1 -0
- package/dist/{logitron-logger.module-BCq3sF27.d.mts → logitron-logger.module-zDKVd_o0.d.mts} +23 -10
- package/dist/logitron-logger.module-zDKVd_o0.d.mts.map +1 -0
- package/dist/middleware.d.mts +5 -2
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts +5 -2
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +13 -4
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +14 -4
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +3 -2
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +3 -2
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +6 -2
- package/dist/nest.mjs +6 -2
- package/dist/safe-stringify-DJ66tW5I.mjs +118 -0
- package/dist/safe-stringify-DJ66tW5I.mjs.map +1 -0
- package/dist/safe-stringify-DWo3aZp_.js +142 -0
- package/dist/safe-stringify-DWo3aZp_.js.map +1 -0
- package/dist/search-CFQRISUv.mjs +1596 -0
- package/dist/search-CFQRISUv.mjs.map +1 -0
- package/dist/search-CQOo-Iq6.d.mts +816 -0
- package/dist/search-CQOo-Iq6.d.mts.map +1 -0
- package/dist/search-DujhR94O.d.ts +816 -0
- package/dist/search-DujhR94O.d.ts.map +1 -0
- package/dist/search-njTI2hdo.js +1631 -0
- package/dist/search-njTI2hdo.js.map +1 -0
- package/dist/search.d.mts +4 -1
- package/dist/search.d.ts +4 -1
- package/dist/search.js +9 -1
- package/dist/search.mjs +3 -2
- package/dist/testing.d.mts +2 -1
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.d.ts +2 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/{transport.manager-ciG4r5uz.js → transport.manager-BivyUTtU.js} +497 -437
- package/dist/transport.manager-BivyUTtU.js.map +1 -0
- package/dist/{transport.manager-DETpXuaY.mjs → transport.manager-D6KL3t9V.mjs} +473 -364
- package/dist/transport.manager-D6KL3t9V.mjs.map +1 -0
- package/dist/transport.types-B5vcyv2k.d.mts +187 -0
- package/dist/transport.types-B5vcyv2k.d.mts.map +1 -0
- package/dist/transport.types-BuY84TwO.d.ts +187 -0
- package/dist/transport.types-BuY84TwO.d.ts.map +1 -0
- package/dist/transports.d.mts +90 -29
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +90 -29
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +14 -2
- package/dist/transports.mjs +10 -2
- package/dist/worker-entry.js +1241 -0
- package/dist/worker.d.mts +3 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.js +4 -0
- package/dist/worker.mjs +4 -0
- package/dist/worker.transport-BP8Q28Z2.d.mts +76 -0
- package/dist/worker.transport-BP8Q28Z2.d.mts.map +1 -0
- package/dist/worker.transport-BhMyvqQ2.mjs +167 -0
- package/dist/worker.transport-BhMyvqQ2.mjs.map +1 -0
- package/dist/worker.transport-CfH6z37Z.js +168 -0
- package/dist/worker.transport-CfH6z37Z.js.map +1 -0
- package/dist/worker.transport-mKXgNK0L.d.ts +76 -0
- package/dist/worker.transport-mKXgNK0L.d.ts.map +1 -0
- package/package.json +23 -18
- package/dist/index-CwFww7VC.d.ts.map +0 -1
- package/dist/index-DnyeaoZU.d.mts.map +0 -1
- package/dist/logitron-logger.module-BCq3sF27.d.mts.map +0 -1
- package/dist/logitron-logger.module-BIGTm2V6.mjs.map +0 -1
- package/dist/logitron-logger.module-BTxDpK6u.js.map +0 -1
- package/dist/logitron-logger.module-BmT-ewin.d.ts.map +0 -1
- package/dist/search-Cg_OasF-.d.ts +0 -1
- package/dist/search-DN676Dnz.d.mts +0 -1
- package/dist/search-DOvSI-mb.mjs +0 -1
- package/dist/search-DoZF3RZj.js +0 -0
- package/dist/transport.manager-DETpXuaY.mjs.map +0 -1
- package/dist/transport.manager-ciG4r5uz.js.map +0 -1
|
@@ -0,0 +1,1631 @@
|
|
|
1
|
+
const require_coerce_utils = require('./coerce.utils-BN980Y9V.js');
|
|
2
|
+
|
|
3
|
+
//#region src/search/core/basic-log-indexer.ts
|
|
4
|
+
/**
|
|
5
|
+
* Basic log indexer implementation
|
|
6
|
+
*/
|
|
7
|
+
var BasicLogIndexer = class {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.index = /* @__PURE__ */ new Map();
|
|
11
|
+
this.fieldIndices = /* @__PURE__ */ new Map();
|
|
12
|
+
this.indexSizeBytes = 0;
|
|
13
|
+
this.logSizeById = /* @__PURE__ */ new Map();
|
|
14
|
+
this.options = {
|
|
15
|
+
maxIndexSize: 1e6,
|
|
16
|
+
autoOptimize: true,
|
|
17
|
+
optimizeThreshold: 1e4,
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
this.initializeFieldIndices();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Index a single log entry
|
|
24
|
+
*/
|
|
25
|
+
async indexLog(log) {
|
|
26
|
+
var _this$options, _this$options2;
|
|
27
|
+
const logId = this.generateLogId(log);
|
|
28
|
+
this.trackInsert(logId, log);
|
|
29
|
+
this.updateFieldIndices(logId, log);
|
|
30
|
+
if (((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.autoOptimize) && this.index.size % (this.options.optimizeThreshold || 1e4) === 0) await this.optimizeIndex();
|
|
31
|
+
if (this.index.size > (((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.maxIndexSize) || 1e6)) {
|
|
32
|
+
var _this$options3;
|
|
33
|
+
await this.removeOldestLogs(Math.floor((((_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.maxIndexSize) || 1e6) * .1));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Index multiple log entries in batch
|
|
38
|
+
*/
|
|
39
|
+
async indexBatch(logs) {
|
|
40
|
+
var _this$options4;
|
|
41
|
+
for (const log of logs) {
|
|
42
|
+
const logId = this.generateLogId(log);
|
|
43
|
+
this.trackInsert(logId, log);
|
|
44
|
+
this.updateFieldIndices(logId, log);
|
|
45
|
+
}
|
|
46
|
+
if ((_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.autoOptimize) await this.optimizeIndex();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build semantic index for intelligent search
|
|
50
|
+
*/
|
|
51
|
+
async buildSemanticIndex(logs) {
|
|
52
|
+
const clusters = await this.clusterLogs(logs);
|
|
53
|
+
this.semanticIndex = {
|
|
54
|
+
version: "1.0.0",
|
|
55
|
+
indexedCount: logs.length,
|
|
56
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
57
|
+
clusters
|
|
58
|
+
};
|
|
59
|
+
return this.semanticIndex;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Update search suggestions based on search history
|
|
63
|
+
*/
|
|
64
|
+
async updateSearchSuggestions(searchHistory) {
|
|
65
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const query of searchHistory) {
|
|
67
|
+
const normalizedQuery = query.query.toLowerCase().trim();
|
|
68
|
+
patterns.set(normalizedQuery, (patterns.get(normalizedQuery) || 0) + 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Optimize the index for better performance
|
|
73
|
+
*/
|
|
74
|
+
async optimizeIndex() {
|
|
75
|
+
this.fieldIndices.clear();
|
|
76
|
+
this.initializeFieldIndices();
|
|
77
|
+
for (const [logId, log] of this.index.entries()) this.updateFieldIndices(logId, log);
|
|
78
|
+
this.lastOptimized = /* @__PURE__ */ new Date();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Clear the index
|
|
82
|
+
*/
|
|
83
|
+
async clearIndex() {
|
|
84
|
+
this.index.clear();
|
|
85
|
+
this.fieldIndices.clear();
|
|
86
|
+
this.semanticIndex = void 0;
|
|
87
|
+
this.indexSizeBytes = 0;
|
|
88
|
+
this.logSizeById.clear();
|
|
89
|
+
this.initializeFieldIndices();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get index statistics
|
|
93
|
+
*/
|
|
94
|
+
async getIndexStats() {
|
|
95
|
+
return {
|
|
96
|
+
totalDocuments: this.index.size,
|
|
97
|
+
indexSize: this.calculateIndexSize(),
|
|
98
|
+
...this.lastOptimized !== void 0 ? { lastOptimized: this.lastOptimized } : {}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Remove logs older than specified time
|
|
103
|
+
*/
|
|
104
|
+
async removeOldLogs(olderThan) {
|
|
105
|
+
const cutoffTime = olderThan.getTime();
|
|
106
|
+
let removedCount = 0;
|
|
107
|
+
for (const [logId, log] of this.index.entries()) if (new Date(log.timestamp).getTime() < cutoffTime) {
|
|
108
|
+
this.trackDelete(logId);
|
|
109
|
+
this.removeFromFieldIndices(logId);
|
|
110
|
+
removedCount++;
|
|
111
|
+
}
|
|
112
|
+
return removedCount;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Search logs by field
|
|
116
|
+
*/
|
|
117
|
+
searchByField(field, value) {
|
|
118
|
+
const fieldIndex = this.fieldIndices.get(field);
|
|
119
|
+
if (!fieldIndex) return [];
|
|
120
|
+
const logIds = fieldIndex.get(value.toLowerCase());
|
|
121
|
+
if (!logIds) return [];
|
|
122
|
+
return Array.from(logIds).map((id) => this.index.get(id)).filter((log) => log !== void 0);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get all indexed logs
|
|
126
|
+
*/
|
|
127
|
+
getAllLogs() {
|
|
128
|
+
return Array.from(this.index.values());
|
|
129
|
+
}
|
|
130
|
+
initializeFieldIndices() {
|
|
131
|
+
for (const field of [
|
|
132
|
+
"level",
|
|
133
|
+
"appName",
|
|
134
|
+
"traceId",
|
|
135
|
+
"context",
|
|
136
|
+
"environment"
|
|
137
|
+
]) this.fieldIndices.set(field, /* @__PURE__ */ new Map());
|
|
138
|
+
}
|
|
139
|
+
updateFieldIndices(logId, log) {
|
|
140
|
+
this.addToFieldIndex("level", log.level, logId);
|
|
141
|
+
if (log.appName) this.addToFieldIndex("appName", log.appName, logId);
|
|
142
|
+
if (log.traceId) this.addToFieldIndex("traceId", log.traceId, logId);
|
|
143
|
+
if (log.context) this.addToFieldIndex("context", log.context, logId);
|
|
144
|
+
if (log.environment) this.addToFieldIndex("environment", log.environment, logId);
|
|
145
|
+
}
|
|
146
|
+
addToFieldIndex(field, value, logId) {
|
|
147
|
+
const fieldIndex = this.fieldIndices.get(field);
|
|
148
|
+
if (!fieldIndex) return;
|
|
149
|
+
const normalizedValue = value.toLowerCase();
|
|
150
|
+
if (!fieldIndex.has(normalizedValue)) fieldIndex.set(normalizedValue, /* @__PURE__ */ new Set());
|
|
151
|
+
fieldIndex.get(normalizedValue).add(logId);
|
|
152
|
+
}
|
|
153
|
+
removeFromFieldIndices(logId) {
|
|
154
|
+
for (const fieldIndex of this.fieldIndices.values()) for (const logIds of fieldIndex.values()) logIds.delete(logId);
|
|
155
|
+
}
|
|
156
|
+
generateLogId(log) {
|
|
157
|
+
return `${log.timestamp}_${log.level}_${Math.random().toString(36).slice(2, 11)}`;
|
|
158
|
+
}
|
|
159
|
+
calculateIndexSize() {
|
|
160
|
+
return this.indexSizeBytes;
|
|
161
|
+
}
|
|
162
|
+
/** Insert into the main index and update the running size estimate. */
|
|
163
|
+
trackInsert(logId, log) {
|
|
164
|
+
const existing = this.logSizeById.get(logId);
|
|
165
|
+
if (existing !== void 0) this.indexSizeBytes -= existing;
|
|
166
|
+
const size = JSON.stringify(log).length;
|
|
167
|
+
this.index.set(logId, log);
|
|
168
|
+
this.logSizeById.set(logId, size);
|
|
169
|
+
this.indexSizeBytes += size;
|
|
170
|
+
}
|
|
171
|
+
/** Delete from the main index and update the running size estimate. */
|
|
172
|
+
trackDelete(logId) {
|
|
173
|
+
const size = this.logSizeById.get(logId);
|
|
174
|
+
if (size !== void 0) {
|
|
175
|
+
this.indexSizeBytes -= size;
|
|
176
|
+
this.logSizeById.delete(logId);
|
|
177
|
+
}
|
|
178
|
+
this.index.delete(logId);
|
|
179
|
+
}
|
|
180
|
+
async removeOldestLogs(count) {
|
|
181
|
+
const logs = Array.from(this.index.entries()).sort((a, b) => new Date(a[1].timestamp).getTime() - new Date(b[1].timestamp).getTime()).slice(0, count);
|
|
182
|
+
for (const [logId] of logs) {
|
|
183
|
+
this.trackDelete(logId);
|
|
184
|
+
this.removeFromFieldIndices(logId);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async clusterLogs(logs) {
|
|
188
|
+
const clusters = /* @__PURE__ */ new Map();
|
|
189
|
+
for (const log of logs) {
|
|
190
|
+
const patternKey = `${log.level}_${log.appName}`;
|
|
191
|
+
if (!clusters.has(patternKey)) clusters.set(patternKey, []);
|
|
192
|
+
clusters.get(patternKey).push(log);
|
|
193
|
+
}
|
|
194
|
+
return Array.from(clusters.entries()).map(([pattern, clusterLogs], index) => ({
|
|
195
|
+
id: `cluster_${index}`,
|
|
196
|
+
centroid: [],
|
|
197
|
+
logs: clusterLogs,
|
|
198
|
+
pattern,
|
|
199
|
+
frequency: clusterLogs.length,
|
|
200
|
+
labels: [pattern]
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/search/core/basic-search-engine.ts
|
|
207
|
+
/**
|
|
208
|
+
* Basic search engine implementation
|
|
209
|
+
*/
|
|
210
|
+
var BasicSearchEngine = class {
|
|
211
|
+
constructor(options) {
|
|
212
|
+
this.options = options;
|
|
213
|
+
this.logs = [];
|
|
214
|
+
this.presets = /* @__PURE__ */ new Map();
|
|
215
|
+
this.searchHistory = [];
|
|
216
|
+
this.suggestionCache = /* @__PURE__ */ new Map();
|
|
217
|
+
this.options = {
|
|
218
|
+
maxHistorySize: 1e3,
|
|
219
|
+
cacheSize: 100,
|
|
220
|
+
maxLogs: 1e5,
|
|
221
|
+
...options
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Add logs to the search index.
|
|
226
|
+
*
|
|
227
|
+
* Bounded to `maxLogs` (default 100k): the buffer previously grew without
|
|
228
|
+
* limit, leaking memory in any long-running process feeding it logs. When the
|
|
229
|
+
* cap is exceeded the oldest entries are dropped (FIFO). We also append with a
|
|
230
|
+
* loop rather than `push(...logs)` to avoid a RangeError from spreading a very
|
|
231
|
+
* large array onto the call stack.
|
|
232
|
+
*/
|
|
233
|
+
addLogs(logs) {
|
|
234
|
+
var _this$options;
|
|
235
|
+
for (const log of logs) this.logs.push(log);
|
|
236
|
+
const maxLogs = ((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.maxLogs) ?? 1e5;
|
|
237
|
+
if (this.logs.length > maxLogs) this.logs.splice(0, this.logs.length - maxLogs);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Clear all logs from the index
|
|
241
|
+
*/
|
|
242
|
+
clearLogs() {
|
|
243
|
+
this.logs = [];
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get all indexed logs
|
|
247
|
+
*/
|
|
248
|
+
getLogs() {
|
|
249
|
+
return this.logs;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Perform a full-text search across logs
|
|
253
|
+
*/
|
|
254
|
+
async search(query, filters, options) {
|
|
255
|
+
const filteredLogs = this.applyFilters(this.logs, filters);
|
|
256
|
+
const results = this.performTextSearch(filteredLogs, query, options);
|
|
257
|
+
this.addToSearchHistory(query);
|
|
258
|
+
const sorted = this.applySorting(results, options === null || options === void 0 ? void 0 : options.sortBy, options === null || options === void 0 ? void 0 : options.sortOrder);
|
|
259
|
+
const paginated = this.applyPagination(sorted, options === null || options === void 0 ? void 0 : options.offset, options === null || options === void 0 ? void 0 : options.limit);
|
|
260
|
+
if (options === null || options === void 0 ? void 0 : options.includeContext) await this.enrichWithContext(paginated, options.contextSize);
|
|
261
|
+
return paginated;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Natural language search (basic implementation)
|
|
265
|
+
*/
|
|
266
|
+
async naturalLanguageSearch(query) {
|
|
267
|
+
const parsed = await this.parseNaturalLanguageQuery(query);
|
|
268
|
+
return this.search(parsed.originalQuery, parsed.filters, {
|
|
269
|
+
semanticSearch: true,
|
|
270
|
+
includeContext: true
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Find logs correlated by trace ID
|
|
275
|
+
*/
|
|
276
|
+
async correlateByTraceId(traceId) {
|
|
277
|
+
const correlatedLogs = this.logs.filter((log) => log.traceId === traceId);
|
|
278
|
+
correlatedLogs.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
279
|
+
const timeline = correlatedLogs.map((log) => {
|
|
280
|
+
let eventType = "info";
|
|
281
|
+
if (log.level === "error") eventType = "error";
|
|
282
|
+
else if (log.message.toLowerCase().includes("start")) eventType = "start";
|
|
283
|
+
else if (log.message.toLowerCase().includes("end") || log.message.toLowerCase().includes("complete")) eventType = "end";
|
|
284
|
+
else if (log.message.toLowerCase().includes("milestone")) eventType = "milestone";
|
|
285
|
+
return {
|
|
286
|
+
timestamp: new Date(log.timestamp),
|
|
287
|
+
log,
|
|
288
|
+
eventType
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
const summary = {
|
|
292
|
+
totalLogs: correlatedLogs.length,
|
|
293
|
+
errorCount: correlatedLogs.filter((l) => l.level === "error").length,
|
|
294
|
+
warningCount: correlatedLogs.filter((l) => l.level === "warn").length,
|
|
295
|
+
services: [...new Set(correlatedLogs.map((l) => l.appName))]
|
|
296
|
+
};
|
|
297
|
+
if (timeline.length > 0) {
|
|
298
|
+
const start = timeline[0].timestamp.getTime();
|
|
299
|
+
summary.duration = timeline[timeline.length - 1].timestamp.getTime() - start;
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
traceId,
|
|
303
|
+
correlationKey: traceId,
|
|
304
|
+
logs: correlatedLogs,
|
|
305
|
+
timeline,
|
|
306
|
+
summary
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Find similar logs based on content similarity
|
|
311
|
+
*/
|
|
312
|
+
async findSimilarLogs(logEntry, limit = 10) {
|
|
313
|
+
const similarities = [];
|
|
314
|
+
for (const log of this.logs) {
|
|
315
|
+
if (log === logEntry) continue;
|
|
316
|
+
const similarity = this.calculateSimilarity(logEntry, log);
|
|
317
|
+
if (similarity > .3) similarities.push({
|
|
318
|
+
log,
|
|
319
|
+
similarity,
|
|
320
|
+
matchedPatterns: this.findMatchedPatterns(logEntry, log),
|
|
321
|
+
reason: this.generateSimilarityReason(logEntry, log, similarity)
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get search suggestions
|
|
328
|
+
*/
|
|
329
|
+
async getSuggestions(partialQuery, limit = 10) {
|
|
330
|
+
var _this$options2;
|
|
331
|
+
const cacheKey = partialQuery.toLowerCase();
|
|
332
|
+
if (this.suggestionCache.has(cacheKey)) return this.suggestionCache.get(cacheKey).slice(0, limit);
|
|
333
|
+
const suggestions = [];
|
|
334
|
+
for (const field of [
|
|
335
|
+
"level",
|
|
336
|
+
"appName",
|
|
337
|
+
"traceId",
|
|
338
|
+
"message",
|
|
339
|
+
"timestamp"
|
|
340
|
+
]) if (field.toLowerCase().includes(partialQuery.toLowerCase())) suggestions.push({
|
|
341
|
+
text: field,
|
|
342
|
+
type: "field",
|
|
343
|
+
category: "field"
|
|
344
|
+
});
|
|
345
|
+
const values = /* @__PURE__ */ new Set();
|
|
346
|
+
for (const log of this.logs.slice(-1e3)) {
|
|
347
|
+
var _log$level, _log$appName;
|
|
348
|
+
if ((_log$level = log.level) === null || _log$level === void 0 ? void 0 : _log$level.toLowerCase().includes(partialQuery.toLowerCase())) values.add(log.level);
|
|
349
|
+
if ((_log$appName = log.appName) === null || _log$appName === void 0 ? void 0 : _log$appName.toLowerCase().includes(partialQuery.toLowerCase())) values.add(log.appName);
|
|
350
|
+
}
|
|
351
|
+
for (const value of values) suggestions.push({
|
|
352
|
+
text: value,
|
|
353
|
+
type: "value",
|
|
354
|
+
category: "value"
|
|
355
|
+
});
|
|
356
|
+
for (const historyItem of this.searchHistory.slice(-50)) if (historyItem.toLowerCase().includes(partialQuery.toLowerCase())) suggestions.push({
|
|
357
|
+
text: historyItem,
|
|
358
|
+
type: "query_history",
|
|
359
|
+
category: "history"
|
|
360
|
+
});
|
|
361
|
+
this.suggestionCache.set(cacheKey, suggestions);
|
|
362
|
+
if (this.suggestionCache.size > (((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.cacheSize) || 100)) {
|
|
363
|
+
const firstKey = this.suggestionCache.keys().next().value;
|
|
364
|
+
if (firstKey !== void 0) this.suggestionCache.delete(firstKey);
|
|
365
|
+
}
|
|
366
|
+
return suggestions.slice(0, limit);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Get search statistics
|
|
370
|
+
*/
|
|
371
|
+
async getStats() {
|
|
372
|
+
return {
|
|
373
|
+
totalResults: this.logs.length,
|
|
374
|
+
executionTime: 0,
|
|
375
|
+
indexSize: this.logs.length,
|
|
376
|
+
topTerms: this.getTopTerms()
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Parse natural language query
|
|
381
|
+
*/
|
|
382
|
+
async parseNaturalLanguageQuery(query) {
|
|
383
|
+
const filters = {};
|
|
384
|
+
const lowerQuery = query.toLowerCase();
|
|
385
|
+
const levels = [];
|
|
386
|
+
if (lowerQuery.includes("error")) levels.push("error");
|
|
387
|
+
if (lowerQuery.includes("warn")) levels.push("warn");
|
|
388
|
+
if (lowerQuery.includes("info")) levels.push("info");
|
|
389
|
+
if (levels.length > 0) filters.levels = levels;
|
|
390
|
+
const timeRange = this.extractTimeRange(query);
|
|
391
|
+
if (timeRange) filters.timeRange = timeRange;
|
|
392
|
+
const serviceMatch = query.match(/from\s+(?:the\s+)?(\w+)\s+service/i);
|
|
393
|
+
if (serviceMatch === null || serviceMatch === void 0 ? void 0 : serviceMatch[1]) filters.services = [serviceMatch[1]];
|
|
394
|
+
const userMatch = query.match(/user\s+(?:id\s+)?(\w+)/i);
|
|
395
|
+
if (userMatch === null || userMatch === void 0 ? void 0 : userMatch[1]) filters.userIds = [userMatch[1]];
|
|
396
|
+
let intent = "general_search";
|
|
397
|
+
if (lowerQuery.includes("error")) intent = "find_errors";
|
|
398
|
+
if (lowerQuery.includes("trace") || lowerQuery.includes("request")) intent = "trace_request";
|
|
399
|
+
if (lowerQuery.includes("user")) intent = "find_user_activity";
|
|
400
|
+
if (lowerQuery.includes("slow") || lowerQuery.includes("performance")) intent = "performance_analysis";
|
|
401
|
+
return {
|
|
402
|
+
originalQuery: query,
|
|
403
|
+
intent,
|
|
404
|
+
entities: [],
|
|
405
|
+
filters,
|
|
406
|
+
confidence: .7
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Save a search preset
|
|
411
|
+
*/
|
|
412
|
+
async savePreset(preset) {
|
|
413
|
+
const id = this.generateId();
|
|
414
|
+
const now = /* @__PURE__ */ new Date();
|
|
415
|
+
const fullPreset = {
|
|
416
|
+
...preset,
|
|
417
|
+
id,
|
|
418
|
+
createdAt: now,
|
|
419
|
+
updatedAt: now
|
|
420
|
+
};
|
|
421
|
+
this.presets.set(id, fullPreset);
|
|
422
|
+
return fullPreset;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get saved presets
|
|
426
|
+
*/
|
|
427
|
+
async getPresets(userId) {
|
|
428
|
+
const allPresets = Array.from(this.presets.values());
|
|
429
|
+
if (userId) return allPresets.filter((p) => p.userId === userId || p.shared);
|
|
430
|
+
return allPresets;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Delete a preset
|
|
434
|
+
*/
|
|
435
|
+
async deletePreset(presetId) {
|
|
436
|
+
this.presets.delete(presetId);
|
|
437
|
+
}
|
|
438
|
+
applyFilters(logs, filters) {
|
|
439
|
+
if (!filters) return logs;
|
|
440
|
+
return logs.filter((log) => {
|
|
441
|
+
if (filters.levels && !filters.levels.includes(log.level)) return false;
|
|
442
|
+
if (filters.services && !filters.services.includes(log.appName)) return false;
|
|
443
|
+
if (filters.traceIds && log.traceId && !filters.traceIds.includes(log.traceId)) return false;
|
|
444
|
+
if (filters.timeRange) {
|
|
445
|
+
const logTime = new Date(log.timestamp).getTime();
|
|
446
|
+
if (logTime < (typeof filters.timeRange.start === "number" ? filters.timeRange.start : filters.timeRange.start.getTime())) return false;
|
|
447
|
+
if (filters.timeRange.end) {
|
|
448
|
+
if (logTime > (typeof filters.timeRange.end === "number" ? filters.timeRange.end : filters.timeRange.end.getTime())) return false;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (filters.hasError !== void 0) {
|
|
452
|
+
const hasError = log.level === "error" || !!log.error;
|
|
453
|
+
if (filters.hasError !== hasError) return false;
|
|
454
|
+
}
|
|
455
|
+
if (filters.contexts && log.context && !filters.contexts.includes(log.context)) return false;
|
|
456
|
+
return true;
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
performTextSearch(logs, query, options) {
|
|
460
|
+
if (!query) return logs.map((log) => ({
|
|
461
|
+
log,
|
|
462
|
+
score: 1
|
|
463
|
+
}));
|
|
464
|
+
const queryTerms = query.toLowerCase().split(/\s+/);
|
|
465
|
+
const results = [];
|
|
466
|
+
for (const log of logs) {
|
|
467
|
+
const searchableText = this.getSearchableText(log).toLowerCase();
|
|
468
|
+
let score = 0;
|
|
469
|
+
const highlights = [];
|
|
470
|
+
const matchedTerms = [];
|
|
471
|
+
for (const term of queryTerms) if (searchableText.includes(term)) {
|
|
472
|
+
score += 1;
|
|
473
|
+
matchedTerms.push(term);
|
|
474
|
+
}
|
|
475
|
+
if (score > 0) {
|
|
476
|
+
if (options === null || options === void 0 ? void 0 : options.highlightMatches) highlights.push({
|
|
477
|
+
field: "message",
|
|
478
|
+
fragments: this.getHighlightFragments(log.message, matchedTerms),
|
|
479
|
+
matchedTerms
|
|
480
|
+
});
|
|
481
|
+
const result = {
|
|
482
|
+
log,
|
|
483
|
+
score: score / queryTerms.length
|
|
484
|
+
};
|
|
485
|
+
if (highlights.length > 0) result.highlights = highlights;
|
|
486
|
+
results.push(result);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return results;
|
|
490
|
+
}
|
|
491
|
+
getSearchableText(log) {
|
|
492
|
+
const payloadText = log.payload ? require_coerce_utils.safeToString(log.payload) : "";
|
|
493
|
+
return [
|
|
494
|
+
log.message,
|
|
495
|
+
log.level,
|
|
496
|
+
log.appName,
|
|
497
|
+
log.context,
|
|
498
|
+
payloadText
|
|
499
|
+
].filter(Boolean).join(" ");
|
|
500
|
+
}
|
|
501
|
+
getHighlightFragments(text, terms) {
|
|
502
|
+
const fragments = [];
|
|
503
|
+
const lowerText = text.toLowerCase();
|
|
504
|
+
for (const term of terms) {
|
|
505
|
+
const index = lowerText.indexOf(term);
|
|
506
|
+
if (index !== -1) {
|
|
507
|
+
const start = Math.max(0, index - 30);
|
|
508
|
+
const end = Math.min(text.length, index + term.length + 30);
|
|
509
|
+
fragments.push(text.slice(start, end));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return fragments;
|
|
513
|
+
}
|
|
514
|
+
applySorting(results, sortBy, sortOrder = "desc") {
|
|
515
|
+
const sorted = [...results];
|
|
516
|
+
sorted.sort((a, b) => {
|
|
517
|
+
let comparison;
|
|
518
|
+
switch (sortBy) {
|
|
519
|
+
case "timestamp":
|
|
520
|
+
comparison = new Date(a.log.timestamp).getTime() - new Date(b.log.timestamp).getTime();
|
|
521
|
+
break;
|
|
522
|
+
case "level":
|
|
523
|
+
comparison = a.log.level.localeCompare(b.log.level);
|
|
524
|
+
break;
|
|
525
|
+
case "score":
|
|
526
|
+
case "relevance":
|
|
527
|
+
default:
|
|
528
|
+
comparison = a.score - b.score;
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
return sortOrder === "asc" ? comparison : -comparison;
|
|
532
|
+
});
|
|
533
|
+
return sorted;
|
|
534
|
+
}
|
|
535
|
+
applyPagination(results, offset = 0, limit = 100) {
|
|
536
|
+
return results.slice(offset, offset + limit);
|
|
537
|
+
}
|
|
538
|
+
async enrichWithContext(results, contextSize = 5) {
|
|
539
|
+
for (const result of results) {
|
|
540
|
+
const logIndex = this.logs.indexOf(result.log);
|
|
541
|
+
if (logIndex !== -1) {
|
|
542
|
+
const start = Math.max(0, logIndex - contextSize);
|
|
543
|
+
const end = Math.min(this.logs.length, logIndex + contextSize + 1);
|
|
544
|
+
result.context = this.logs.slice(start, end).filter((l) => l !== result.log);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
calculateSimilarity(log1, log2) {
|
|
549
|
+
let score = 0;
|
|
550
|
+
let factors = 0;
|
|
551
|
+
if (log1.level === log2.level) score += .3;
|
|
552
|
+
factors++;
|
|
553
|
+
if (log1.appName === log2.appName) score += .2;
|
|
554
|
+
factors++;
|
|
555
|
+
if (log1.traceId && log1.traceId === log2.traceId) score += .3;
|
|
556
|
+
factors++;
|
|
557
|
+
const messageSimilarity = this.calculateTextSimilarity(log1.message, log2.message);
|
|
558
|
+
score += messageSimilarity * .2;
|
|
559
|
+
factors++;
|
|
560
|
+
return score / factors;
|
|
561
|
+
}
|
|
562
|
+
calculateTextSimilarity(text1, text2) {
|
|
563
|
+
const words1 = new Set(text1.toLowerCase().split(/\s+/));
|
|
564
|
+
const words2 = new Set(text2.toLowerCase().split(/\s+/));
|
|
565
|
+
const intersection = new Set([...words1].filter((x) => words2.has(x)));
|
|
566
|
+
const union = new Set([...words1, ...words2]);
|
|
567
|
+
return union.size > 0 ? intersection.size / union.size : 0;
|
|
568
|
+
}
|
|
569
|
+
findMatchedPatterns(log1, log2) {
|
|
570
|
+
const patterns = [];
|
|
571
|
+
if (log1.level === log2.level) patterns.push("same_level");
|
|
572
|
+
if (log1.appName === log2.appName) patterns.push("same_service");
|
|
573
|
+
if (log1.traceId === log2.traceId) patterns.push("same_trace");
|
|
574
|
+
if (log1.context === log2.context) patterns.push("same_context");
|
|
575
|
+
return patterns;
|
|
576
|
+
}
|
|
577
|
+
generateSimilarityReason(log1, log2, similarity) {
|
|
578
|
+
const reasons = [];
|
|
579
|
+
if (log1.level === log2.level) reasons.push("same log level");
|
|
580
|
+
if (log1.appName === log2.appName) reasons.push("same service");
|
|
581
|
+
if (log1.traceId === log2.traceId) reasons.push("same trace ID");
|
|
582
|
+
return reasons.length > 0 ? `Similar because: ${reasons.join(", ")}` : `${Math.round(similarity * 100)}% content similarity`;
|
|
583
|
+
}
|
|
584
|
+
extractTimeRange(query) {
|
|
585
|
+
const lowerQuery = query.toLowerCase();
|
|
586
|
+
if (lowerQuery.includes("last hour") || lowerQuery.includes("past hour")) return { start: /* @__PURE__ */ new Date(Date.now() - 3600 * 1e3) };
|
|
587
|
+
const hoursMatch = query.match(/last\s+(\d+)\s+hours?/i);
|
|
588
|
+
if (hoursMatch) return { start: /* @__PURE__ */ new Date(Date.now() - Number.parseInt(hoursMatch[1] ?? "0") * 60 * 60 * 1e3) };
|
|
589
|
+
if (lowerQuery.includes("today")) {
|
|
590
|
+
const today = /* @__PURE__ */ new Date();
|
|
591
|
+
today.setHours(0, 0, 0, 0);
|
|
592
|
+
return { start: today };
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
addToSearchHistory(query) {
|
|
596
|
+
var _this$options3;
|
|
597
|
+
this.searchHistory.push(query);
|
|
598
|
+
const maxSize = ((_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.maxHistorySize) || 1e3;
|
|
599
|
+
if (this.searchHistory.length > maxSize) this.searchHistory = this.searchHistory.slice(-maxSize);
|
|
600
|
+
}
|
|
601
|
+
getTopTerms() {
|
|
602
|
+
const termCounts = /* @__PURE__ */ new Map();
|
|
603
|
+
for (const log of this.logs.slice(-1e3)) {
|
|
604
|
+
const words = log.message.toLowerCase().split(/\s+/);
|
|
605
|
+
for (const word of words) if (word.length > 3) termCounts.set(word, (termCounts.get(word) || 0) + 1);
|
|
606
|
+
}
|
|
607
|
+
return Array.from(termCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([term]) => term);
|
|
608
|
+
}
|
|
609
|
+
generateId() {
|
|
610
|
+
return `preset_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
//#endregion
|
|
615
|
+
//#region src/search/engines/correlation-engine.ts
|
|
616
|
+
/**
|
|
617
|
+
* Correlation engine for log analysis
|
|
618
|
+
*/
|
|
619
|
+
var CorrelationEngine = class {
|
|
620
|
+
constructor(options) {
|
|
621
|
+
this.options = options;
|
|
622
|
+
this.options = {
|
|
623
|
+
maxCorrelationDistance: 100,
|
|
624
|
+
temporalWindowMs: 300 * 1e3,
|
|
625
|
+
minSimilarityScore: .3,
|
|
626
|
+
...options
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Find logs related to a given log entry
|
|
631
|
+
*/
|
|
632
|
+
async findRelatedLogs(log, allLogs, limit = 50) {
|
|
633
|
+
const related = [];
|
|
634
|
+
for (const otherLog of allLogs) {
|
|
635
|
+
if (otherLog === log) continue;
|
|
636
|
+
const relationships = this.findRelationships(log, otherLog);
|
|
637
|
+
for (const relationship of relationships) {
|
|
638
|
+
var _this$options;
|
|
639
|
+
const score = this.calculateRelationshipScore(relationship, log, otherLog);
|
|
640
|
+
if (score > (((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.minSimilarityScore) || .3)) related.push({
|
|
641
|
+
log: otherLog,
|
|
642
|
+
relationship,
|
|
643
|
+
score
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return this.deduplicateRelatedLogs(related).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Correlate logs by multiple criteria
|
|
651
|
+
*/
|
|
652
|
+
async correlateByMultipleCriteria(logs, criteria) {
|
|
653
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
654
|
+
if (criteria.traceId) {
|
|
655
|
+
const traceCorrelations = this.correlateByTraceId(logs);
|
|
656
|
+
for (const [key, value] of traceCorrelations) correlations.set(`trace_${key}`, value);
|
|
657
|
+
}
|
|
658
|
+
if (criteria.userId) {
|
|
659
|
+
const userCorrelations = this.correlateByUserId(logs);
|
|
660
|
+
for (const [key, value] of userCorrelations) correlations.set(`user_${key}`, value);
|
|
661
|
+
}
|
|
662
|
+
if (criteria.sessionId) {
|
|
663
|
+
const sessionCorrelations = this.correlateBySessionId(logs);
|
|
664
|
+
for (const [key, value] of sessionCorrelations) correlations.set(`session_${key}`, value);
|
|
665
|
+
}
|
|
666
|
+
if (criteria.temporal) {
|
|
667
|
+
const temporalCorrelations = this.correlateByTemporalProximity(logs);
|
|
668
|
+
for (const [key, value] of temporalCorrelations) correlations.set(`temporal_${key}`, value);
|
|
669
|
+
}
|
|
670
|
+
if (criteria.errorCascade) {
|
|
671
|
+
const errorCorrelations = this.correlateErrorCascades(logs);
|
|
672
|
+
for (const [key, value] of errorCorrelations) correlations.set(`error_${key}`, value);
|
|
673
|
+
}
|
|
674
|
+
return correlations;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Build a timeline from correlated logs
|
|
678
|
+
*/
|
|
679
|
+
buildTimeline(logs) {
|
|
680
|
+
const timeline = [];
|
|
681
|
+
const sortedLogs = [...logs].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
682
|
+
for (let i = 0; i < sortedLogs.length; i++) {
|
|
683
|
+
const log = sortedLogs[i];
|
|
684
|
+
const eventType = this.determineEventType(log, sortedLogs, i);
|
|
685
|
+
const event = {
|
|
686
|
+
timestamp: new Date(log.timestamp),
|
|
687
|
+
log,
|
|
688
|
+
eventType
|
|
689
|
+
};
|
|
690
|
+
if (eventType === "start" && i < sortedLogs.length - 1) {
|
|
691
|
+
const endEvent = sortedLogs.slice(i + 1).find((l) => this.determineEventType(l, sortedLogs, sortedLogs.indexOf(l)) === "end");
|
|
692
|
+
if (endEvent) event.duration = new Date(endEvent.timestamp).getTime() - new Date(log.timestamp).getTime();
|
|
693
|
+
}
|
|
694
|
+
timeline.push(event);
|
|
695
|
+
}
|
|
696
|
+
return timeline;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Analyze error cascades
|
|
700
|
+
*/
|
|
701
|
+
async analyzeErrorCascade(logs) {
|
|
702
|
+
const errors = logs.filter((log) => log.level === "error");
|
|
703
|
+
if (errors.length === 0) return {
|
|
704
|
+
cascade: [],
|
|
705
|
+
impactedServices: []
|
|
706
|
+
};
|
|
707
|
+
const rootCause = errors.reduce((earliest, current) => new Date(current.timestamp) < new Date(earliest.timestamp) ? current : earliest);
|
|
708
|
+
const cascade = this.buildErrorCascade(rootCause, errors);
|
|
709
|
+
return {
|
|
710
|
+
rootCause,
|
|
711
|
+
cascade,
|
|
712
|
+
impactedServices: [...new Set(cascade.map((log) => log.appName))]
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
correlateByTraceId(logs) {
|
|
716
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
717
|
+
for (const log of logs) {
|
|
718
|
+
if (!log.traceId) continue;
|
|
719
|
+
if (!correlations.has(log.traceId)) correlations.set(log.traceId, []);
|
|
720
|
+
correlations.get(log.traceId).push(log);
|
|
721
|
+
}
|
|
722
|
+
return this.convertToCorrelatedLogs(correlations, "trace");
|
|
723
|
+
}
|
|
724
|
+
correlateByUserId(logs) {
|
|
725
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
726
|
+
for (const log of logs) {
|
|
727
|
+
var _log$payload;
|
|
728
|
+
const userId = (_log$payload = log.payload) === null || _log$payload === void 0 ? void 0 : _log$payload.userId;
|
|
729
|
+
if (!userId) continue;
|
|
730
|
+
if (!correlations.has(userId)) correlations.set(userId, []);
|
|
731
|
+
correlations.get(userId).push(log);
|
|
732
|
+
}
|
|
733
|
+
return this.convertToCorrelatedLogs(correlations, "user");
|
|
734
|
+
}
|
|
735
|
+
correlateBySessionId(logs) {
|
|
736
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
737
|
+
for (const log of logs) {
|
|
738
|
+
var _log$payload2;
|
|
739
|
+
const sessionId = (_log$payload2 = log.payload) === null || _log$payload2 === void 0 ? void 0 : _log$payload2.sessionId;
|
|
740
|
+
if (!sessionId) continue;
|
|
741
|
+
if (!correlations.has(sessionId)) correlations.set(sessionId, []);
|
|
742
|
+
correlations.get(sessionId).push(log);
|
|
743
|
+
}
|
|
744
|
+
return this.convertToCorrelatedLogs(correlations, "session");
|
|
745
|
+
}
|
|
746
|
+
correlateByTemporalProximity(logs) {
|
|
747
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
748
|
+
const sortedLogs = [...logs].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
749
|
+
let currentGroup = [];
|
|
750
|
+
let groupStartTime = null;
|
|
751
|
+
for (const log of sortedLogs) {
|
|
752
|
+
var _this$options2;
|
|
753
|
+
const logTime = new Date(log.timestamp).getTime();
|
|
754
|
+
if (groupStartTime === null) {
|
|
755
|
+
groupStartTime = logTime;
|
|
756
|
+
currentGroup = [log];
|
|
757
|
+
} else if (logTime - groupStartTime <= (((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.temporalWindowMs) || 3e5)) currentGroup.push(log);
|
|
758
|
+
else {
|
|
759
|
+
if (currentGroup.length > 1) {
|
|
760
|
+
const groupKey = `${groupStartTime}`;
|
|
761
|
+
correlations.set(groupKey, currentGroup);
|
|
762
|
+
}
|
|
763
|
+
groupStartTime = logTime;
|
|
764
|
+
currentGroup = [log];
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (currentGroup.length > 1 && groupStartTime !== null) correlations.set(`${groupStartTime}`, currentGroup);
|
|
768
|
+
return this.convertToCorrelatedLogs(correlations, "temporal");
|
|
769
|
+
}
|
|
770
|
+
correlateErrorCascades(logs) {
|
|
771
|
+
const correlations = /* @__PURE__ */ new Map();
|
|
772
|
+
const errors = logs.filter((log) => log.level === "error");
|
|
773
|
+
for (const error of errors) {
|
|
774
|
+
const cascade = this.buildErrorCascade(error, logs);
|
|
775
|
+
if (cascade.length > 1) {
|
|
776
|
+
const key = `${error.timestamp}_${error.message.slice(0, 20)}`;
|
|
777
|
+
correlations.set(key, cascade);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return this.convertToCorrelatedLogs(correlations, "error_cascade");
|
|
781
|
+
}
|
|
782
|
+
buildErrorCascade(rootError, allLogs) {
|
|
783
|
+
var _this$options3;
|
|
784
|
+
const cascade = [rootError];
|
|
785
|
+
const rootTime = new Date(rootError.timestamp).getTime();
|
|
786
|
+
const windowMs = ((_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.temporalWindowMs) || 3e5;
|
|
787
|
+
for (const log of allLogs) {
|
|
788
|
+
if (log === rootError) continue;
|
|
789
|
+
const timeDiff = new Date(log.timestamp).getTime() - rootTime;
|
|
790
|
+
if (timeDiff > 0 && timeDiff <= windowMs && (log.level === "error" || log.level === "warn") && (log.traceId === rootError.traceId || log.appName === rootError.appName)) cascade.push(log);
|
|
791
|
+
}
|
|
792
|
+
return cascade.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
793
|
+
}
|
|
794
|
+
findRelationships(log1, log2) {
|
|
795
|
+
var _log1$payload, _log2$payload, _log1$payload2, _log2$payload2, _this$options4, _this$options5;
|
|
796
|
+
const relationships = [];
|
|
797
|
+
if (log1.traceId && log1.traceId === log2.traceId) relationships.push("same_trace");
|
|
798
|
+
const user1 = (_log1$payload = log1.payload) === null || _log1$payload === void 0 ? void 0 : _log1$payload.userId;
|
|
799
|
+
const user2 = (_log2$payload = log2.payload) === null || _log2$payload === void 0 ? void 0 : _log2$payload.userId;
|
|
800
|
+
if (user1 && user1 === user2) relationships.push("same_user");
|
|
801
|
+
const session1 = (_log1$payload2 = log1.payload) === null || _log1$payload2 === void 0 ? void 0 : _log1$payload2.sessionId;
|
|
802
|
+
const session2 = (_log2$payload2 = log2.payload) === null || _log2$payload2 === void 0 ? void 0 : _log2$payload2.sessionId;
|
|
803
|
+
if (session1 && session1 === session2) relationships.push("same_session");
|
|
804
|
+
const time1 = new Date(log1.timestamp).getTime();
|
|
805
|
+
const time2 = new Date(log2.timestamp).getTime();
|
|
806
|
+
if (Math.abs(time1 - time2) <= (((_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.temporalWindowMs) || 3e5)) relationships.push("temporal_proximity");
|
|
807
|
+
if ((log1.level === "error" || log2.level === "error") && time2 > time1 && time2 - time1 <= (((_this$options5 = this.options) === null || _this$options5 === void 0 ? void 0 : _this$options5.temporalWindowMs) || 3e5)) relationships.push("error_cascade");
|
|
808
|
+
if (this.haveSimilarPattern(log1, log2)) relationships.push("similar_pattern");
|
|
809
|
+
return relationships;
|
|
810
|
+
}
|
|
811
|
+
calculateRelationshipScore(relationship, log1, log2) {
|
|
812
|
+
let score = {
|
|
813
|
+
same_trace: .9,
|
|
814
|
+
same_user: .7,
|
|
815
|
+
same_session: .8,
|
|
816
|
+
temporal_proximity: .4,
|
|
817
|
+
error_cascade: .8,
|
|
818
|
+
similar_pattern: .5
|
|
819
|
+
}[relationship] || .3;
|
|
820
|
+
if (log1.appName === log2.appName) score += .1;
|
|
821
|
+
return Math.min(score, 1);
|
|
822
|
+
}
|
|
823
|
+
haveSimilarPattern(log1, log2) {
|
|
824
|
+
return this.normalizeMessage(log1.message) === this.normalizeMessage(log2.message);
|
|
825
|
+
}
|
|
826
|
+
normalizeMessage(message) {
|
|
827
|
+
return message.replace(/\d+/g, "<NUM>").replace(/[a-f0-9-]{36}/gi, "<UUID>").toLowerCase().trim();
|
|
828
|
+
}
|
|
829
|
+
determineEventType(log, _allLogs, _index) {
|
|
830
|
+
const message = log.message.toLowerCase();
|
|
831
|
+
if (message.includes("start") || message.includes("begin") || message.includes("initiated")) return "start";
|
|
832
|
+
if (message.includes("end") || message.includes("complete") || message.includes("finished")) return "end";
|
|
833
|
+
if (log.level === "error") return "error";
|
|
834
|
+
if (message.includes("milestone") || message.includes("checkpoint")) return "milestone";
|
|
835
|
+
return "info";
|
|
836
|
+
}
|
|
837
|
+
deduplicateRelatedLogs(related) {
|
|
838
|
+
const seen = /* @__PURE__ */ new Set();
|
|
839
|
+
const unique = [];
|
|
840
|
+
for (const item of related) if (!seen.has(item.log)) {
|
|
841
|
+
seen.add(item.log);
|
|
842
|
+
unique.push(item);
|
|
843
|
+
}
|
|
844
|
+
return unique;
|
|
845
|
+
}
|
|
846
|
+
convertToCorrelatedLogs(correlations, type) {
|
|
847
|
+
const result = /* @__PURE__ */ new Map();
|
|
848
|
+
for (const [key, logs] of correlations.entries()) {
|
|
849
|
+
if (logs.length < 2) continue;
|
|
850
|
+
const timeline = this.buildTimeline(logs);
|
|
851
|
+
const summary = this.generateSummary(logs);
|
|
852
|
+
result.set(key, {
|
|
853
|
+
correlationKey: key,
|
|
854
|
+
...type === "trace" ? { traceId: key } : {},
|
|
855
|
+
logs,
|
|
856
|
+
timeline,
|
|
857
|
+
summary
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
return result;
|
|
861
|
+
}
|
|
862
|
+
generateSummary(logs) {
|
|
863
|
+
const errorCount = logs.filter((l) => l.level === "error").length;
|
|
864
|
+
const warningCount = logs.filter((l) => l.level === "warn").length;
|
|
865
|
+
const services = [...new Set(logs.map((l) => l.appName))];
|
|
866
|
+
let duration;
|
|
867
|
+
if (logs.length > 1) {
|
|
868
|
+
const sorted = [...logs].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
869
|
+
const start = new Date(sorted[0].timestamp).getTime();
|
|
870
|
+
duration = new Date(sorted[sorted.length - 1].timestamp).getTime() - start;
|
|
871
|
+
}
|
|
872
|
+
return {
|
|
873
|
+
totalLogs: logs.length,
|
|
874
|
+
errorCount,
|
|
875
|
+
warningCount,
|
|
876
|
+
services,
|
|
877
|
+
...duration !== void 0 ? { duration } : {}
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
//#endregion
|
|
883
|
+
//#region src/search/engines/nlp-search-engine.ts
|
|
884
|
+
/**
|
|
885
|
+
* NLP-enhanced search engine
|
|
886
|
+
*/
|
|
887
|
+
var NLPSearchEngine = class extends BasicSearchEngine {
|
|
888
|
+
constructor(options) {
|
|
889
|
+
super(options);
|
|
890
|
+
this.initializePatterns();
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Enhanced natural language query parsing
|
|
894
|
+
*/
|
|
895
|
+
async parseNaturalLanguageQuery(query) {
|
|
896
|
+
const entities = [];
|
|
897
|
+
const filters = {};
|
|
898
|
+
const intent = this.detectIntent(query);
|
|
899
|
+
const extractedEntities = this.extractEntities(query);
|
|
900
|
+
entities.push(...extractedEntities);
|
|
901
|
+
for (const entity of entities) this.applyEntityToFilter(entity, filters);
|
|
902
|
+
const timeRange = this.extractAdvancedTimeRange(query);
|
|
903
|
+
if (timeRange) filters.timeRange = timeRange;
|
|
904
|
+
const confidence = this.calculateConfidence(intent, entities, query);
|
|
905
|
+
return {
|
|
906
|
+
originalQuery: query,
|
|
907
|
+
intent,
|
|
908
|
+
entities,
|
|
909
|
+
filters,
|
|
910
|
+
...timeRange !== void 0 ? { timeRange } : {},
|
|
911
|
+
confidence
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Enhanced natural language search
|
|
916
|
+
*/
|
|
917
|
+
async naturalLanguageSearch(query) {
|
|
918
|
+
const parsed = await this.parseNaturalLanguageQuery(query);
|
|
919
|
+
const options = this.getOptionsForIntent(parsed.intent);
|
|
920
|
+
const cleanQuery = this.extractCleanQuery(query, parsed.entities);
|
|
921
|
+
return this.search(cleanQuery, parsed.filters, options);
|
|
922
|
+
}
|
|
923
|
+
initializePatterns() {
|
|
924
|
+
this.intentPatterns = new Map([
|
|
925
|
+
["find_errors", [
|
|
926
|
+
/show.*errors?/i,
|
|
927
|
+
/find.*errors?/i,
|
|
928
|
+
/all.*errors?/i,
|
|
929
|
+
/errors?\s+(?:in|from|for)/i,
|
|
930
|
+
/what.*went wrong/i,
|
|
931
|
+
/failures?/i
|
|
932
|
+
]],
|
|
933
|
+
["trace_request", [
|
|
934
|
+
/trace\s+(?:request|id)/i,
|
|
935
|
+
/follow\s+request/i,
|
|
936
|
+
/track\s+request/i,
|
|
937
|
+
/request\s+(?:flow|path)/i,
|
|
938
|
+
/trace.*across/i
|
|
939
|
+
]],
|
|
940
|
+
["find_user_activity", [
|
|
941
|
+
/user\s+(?:\w+|id)/i,
|
|
942
|
+
/activity\s+(?:for|of)\s+user/i,
|
|
943
|
+
/what\s+did\s+user/i,
|
|
944
|
+
/user\s+journey/i,
|
|
945
|
+
/user\s+session/i
|
|
946
|
+
]],
|
|
947
|
+
["performance_analysis", [
|
|
948
|
+
/slow\s+(?:queries?|requests?|operations?)/i,
|
|
949
|
+
/performance\s+issues?/i,
|
|
950
|
+
/latency/i,
|
|
951
|
+
/response\s+time/i,
|
|
952
|
+
/took\s+(?:too\s+)?long/i
|
|
953
|
+
]],
|
|
954
|
+
["time_range_query", [
|
|
955
|
+
/(?:in|during|from)\s+the\s+last/i,
|
|
956
|
+
/(?:today|yesterday|this\s+week)/i,
|
|
957
|
+
/between.*and/i,
|
|
958
|
+
/in\s+the\s+past/i
|
|
959
|
+
]],
|
|
960
|
+
["correlation", [
|
|
961
|
+
/related\s+to/i,
|
|
962
|
+
/connected\s+with/i,
|
|
963
|
+
/caused\s+by/i,
|
|
964
|
+
/before.*happened/i,
|
|
965
|
+
/after.*occurred/i
|
|
966
|
+
]]
|
|
967
|
+
]);
|
|
968
|
+
this.entityPatterns = new Map([
|
|
969
|
+
["level", /(error|warn|warning|info|debug|trace|verbose)/i],
|
|
970
|
+
["service", /(?:from|in)\s+(?:the\s+)?(\w+)\s+(?:service|app|application)/i],
|
|
971
|
+
["user_id", /user\s+(?:id\s+)?['"]?(\w+)['"]?/i],
|
|
972
|
+
["trace_id", /trace\s+(?:id\s+)?['"]?([\w-]+)['"]?/i],
|
|
973
|
+
["time", /(?:last|past|previous)\s+(\d+)\s+(second|minute|hour|day|week)s?/i],
|
|
974
|
+
["error_type", /(\w+Error|\w+Exception)/i]
|
|
975
|
+
]);
|
|
976
|
+
}
|
|
977
|
+
detectIntent(query) {
|
|
978
|
+
let maxScore = 0;
|
|
979
|
+
let detectedIntent = "general_search";
|
|
980
|
+
for (const [intent, patterns] of this.intentPatterns.entries()) {
|
|
981
|
+
let score = 0;
|
|
982
|
+
for (const pattern of patterns) if (pattern.test(query)) score++;
|
|
983
|
+
if (score > maxScore) {
|
|
984
|
+
maxScore = score;
|
|
985
|
+
detectedIntent = intent;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return detectedIntent;
|
|
989
|
+
}
|
|
990
|
+
extractEntities(query) {
|
|
991
|
+
const entities = [];
|
|
992
|
+
for (const [type, pattern] of this.entityPatterns.entries()) {
|
|
993
|
+
const matches = query.matchAll(new RegExp(pattern, "gi"));
|
|
994
|
+
for (const match of matches) {
|
|
995
|
+
const value = match[1] || match[0];
|
|
996
|
+
entities.push({
|
|
997
|
+
type,
|
|
998
|
+
value: value.trim(),
|
|
999
|
+
confidence: .8
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return entities;
|
|
1004
|
+
}
|
|
1005
|
+
applyEntityToFilter(entity, filters) {
|
|
1006
|
+
switch (entity.type) {
|
|
1007
|
+
case "level":
|
|
1008
|
+
if (!filters.levels) filters.levels = [];
|
|
1009
|
+
filters.levels.push(entity.value.toLowerCase());
|
|
1010
|
+
break;
|
|
1011
|
+
case "service":
|
|
1012
|
+
if (!filters.services) filters.services = [];
|
|
1013
|
+
filters.services.push(entity.value);
|
|
1014
|
+
break;
|
|
1015
|
+
case "user_id":
|
|
1016
|
+
if (!filters.userIds) filters.userIds = [];
|
|
1017
|
+
filters.userIds.push(entity.value);
|
|
1018
|
+
break;
|
|
1019
|
+
case "trace_id":
|
|
1020
|
+
if (!filters.traceIds) filters.traceIds = [];
|
|
1021
|
+
filters.traceIds.push(entity.value);
|
|
1022
|
+
break;
|
|
1023
|
+
case "error_type": break;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
extractAdvancedTimeRange(query) {
|
|
1027
|
+
const lowerQuery = query.toLowerCase();
|
|
1028
|
+
for (const { pattern, unit } of [
|
|
1029
|
+
{
|
|
1030
|
+
pattern: /last\s+(\d+)\s+second/i,
|
|
1031
|
+
unit: "seconds"
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
pattern: /last\s+(\d+)\s+minute/i,
|
|
1035
|
+
unit: "minutes"
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
pattern: /last\s+(\d+)\s+hour/i,
|
|
1039
|
+
unit: "hours"
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
pattern: /last\s+(\d+)\s+day/i,
|
|
1043
|
+
unit: "days"
|
|
1044
|
+
}
|
|
1045
|
+
]) {
|
|
1046
|
+
const match = query.match(pattern);
|
|
1047
|
+
if (match) {
|
|
1048
|
+
const value = Number.parseInt(match[1] ?? "0");
|
|
1049
|
+
const multiplier = {
|
|
1050
|
+
seconds: 1e3,
|
|
1051
|
+
minutes: 60 * 1e3,
|
|
1052
|
+
hours: 3600 * 1e3,
|
|
1053
|
+
days: 1440 * 60 * 1e3
|
|
1054
|
+
}[unit];
|
|
1055
|
+
return {
|
|
1056
|
+
start: new Date(Date.now() - value * multiplier),
|
|
1057
|
+
relative: {
|
|
1058
|
+
value,
|
|
1059
|
+
unit
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (lowerQuery.includes("today")) {
|
|
1065
|
+
const today = /* @__PURE__ */ new Date();
|
|
1066
|
+
today.setHours(0, 0, 0, 0);
|
|
1067
|
+
return { start: today };
|
|
1068
|
+
}
|
|
1069
|
+
if (lowerQuery.includes("yesterday")) {
|
|
1070
|
+
const yesterday = /* @__PURE__ */ new Date();
|
|
1071
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
1072
|
+
yesterday.setHours(0, 0, 0, 0);
|
|
1073
|
+
const endOfYesterday = new Date(yesterday);
|
|
1074
|
+
endOfYesterday.setHours(23, 59, 59, 999);
|
|
1075
|
+
return {
|
|
1076
|
+
start: yesterday,
|
|
1077
|
+
end: endOfYesterday
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
if (lowerQuery.includes("this week")) {
|
|
1081
|
+
const now = /* @__PURE__ */ new Date();
|
|
1082
|
+
const startOfWeek = new Date(now);
|
|
1083
|
+
startOfWeek.setDate(now.getDate() - now.getDay());
|
|
1084
|
+
startOfWeek.setHours(0, 0, 0, 0);
|
|
1085
|
+
return { start: startOfWeek };
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
calculateConfidence(intent, entities, query) {
|
|
1089
|
+
let confidence = .5;
|
|
1090
|
+
if (intent !== "general_search") confidence += .2;
|
|
1091
|
+
confidence += Math.min(entities.length * .1, .3);
|
|
1092
|
+
const wordCount = query.split(/\s+/).length;
|
|
1093
|
+
if (wordCount < 3 || wordCount > 20) confidence -= .1;
|
|
1094
|
+
return Math.max(0, Math.min(1, confidence));
|
|
1095
|
+
}
|
|
1096
|
+
getOptionsForIntent(intent) {
|
|
1097
|
+
const baseOptions = {
|
|
1098
|
+
limit: 100,
|
|
1099
|
+
highlightMatches: true
|
|
1100
|
+
};
|
|
1101
|
+
switch (intent) {
|
|
1102
|
+
case "find_errors": return {
|
|
1103
|
+
...baseOptions,
|
|
1104
|
+
includeContext: true,
|
|
1105
|
+
contextSize: 3,
|
|
1106
|
+
findSimilar: true
|
|
1107
|
+
};
|
|
1108
|
+
case "trace_request": return {
|
|
1109
|
+
...baseOptions,
|
|
1110
|
+
includeContext: true,
|
|
1111
|
+
contextSize: 10,
|
|
1112
|
+
correlate: true,
|
|
1113
|
+
sortBy: "timestamp",
|
|
1114
|
+
sortOrder: "asc"
|
|
1115
|
+
};
|
|
1116
|
+
case "find_user_activity": return {
|
|
1117
|
+
...baseOptions,
|
|
1118
|
+
includeContext: true,
|
|
1119
|
+
sortBy: "timestamp",
|
|
1120
|
+
sortOrder: "asc",
|
|
1121
|
+
limit: 200
|
|
1122
|
+
};
|
|
1123
|
+
case "performance_analysis": return {
|
|
1124
|
+
...baseOptions,
|
|
1125
|
+
includeContext: true,
|
|
1126
|
+
contextSize: 5,
|
|
1127
|
+
sortBy: "timestamp"
|
|
1128
|
+
};
|
|
1129
|
+
case "correlation": return {
|
|
1130
|
+
...baseOptions,
|
|
1131
|
+
includeContext: true,
|
|
1132
|
+
contextSize: 5,
|
|
1133
|
+
correlate: true,
|
|
1134
|
+
findSimilar: true
|
|
1135
|
+
};
|
|
1136
|
+
default: return baseOptions;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
extractCleanQuery(query, entities) {
|
|
1140
|
+
let cleanQuery = query;
|
|
1141
|
+
for (const entity of entities) cleanQuery = cleanQuery.replace(new RegExp(`\\b${entity.value}\\b`, "gi"), "");
|
|
1142
|
+
for (const word of [
|
|
1143
|
+
"show",
|
|
1144
|
+
"find",
|
|
1145
|
+
"get",
|
|
1146
|
+
"all",
|
|
1147
|
+
"from",
|
|
1148
|
+
"in",
|
|
1149
|
+
"the",
|
|
1150
|
+
"for",
|
|
1151
|
+
"with",
|
|
1152
|
+
"last",
|
|
1153
|
+
"past",
|
|
1154
|
+
"today",
|
|
1155
|
+
"yesterday",
|
|
1156
|
+
"service",
|
|
1157
|
+
"user",
|
|
1158
|
+
"trace",
|
|
1159
|
+
"error",
|
|
1160
|
+
"errors"
|
|
1161
|
+
]) cleanQuery = cleanQuery.replace(new RegExp(`\\b${word}\\b`, "gi"), "");
|
|
1162
|
+
cleanQuery = cleanQuery.replace(/\s+/g, " ").trim();
|
|
1163
|
+
return cleanQuery || query;
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
//#endregion
|
|
1168
|
+
//#region src/search/engines/pattern-recognition-engine.ts
|
|
1169
|
+
/**
|
|
1170
|
+
* Pattern recognition engine for log analysis
|
|
1171
|
+
*/
|
|
1172
|
+
var PatternRecognitionEngine = class {
|
|
1173
|
+
constructor(options) {
|
|
1174
|
+
this.options = options;
|
|
1175
|
+
this.patterns = /* @__PURE__ */ new Map();
|
|
1176
|
+
this.patternFrequencies = /* @__PURE__ */ new Map();
|
|
1177
|
+
this.options = {
|
|
1178
|
+
minFrequency: 3,
|
|
1179
|
+
maxPatterns: 1e3,
|
|
1180
|
+
anomalyThreshold: .3,
|
|
1181
|
+
...options
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Analyze logs and detect patterns
|
|
1186
|
+
*/
|
|
1187
|
+
async analyzePatterns(logs) {
|
|
1188
|
+
var _this$options2;
|
|
1189
|
+
const messagePatterns = this.extractMessagePatterns(logs);
|
|
1190
|
+
const errorPatterns = this.extractErrorPatterns(logs);
|
|
1191
|
+
const timingPatterns = this.extractTimingPatterns(logs);
|
|
1192
|
+
const frequentPatterns = [
|
|
1193
|
+
...messagePatterns,
|
|
1194
|
+
...errorPatterns,
|
|
1195
|
+
...timingPatterns
|
|
1196
|
+
].filter((p) => {
|
|
1197
|
+
var _this$options;
|
|
1198
|
+
return p.frequency >= (((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.minFrequency) || 3);
|
|
1199
|
+
});
|
|
1200
|
+
frequentPatterns.sort((a, b) => b.frequency - a.frequency);
|
|
1201
|
+
const limitedPatterns = frequentPatterns.slice(0, ((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.maxPatterns) || 1e3);
|
|
1202
|
+
for (const pattern of limitedPatterns) this.patterns.set(pattern.id, pattern);
|
|
1203
|
+
return limitedPatterns;
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Detect anomalies in logs
|
|
1207
|
+
*/
|
|
1208
|
+
async detectAnomalies(logs) {
|
|
1209
|
+
const anomalies = [];
|
|
1210
|
+
for (const log of logs) {
|
|
1211
|
+
var _this$options3;
|
|
1212
|
+
const anomalyScore = await this.calculateAnomalyScore(log);
|
|
1213
|
+
if (anomalyScore > (((_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.anomalyThreshold) || .3)) anomalies.push({
|
|
1214
|
+
log,
|
|
1215
|
+
anomalyScore,
|
|
1216
|
+
reason: this.generateAnomalyReason(log, anomalyScore),
|
|
1217
|
+
deviations: this.findDeviations(log)
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
return anomalies.sort((a, b) => b.anomalyScore - a.anomalyScore);
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Find patterns matching a log entry
|
|
1224
|
+
*/
|
|
1225
|
+
findMatchingPatterns(log) {
|
|
1226
|
+
const matching = [];
|
|
1227
|
+
for (const pattern of this.patterns.values()) if (this.doesLogMatchPattern(log, pattern)) matching.push(pattern);
|
|
1228
|
+
return matching;
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Get all detected patterns
|
|
1232
|
+
*/
|
|
1233
|
+
getPatterns() {
|
|
1234
|
+
return Array.from(this.patterns.values());
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Get pattern by ID
|
|
1238
|
+
*/
|
|
1239
|
+
getPattern(patternId) {
|
|
1240
|
+
return this.patterns.get(patternId);
|
|
1241
|
+
}
|
|
1242
|
+
extractMessagePatterns(logs) {
|
|
1243
|
+
const patternMap = /* @__PURE__ */ new Map();
|
|
1244
|
+
for (const log of logs) {
|
|
1245
|
+
const normalizedMessage = this.normalizeMessage(log.message);
|
|
1246
|
+
if (!patternMap.has(normalizedMessage)) patternMap.set(normalizedMessage, {
|
|
1247
|
+
examples: [],
|
|
1248
|
+
count: 0
|
|
1249
|
+
});
|
|
1250
|
+
const pattern = patternMap.get(normalizedMessage);
|
|
1251
|
+
if (pattern.examples.length < 3) pattern.examples.push(log);
|
|
1252
|
+
pattern.count++;
|
|
1253
|
+
}
|
|
1254
|
+
return Array.from(patternMap.entries()).map(([pattern, data], index) => {
|
|
1255
|
+
var _data$examples;
|
|
1256
|
+
return {
|
|
1257
|
+
id: `msg_pattern_${index}`,
|
|
1258
|
+
pattern,
|
|
1259
|
+
examples: data.examples,
|
|
1260
|
+
frequency: data.count,
|
|
1261
|
+
lastSeen: ((_data$examples = data.examples[data.examples.length - 1]) === null || _data$examples === void 0 ? void 0 : _data$examples.timestamp) ? new Date(data.examples[data.examples.length - 1].timestamp) : /* @__PURE__ */ new Date(),
|
|
1262
|
+
category: "message"
|
|
1263
|
+
};
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
extractErrorPatterns(logs) {
|
|
1267
|
+
const errorLogs = logs.filter((log) => log.level === "error" || log.error);
|
|
1268
|
+
const patternMap = /* @__PURE__ */ new Map();
|
|
1269
|
+
for (const log of errorLogs) {
|
|
1270
|
+
const errorPattern = this.extractErrorPattern(log);
|
|
1271
|
+
if (!patternMap.has(errorPattern)) patternMap.set(errorPattern, {
|
|
1272
|
+
examples: [],
|
|
1273
|
+
count: 0
|
|
1274
|
+
});
|
|
1275
|
+
const pattern = patternMap.get(errorPattern);
|
|
1276
|
+
if (pattern.examples.length < 3) pattern.examples.push(log);
|
|
1277
|
+
pattern.count++;
|
|
1278
|
+
}
|
|
1279
|
+
return Array.from(patternMap.entries()).map(([pattern, data], index) => {
|
|
1280
|
+
var _data$examples2;
|
|
1281
|
+
return {
|
|
1282
|
+
id: `error_pattern_${index}`,
|
|
1283
|
+
pattern,
|
|
1284
|
+
examples: data.examples,
|
|
1285
|
+
frequency: data.count,
|
|
1286
|
+
lastSeen: ((_data$examples2 = data.examples[data.examples.length - 1]) === null || _data$examples2 === void 0 ? void 0 : _data$examples2.timestamp) ? new Date(data.examples[data.examples.length - 1].timestamp) : /* @__PURE__ */ new Date(),
|
|
1287
|
+
category: "error",
|
|
1288
|
+
severity: "high"
|
|
1289
|
+
};
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
extractTimingPatterns(logs) {
|
|
1293
|
+
const patterns = [];
|
|
1294
|
+
const hourCounts = /* @__PURE__ */ new Map();
|
|
1295
|
+
for (const log of logs) {
|
|
1296
|
+
const hour = new Date(log.timestamp).getHours();
|
|
1297
|
+
hourCounts.set(hour, (hourCounts.get(hour) || 0) + 1);
|
|
1298
|
+
}
|
|
1299
|
+
const peakHour = Array.from(hourCounts.entries()).sort((a, b) => b[1] - a[1])[0];
|
|
1300
|
+
if (peakHour) patterns.push({
|
|
1301
|
+
id: "timing_peak",
|
|
1302
|
+
pattern: `Peak activity at hour ${peakHour[0]}`,
|
|
1303
|
+
examples: logs.slice(0, 3),
|
|
1304
|
+
frequency: peakHour[1],
|
|
1305
|
+
lastSeen: /* @__PURE__ */ new Date(),
|
|
1306
|
+
category: "timing"
|
|
1307
|
+
});
|
|
1308
|
+
return patterns;
|
|
1309
|
+
}
|
|
1310
|
+
normalizeMessage(message) {
|
|
1311
|
+
return message.replace(/\d+/g, "<NUM>").replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, "<UUID>").replace(/[a-f0-9]{32}/gi, "<HASH>").replace(/"[^"]*"/g, "<STRING>").replace(/\b\w+@\w+\.\w+\b/g, "<EMAIL>").trim();
|
|
1312
|
+
}
|
|
1313
|
+
extractErrorPattern(log) {
|
|
1314
|
+
if (log.error) return `${log.error.name}: ${this.normalizeMessage(log.error.message || "")}`;
|
|
1315
|
+
return this.normalizeMessage(log.message);
|
|
1316
|
+
}
|
|
1317
|
+
async calculateAnomalyScore(log) {
|
|
1318
|
+
let score = 0;
|
|
1319
|
+
if (this.findMatchingPatterns(log).length === 0) score += .3;
|
|
1320
|
+
if (log.level === "error") {
|
|
1321
|
+
const errorPattern = this.extractErrorPattern(log);
|
|
1322
|
+
if ((this.patternFrequencies.get(errorPattern) || 0) < 2) score += .3;
|
|
1323
|
+
}
|
|
1324
|
+
const hour = new Date(log.timestamp).getHours();
|
|
1325
|
+
if (hour < 6 || hour > 22) score += .2;
|
|
1326
|
+
return Math.min(score, 1);
|
|
1327
|
+
}
|
|
1328
|
+
generateAnomalyReason(log, score) {
|
|
1329
|
+
const reasons = [];
|
|
1330
|
+
if (score > .7) reasons.push("Highly unusual log entry");
|
|
1331
|
+
else if (score > .5) reasons.push("Moderately unusual log entry");
|
|
1332
|
+
else reasons.push("Slightly unusual log entry");
|
|
1333
|
+
if (this.findMatchingPatterns(log).length === 0) reasons.push("does not match any known patterns");
|
|
1334
|
+
if (log.level === "error") reasons.push("rare error type");
|
|
1335
|
+
const hour = new Date(log.timestamp).getHours();
|
|
1336
|
+
if (hour < 6 || hour > 22) reasons.push("occurred during off-hours");
|
|
1337
|
+
return reasons.join(", ");
|
|
1338
|
+
}
|
|
1339
|
+
findDeviations(log) {
|
|
1340
|
+
const deviations = [];
|
|
1341
|
+
if (!log.traceId) deviations.push("Missing trace ID");
|
|
1342
|
+
if (!log.context) deviations.push("Missing context");
|
|
1343
|
+
if (log.payload && Object.keys(log.payload).length > 20) deviations.push("Unusually large payload");
|
|
1344
|
+
if (log.level !== "error" && log.message.includes("at ")) deviations.push("Stack trace in non-error log");
|
|
1345
|
+
return deviations;
|
|
1346
|
+
}
|
|
1347
|
+
doesLogMatchPattern(log, pattern) {
|
|
1348
|
+
const normalizedMessage = this.normalizeMessage(log.message);
|
|
1349
|
+
if (pattern.regex) return pattern.regex.test(log.message);
|
|
1350
|
+
return normalizedMessage === pattern.pattern;
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
//#endregion
|
|
1355
|
+
//#region src/search/search-manager.ts
|
|
1356
|
+
/**
|
|
1357
|
+
* Main search manager class
|
|
1358
|
+
*/
|
|
1359
|
+
var SearchManager = class {
|
|
1360
|
+
constructor(config) {
|
|
1361
|
+
this.config = {
|
|
1362
|
+
enableNLP: true,
|
|
1363
|
+
enablePatternRecognition: true,
|
|
1364
|
+
enableCorrelation: true,
|
|
1365
|
+
maxIndexSize: 1e6,
|
|
1366
|
+
autoOptimize: true,
|
|
1367
|
+
...config
|
|
1368
|
+
};
|
|
1369
|
+
this.searchEngine = this.config.enableNLP ? new NLPSearchEngine() : new BasicSearchEngine();
|
|
1370
|
+
this.indexer = new BasicLogIndexer({
|
|
1371
|
+
maxIndexSize: this.config.maxIndexSize,
|
|
1372
|
+
autoOptimize: this.config.autoOptimize
|
|
1373
|
+
});
|
|
1374
|
+
if (this.config.enablePatternRecognition) this.patternEngine = new PatternRecognitionEngine();
|
|
1375
|
+
if (this.config.enableCorrelation) this.correlationEngine = new CorrelationEngine();
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Index new logs
|
|
1379
|
+
*/
|
|
1380
|
+
async indexLogs(logs) {
|
|
1381
|
+
await this.indexer.indexBatch(logs);
|
|
1382
|
+
this.searchEngine.addLogs(logs);
|
|
1383
|
+
if (this.patternEngine && logs.length > 10) await this.patternEngine.analyzePatterns(logs);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Add a single log to the index
|
|
1387
|
+
*/
|
|
1388
|
+
async indexLog(log) {
|
|
1389
|
+
await this.indexer.indexLog(log);
|
|
1390
|
+
this.searchEngine.addLogs([log]);
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Perform a search
|
|
1394
|
+
*/
|
|
1395
|
+
async search(query, filters, options) {
|
|
1396
|
+
return this.searchEngine.search(query, filters, options);
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Perform a natural language search
|
|
1400
|
+
*/
|
|
1401
|
+
async naturalLanguageSearch(query) {
|
|
1402
|
+
return this.searchEngine.naturalLanguageSearch(query);
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Find logs correlated by trace ID
|
|
1406
|
+
*/
|
|
1407
|
+
async correlateByTraceId(traceId) {
|
|
1408
|
+
return this.searchEngine.correlateByTraceId(traceId);
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Find similar logs
|
|
1412
|
+
*/
|
|
1413
|
+
async findSimilarLogs(logEntry, limit) {
|
|
1414
|
+
return this.searchEngine.findSimilarLogs(logEntry, limit);
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Find logs related to a given log
|
|
1418
|
+
*/
|
|
1419
|
+
async findRelatedLogs(log, limit) {
|
|
1420
|
+
if (!this.correlationEngine) throw new Error("Correlation engine not enabled");
|
|
1421
|
+
const allLogs = this.searchEngine.getLogs();
|
|
1422
|
+
return this.correlationEngine.findRelatedLogs(log, allLogs, limit);
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Get search suggestions
|
|
1426
|
+
*/
|
|
1427
|
+
async getSuggestions(partialQuery, limit) {
|
|
1428
|
+
return this.searchEngine.getSuggestions(partialQuery, limit);
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Get search statistics
|
|
1432
|
+
*/
|
|
1433
|
+
async getStats() {
|
|
1434
|
+
return this.searchEngine.getStats();
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Parse natural language query
|
|
1438
|
+
*/
|
|
1439
|
+
async parseNaturalLanguageQuery(query) {
|
|
1440
|
+
return this.searchEngine.parseNaturalLanguageQuery(query);
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Save a search preset
|
|
1444
|
+
*/
|
|
1445
|
+
async savePreset(preset) {
|
|
1446
|
+
return this.searchEngine.savePreset(preset);
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Get saved presets
|
|
1450
|
+
*/
|
|
1451
|
+
async getPresets(userId) {
|
|
1452
|
+
return this.searchEngine.getPresets(userId);
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Delete a preset
|
|
1456
|
+
*/
|
|
1457
|
+
async deletePreset(presetId) {
|
|
1458
|
+
return this.searchEngine.deletePreset(presetId);
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Detect log patterns
|
|
1462
|
+
*/
|
|
1463
|
+
async detectPatterns() {
|
|
1464
|
+
if (!this.patternEngine) throw new Error("Pattern recognition not enabled");
|
|
1465
|
+
const allLogs = this.searchEngine.getLogs();
|
|
1466
|
+
return this.patternEngine.analyzePatterns(allLogs);
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Get detected patterns
|
|
1470
|
+
*/
|
|
1471
|
+
getPatterns() {
|
|
1472
|
+
if (!this.patternEngine) return [];
|
|
1473
|
+
return this.patternEngine.getPatterns();
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Detect anomalies in logs
|
|
1477
|
+
*/
|
|
1478
|
+
async detectAnomalies() {
|
|
1479
|
+
if (!this.patternEngine) throw new Error("Pattern recognition not enabled");
|
|
1480
|
+
const allLogs = this.searchEngine.getLogs();
|
|
1481
|
+
return this.patternEngine.detectAnomalies(allLogs);
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Correlate logs by multiple criteria
|
|
1485
|
+
*/
|
|
1486
|
+
async correlateByMultipleCriteria(criteria) {
|
|
1487
|
+
if (!this.correlationEngine) throw new Error("Correlation engine not enabled");
|
|
1488
|
+
const allLogs = this.searchEngine.getLogs();
|
|
1489
|
+
return this.correlationEngine.correlateByMultipleCriteria(allLogs, criteria);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Analyze error cascades
|
|
1493
|
+
*/
|
|
1494
|
+
async analyzeErrorCascade(traceId) {
|
|
1495
|
+
if (!this.correlationEngine) throw new Error("Correlation engine not enabled");
|
|
1496
|
+
const correlated = await this.correlateByTraceId(traceId);
|
|
1497
|
+
return this.correlationEngine.analyzeErrorCascade(correlated.logs);
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Export search results
|
|
1501
|
+
*/
|
|
1502
|
+
async exportResults(results, options) {
|
|
1503
|
+
switch (options.format) {
|
|
1504
|
+
case "json": return this.exportAsJSON(results, options);
|
|
1505
|
+
case "csv": return this.exportAsCSV(results, options);
|
|
1506
|
+
case "text": return this.exportAsText(results, options);
|
|
1507
|
+
default: throw new Error(`Unsupported export format: ${options.format}`);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Clear all indexed data
|
|
1512
|
+
*/
|
|
1513
|
+
async clearIndex() {
|
|
1514
|
+
await this.indexer.clearIndex();
|
|
1515
|
+
this.searchEngine.clearLogs();
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Optimize the index
|
|
1519
|
+
*/
|
|
1520
|
+
async optimizeIndex() {
|
|
1521
|
+
await this.indexer.optimizeIndex();
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Get index statistics
|
|
1525
|
+
*/
|
|
1526
|
+
async getIndexStats() {
|
|
1527
|
+
return this.indexer.getIndexStats();
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Remove old logs
|
|
1531
|
+
*/
|
|
1532
|
+
async removeOldLogs(olderThan) {
|
|
1533
|
+
const removed = await this.indexer.removeOldLogs(olderThan);
|
|
1534
|
+
const filteredLogs = this.searchEngine.getLogs().filter((log) => new Date(log.timestamp) >= olderThan);
|
|
1535
|
+
this.searchEngine.clearLogs();
|
|
1536
|
+
this.searchEngine.addLogs(filteredLogs);
|
|
1537
|
+
return removed;
|
|
1538
|
+
}
|
|
1539
|
+
exportAsJSON(results, options) {
|
|
1540
|
+
const data = options.includeMetadata ? results : results.map((r) => r.log);
|
|
1541
|
+
if (options.fields) return JSON.stringify(data.map((item) => this.filterFields(item, options.fields)), null, 2);
|
|
1542
|
+
return JSON.stringify(data, null, 2);
|
|
1543
|
+
}
|
|
1544
|
+
exportAsCSV(results, options) {
|
|
1545
|
+
const logs = results.map((r) => r.log);
|
|
1546
|
+
if (logs.length === 0) return "";
|
|
1547
|
+
const fields = options.fields || [
|
|
1548
|
+
"timestamp",
|
|
1549
|
+
"level",
|
|
1550
|
+
"appName",
|
|
1551
|
+
"message"
|
|
1552
|
+
];
|
|
1553
|
+
return [fields.join(","), ...logs.map((log) => {
|
|
1554
|
+
return fields.map((field) => {
|
|
1555
|
+
const value = log[field];
|
|
1556
|
+
return this.escapeCSVValue(value);
|
|
1557
|
+
}).join(",");
|
|
1558
|
+
})].join("\n");
|
|
1559
|
+
}
|
|
1560
|
+
exportAsText(results, options) {
|
|
1561
|
+
return results.map((result) => {
|
|
1562
|
+
const log = result.log;
|
|
1563
|
+
let text = `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.appName}: ${log.message}`;
|
|
1564
|
+
if (options.includeMetadata) {
|
|
1565
|
+
text += `\n Score: ${result.score.toFixed(2)}`;
|
|
1566
|
+
if (result.highlights) text += `\n Matches: ${result.highlights.length}`;
|
|
1567
|
+
}
|
|
1568
|
+
return text;
|
|
1569
|
+
}).join("\n\n");
|
|
1570
|
+
}
|
|
1571
|
+
filterFields(obj, fields) {
|
|
1572
|
+
const filtered = {};
|
|
1573
|
+
for (const field of fields) if (obj !== null && typeof obj === "object" && field in obj) filtered[field] = obj[field];
|
|
1574
|
+
else if (field.includes(".")) {
|
|
1575
|
+
const value = this.getNestedValue(obj, field);
|
|
1576
|
+
if (value !== void 0) filtered[field] = value;
|
|
1577
|
+
}
|
|
1578
|
+
return filtered;
|
|
1579
|
+
}
|
|
1580
|
+
getNestedValue(obj, path) {
|
|
1581
|
+
return path.split(".").reduce((current, key) => {
|
|
1582
|
+
if (current !== null && typeof current === "object") return current[key];
|
|
1583
|
+
return current;
|
|
1584
|
+
}, obj);
|
|
1585
|
+
}
|
|
1586
|
+
escapeCSVValue(value) {
|
|
1587
|
+
if (value === null || value === void 0) return "";
|
|
1588
|
+
const str = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
1589
|
+
if (str.includes(",") || str.includes("\n") || str.includes("\"")) return `"${str.replace(/"/g, "\"\"")}"`;
|
|
1590
|
+
return str;
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
|
|
1594
|
+
//#endregion
|
|
1595
|
+
Object.defineProperty(exports, 'BasicLogIndexer', {
|
|
1596
|
+
enumerable: true,
|
|
1597
|
+
get: function () {
|
|
1598
|
+
return BasicLogIndexer;
|
|
1599
|
+
}
|
|
1600
|
+
});
|
|
1601
|
+
Object.defineProperty(exports, 'BasicSearchEngine', {
|
|
1602
|
+
enumerable: true,
|
|
1603
|
+
get: function () {
|
|
1604
|
+
return BasicSearchEngine;
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
Object.defineProperty(exports, 'CorrelationEngine', {
|
|
1608
|
+
enumerable: true,
|
|
1609
|
+
get: function () {
|
|
1610
|
+
return CorrelationEngine;
|
|
1611
|
+
}
|
|
1612
|
+
});
|
|
1613
|
+
Object.defineProperty(exports, 'NLPSearchEngine', {
|
|
1614
|
+
enumerable: true,
|
|
1615
|
+
get: function () {
|
|
1616
|
+
return NLPSearchEngine;
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
Object.defineProperty(exports, 'PatternRecognitionEngine', {
|
|
1620
|
+
enumerable: true,
|
|
1621
|
+
get: function () {
|
|
1622
|
+
return PatternRecognitionEngine;
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
Object.defineProperty(exports, 'SearchManager', {
|
|
1626
|
+
enumerable: true,
|
|
1627
|
+
get: function () {
|
|
1628
|
+
return SearchManager;
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
1631
|
+
//# sourceMappingURL=search-njTI2hdo.js.map
|