@heliyos/heliyos-api-core 1.0.35 → 1.0.36
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/dist/mongoose.js +168 -4
- package/package.json +1 -1
package/dist/mongoose.js
CHANGED
|
@@ -10,6 +10,18 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
|
11
11
|
o[k2] = m[k];
|
|
12
12
|
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
13
25
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
26
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
27
|
};
|
|
@@ -22,13 +34,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
22
34
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
35
|
});
|
|
24
36
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
38
|
exports.mongooseConnection = exports.mongoInstance = exports.MongoConnectionManager = void 0;
|
|
30
39
|
exports.initializeDatabase = initializeDatabase;
|
|
31
|
-
const mongoose_1 =
|
|
40
|
+
const mongoose_1 = __importStar(require("mongoose"));
|
|
32
41
|
const logger_1 = require("./logger");
|
|
33
42
|
// Export commonly used mongoose types
|
|
34
43
|
__exportStar(require("mongoose"), exports);
|
|
@@ -65,6 +74,7 @@ class MongoConnectionManager {
|
|
|
65
74
|
retryReads: true,
|
|
66
75
|
maxConnecting: 1,
|
|
67
76
|
minHeartbeatFrequencyMS: 2000,
|
|
77
|
+
family: 4,
|
|
68
78
|
// Add monitoring capability
|
|
69
79
|
monitorCommands: true,
|
|
70
80
|
};
|
|
@@ -194,3 +204,157 @@ mongoose_1.default.Query.prototype.paginate = function () {
|
|
|
194
204
|
}
|
|
195
205
|
});
|
|
196
206
|
};
|
|
207
|
+
const ENABLE_METRICS = process.env.MONGO_METRICS === "true";
|
|
208
|
+
const DEBUG_QUERIES = process.env.MONGO_DEBUG === "true";
|
|
209
|
+
const originalExec = mongoose_1.Query.prototype.exec;
|
|
210
|
+
mongoose_1.Query.prototype.exec = function (...args) {
|
|
211
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
212
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
213
|
+
// Skip metrics collection if disabled
|
|
214
|
+
if (!ENABLE_METRICS) {
|
|
215
|
+
return originalExec.apply(this, args);
|
|
216
|
+
}
|
|
217
|
+
const startTime = Date.now();
|
|
218
|
+
const queryName = this.model.modelName;
|
|
219
|
+
const operation = this.op;
|
|
220
|
+
// Enhanced query details for debugging
|
|
221
|
+
const queryDetails = {
|
|
222
|
+
filter: this.getFilter(),
|
|
223
|
+
sort: this.getSort(),
|
|
224
|
+
limit: this.options.limit,
|
|
225
|
+
skip: this.options.skip,
|
|
226
|
+
select: this.getOptions().select,
|
|
227
|
+
collection: this.model.collection.name,
|
|
228
|
+
operation: this.op,
|
|
229
|
+
options: this.getOptions(),
|
|
230
|
+
};
|
|
231
|
+
// Debug log the query details
|
|
232
|
+
if (DEBUG_QUERIES) {
|
|
233
|
+
logger_1.logger.debug(`MongoDB Query Details [${queryName}:${operation}]:`, {
|
|
234
|
+
timestamp: new Date().toISOString(),
|
|
235
|
+
queryDetails,
|
|
236
|
+
stack: (_a = new Error().stack) === null || _a === void 0 ? void 0 : _a.split("\n").slice(2).map((line) => line.trim()),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
// Run explain only for read operations and when debugging is enabled
|
|
241
|
+
let explainPromise;
|
|
242
|
+
if (DEBUG_QUERIES &&
|
|
243
|
+
["find", "findOne", "count", "countDocuments"].includes(operation)) {
|
|
244
|
+
explainPromise = this.model
|
|
245
|
+
.find(queryDetails.filter)
|
|
246
|
+
.explain("executionStats")
|
|
247
|
+
.catch((err) => {
|
|
248
|
+
logger_1.logger.debug("Explain analysis failed:", {
|
|
249
|
+
error: err.message,
|
|
250
|
+
queryName,
|
|
251
|
+
operation,
|
|
252
|
+
});
|
|
253
|
+
return null;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// Execute original query
|
|
257
|
+
const result = yield originalExec.apply(this, args);
|
|
258
|
+
const executionTimeMs = Date.now() - startTime;
|
|
259
|
+
// Get explain data if available
|
|
260
|
+
const explainData = yield explainPromise;
|
|
261
|
+
const metrics = Object.assign({ queryName,
|
|
262
|
+
operation,
|
|
263
|
+
executionTimeMs, timestamp: new Date().toISOString(), documentCount: Array.isArray(result) ? result.length : 1, queryDetails }, (explainData && {
|
|
264
|
+
explainData: {
|
|
265
|
+
nReturned: (_b = explainData.executionStats) === null || _b === void 0 ? void 0 : _b.nReturned,
|
|
266
|
+
totalKeysExamined: (_c = explainData.executionStats) === null || _c === void 0 ? void 0 : _c.totalKeysExamined,
|
|
267
|
+
totalDocsExamined: (_d = explainData.executionStats) === null || _d === void 0 ? void 0 : _d.totalDocsExamined,
|
|
268
|
+
executionTimeMillis: (_e = explainData.executionStats) === null || _e === void 0 ? void 0 : _e.executionTimeMillis,
|
|
269
|
+
indexesUsed: ((_h = (_g = (_f = explainData.queryPlanner) === null || _f === void 0 ? void 0 : _f.winningPlan) === null || _g === void 0 ? void 0 : _g.inputStage) === null || _h === void 0 ? void 0 : _h.indexName)
|
|
270
|
+
? [explainData.queryPlanner.winningPlan.inputStage.indexName]
|
|
271
|
+
: [],
|
|
272
|
+
isMultiKey: (_l = (_k = (_j = explainData.queryPlanner) === null || _j === void 0 ? void 0 : _j.winningPlan) === null || _k === void 0 ? void 0 : _k.inputStage) === null || _l === void 0 ? void 0 : _l.isMultiKey,
|
|
273
|
+
inMemorySort: ((_o = (_m = explainData.executionStats) === null || _m === void 0 ? void 0 : _m.executionStages) === null || _o === void 0 ? void 0 : _o.stage) === "SORT",
|
|
274
|
+
queryPlan: DEBUG_QUERIES ? explainData.queryPlanner : undefined,
|
|
275
|
+
},
|
|
276
|
+
}));
|
|
277
|
+
// Analyze query performance and log recommendations
|
|
278
|
+
analyzeQueryPerformance(metrics);
|
|
279
|
+
// Debug log the result summary
|
|
280
|
+
if (DEBUG_QUERIES) {
|
|
281
|
+
logger_1.logger.debug(`MongoDB Query Complete [${queryName}:${operation}]:`, {
|
|
282
|
+
executionTimeMs,
|
|
283
|
+
resultSize: Array.isArray(result) ? result.length : 1,
|
|
284
|
+
resultSample: Array.isArray(result)
|
|
285
|
+
? result.slice(0, 2).map((doc) => (Object.assign({ _id: doc._id }, doc)))
|
|
286
|
+
: result === null || result === void 0 ? void 0 : result._id,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
const errorDetails = {
|
|
293
|
+
queryName,
|
|
294
|
+
operation,
|
|
295
|
+
queryDetails,
|
|
296
|
+
error: {
|
|
297
|
+
message: error.message,
|
|
298
|
+
code: error.code,
|
|
299
|
+
name: error.name,
|
|
300
|
+
stack: DEBUG_QUERIES ? error.stack : undefined,
|
|
301
|
+
},
|
|
302
|
+
duration: Date.now() - startTime,
|
|
303
|
+
};
|
|
304
|
+
logger_1.logger.error("Query execution failed:", errorDetails);
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
function analyzeQueryPerformance(metrics) {
|
|
310
|
+
const warnings = [];
|
|
311
|
+
const suggestions = [];
|
|
312
|
+
let logLevel = "info";
|
|
313
|
+
// Performance thresholds
|
|
314
|
+
const SLOW_QUERY_THRESHOLD = 100; // ms
|
|
315
|
+
const VERY_SLOW_QUERY_THRESHOLD = 1000; // ms
|
|
316
|
+
const DOCS_EXAMINED_RATIO_THRESHOLD = 3;
|
|
317
|
+
const LARGE_RESULT_SET = 1000;
|
|
318
|
+
// Check execution time
|
|
319
|
+
if (metrics.executionTimeMs > VERY_SLOW_QUERY_THRESHOLD) {
|
|
320
|
+
warnings.push(`Very slow query: ${metrics.executionTimeMs}ms`);
|
|
321
|
+
logLevel = "error";
|
|
322
|
+
}
|
|
323
|
+
else if (metrics.executionTimeMs > SLOW_QUERY_THRESHOLD) {
|
|
324
|
+
warnings.push(`Slow query: ${metrics.executionTimeMs}ms`);
|
|
325
|
+
logLevel = "warn";
|
|
326
|
+
}
|
|
327
|
+
// Analyze explain data if available
|
|
328
|
+
if (metrics.explainData) {
|
|
329
|
+
const { totalDocsExamined, nReturned, indexesUsed, inMemorySort } = metrics.explainData;
|
|
330
|
+
// Check index usage
|
|
331
|
+
if (totalDocsExamined && !(indexesUsed === null || indexesUsed === void 0 ? void 0 : indexesUsed.length)) {
|
|
332
|
+
warnings.push("No indexes used (COLLSCAN)");
|
|
333
|
+
suggestions.push("Consider adding an index for this query pattern");
|
|
334
|
+
}
|
|
335
|
+
// Check documents examined ratio
|
|
336
|
+
if (totalDocsExamined && nReturned) {
|
|
337
|
+
const examineRatio = totalDocsExamined / nReturned;
|
|
338
|
+
if (examineRatio > DOCS_EXAMINED_RATIO_THRESHOLD) {
|
|
339
|
+
warnings.push(`High document examine ratio: ${examineRatio.toFixed(1)}`);
|
|
340
|
+
suggestions.push("Review index coverage or query selectivity");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Check for in-memory sorts
|
|
344
|
+
if (inMemorySort) {
|
|
345
|
+
warnings.push("In-memory sort detected");
|
|
346
|
+
suggestions.push("Add index to support sort operation");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Check result set size
|
|
350
|
+
if (metrics.documentCount > LARGE_RESULT_SET) {
|
|
351
|
+
warnings.push(`Large result set: ${metrics.documentCount} documents`);
|
|
352
|
+
suggestions.push("Consider implementing pagination");
|
|
353
|
+
}
|
|
354
|
+
// Check for potential limit issues
|
|
355
|
+
if (!metrics.queryDetails.limit && metrics.operation === "find") {
|
|
356
|
+
suggestions.push("Consider adding a limit to the query");
|
|
357
|
+
}
|
|
358
|
+
// Log the analysis
|
|
359
|
+
logger_1.logger[logLevel]("Query Performance Analysis:", Object.assign(Object.assign({}, metrics), { warnings: warnings.length ? warnings : undefined, suggestions: suggestions.length ? suggestions : undefined, performanceCategory: logLevel }));
|
|
360
|
+
}
|