@smoothbricks/lmao 0.1.2 → 0.1.3
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/lib/cleanupDiagnostics.d.ts +4 -0
- package/dist/lib/cleanupDiagnostics.d.ts.map +1 -0
- package/dist/lib/cleanupDiagnostics.js +42 -0
- package/dist/lib/flushScheduler.d.ts.map +1 -1
- package/dist/lib/flushScheduler.js +10 -0
- package/dist/lib/sqlite/sqlite-async-writer.d.ts.map +1 -1
- package/dist/lib/sqlite/sqlite-async-writer.js +16 -0
- package/dist/lib/sqlite/sqlite-writer.d.ts.map +1 -1
- package/dist/lib/sqlite/sqlite-writer.js +22 -0
- package/dist/lib/testing/bun-harness.d.ts.map +1 -1
- package/dist/lib/testing/bun-harness.js +21 -0
- package/dist/lib/tracers/CompositeTracer.d.ts.map +1 -1
- package/dist/lib/tracers/CompositeTracer.js +5 -0
- package/dist/lib/tracers/SQLiteTracer.d.ts.map +1 -1
- package/dist/lib/tracers/SQLiteTracer.js +9 -0
- package/package.json +7 -4
- package/src/lib/cleanupDiagnostics.ts +52 -0
- package/src/lib/flushScheduler.ts +10 -0
- package/src/lib/sqlite/sqlite-async-writer.ts +8 -0
- package/src/lib/sqlite/sqlite-writer.ts +6 -0
- package/src/lib/testing/bun-harness.ts +21 -0
- package/src/lib/tracers/CompositeTracer.ts +5 -0
- package/src/lib/tracers/SQLiteTracer.ts +9 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function isCleanupDebugEnabled(): boolean;
|
|
2
|
+
export declare function cleanupDebug(label: string, details?: Record<string, unknown>): void;
|
|
3
|
+
export declare function cleanupDebugActiveHandles(label: string): void;
|
|
4
|
+
//# sourceMappingURL=cleanupDiagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanupDiagnostics.d.ts","sourceRoot":"","sources":["../../src/lib/cleanupDiagnostics.ts"],"names":[],"mappings":"AAMA,wBAAgB,qBAAqB,IAAI,OAAO,CAO/C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAOnF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CA2B7D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="bun" />
|
|
2
|
+
function isTruthyEnvFlag(value) {
|
|
3
|
+
return value === true || value === '1' || value === 'true';
|
|
4
|
+
}
|
|
5
|
+
export function isCleanupDebugEnabled() {
|
|
6
|
+
const globalDebug = Reflect.get(globalThis, '__LMAO_TEST_CLEANUP_DEBUG__');
|
|
7
|
+
if (isTruthyEnvFlag(globalDebug)) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return isTruthyEnvFlag(process.env.LMAO_TEST_CLEANUP_DEBUG);
|
|
11
|
+
}
|
|
12
|
+
export function cleanupDebug(label, details) {
|
|
13
|
+
if (!isCleanupDebugEnabled()) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const suffix = details ? ` ${JSON.stringify(details)}` : '';
|
|
17
|
+
console.error(`[lmao/cleanup] ${label}${suffix}`);
|
|
18
|
+
}
|
|
19
|
+
export function cleanupDebugActiveHandles(label) {
|
|
20
|
+
if (!isCleanupDebugEnabled()) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const getActiveHandles = Reflect.get(process, '_getActiveHandles');
|
|
24
|
+
if (typeof getActiveHandles !== 'function') {
|
|
25
|
+
cleanupDebug(label, { activeHandles: 'unavailable' });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const handles = getActiveHandles.call(process);
|
|
29
|
+
if (!Array.isArray(handles)) {
|
|
30
|
+
cleanupDebug(label, { activeHandles: 'unavailable' });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const names = handles.map((handle) => {
|
|
34
|
+
if (typeof handle !== 'object' || handle === null) {
|
|
35
|
+
return typeof handle;
|
|
36
|
+
}
|
|
37
|
+
const constructor = Reflect.get(handle, 'constructor');
|
|
38
|
+
const name = typeof constructor === 'function' ? Reflect.get(constructor, 'name') : undefined;
|
|
39
|
+
return typeof name === 'string' && name.length > 0 ? name : 'Object';
|
|
40
|
+
});
|
|
41
|
+
cleanupDebug(label, { activeHandleCount: handles.length, activeHandles: names });
|
|
42
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flushScheduler.d.ts","sourceRoot":"","sources":["../../src/lib/flushScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAU,KAAK,KAAK,EAAoB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"flushScheduler.d.ts","sourceRoot":"","sources":["../../src/lib/flushScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAU,KAAK,KAAK,EAAoB,MAAM,mBAAmB,CAAC;AAKzE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,YAAY,CAAC;AAuC5D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE3F;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,OAAO,CAAe;IAE9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,SAAS,CAAS;IAE1B,wDAAwD;IACxD,OAAO,CAAC,WAAW,CAAK;IAExB;;;;OAIG;IACH,OAAO,CAAC,+BAA+B,CAAgD;gBAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,GAAE,oBAAyB;IAepE;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAUrC;;OAEG;IACH,KAAK,IAAI,IAAI;IA+Bb;;OAEG;IACH,IAAI,IAAI,IAAI;IAuBZ;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAiB5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAU7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAatB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;YACW,OAAO;IAqJrB;;OAEG;IACH,cAAc,IAAI,IAAI;CAGvB;AAQD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,cAAc,CAK5G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAKhD;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB;IAClC;;OAEG;6BACsB,cAAc,GAAG,MAAM,CAAC,OAAO,GAAG,SAAS;IAKpE;;OAEG;6BACsB,cAAc,SAAS,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI;IAIjF;;OAEG;mCAC4B,cAAc,GAAG,MAAM,GAAG,SAAS;IAKlE;;OAEG;mCAC4B,cAAc,QAAQ,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;CAGtF,CAAC"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Background processing (cold path)
|
|
8
8
|
*/
|
|
9
9
|
import { Column, tableFromColumns } from '@uwdata/flechette';
|
|
10
|
+
import { cleanupDebug } from './cleanupDiagnostics.js';
|
|
10
11
|
import { convertSpanTreeToArrowTable } from './convertToArrow.js';
|
|
11
12
|
/**
|
|
12
13
|
* Number of flushes before logging capacity stats.
|
|
@@ -95,6 +96,7 @@ export class FlushScheduler {
|
|
|
95
96
|
this.isRunning = true;
|
|
96
97
|
this.lastFlushTime = Date.now();
|
|
97
98
|
this.lastActivityTime = Date.now();
|
|
99
|
+
cleanupDebug('flushScheduler.start', this.config);
|
|
98
100
|
// Set up periodic flush timer
|
|
99
101
|
this.flushTimer = setInterval(() => {
|
|
100
102
|
this.checkFlushConditions();
|
|
@@ -121,6 +123,7 @@ export class FlushScheduler {
|
|
|
121
123
|
stop() {
|
|
122
124
|
if (!this.isRunning)
|
|
123
125
|
return;
|
|
126
|
+
cleanupDebug('flushScheduler.stop:start', { pendingBuffers: this.buffers.size });
|
|
124
127
|
this.isRunning = false;
|
|
125
128
|
if (this.flushTimer) {
|
|
126
129
|
clearInterval(this.flushTimer);
|
|
@@ -134,6 +137,7 @@ export class FlushScheduler {
|
|
|
134
137
|
clearInterval(this.memoryTimer);
|
|
135
138
|
this.memoryTimer = undefined;
|
|
136
139
|
}
|
|
140
|
+
cleanupDebug('flushScheduler.stop:end', { pendingBuffers: this.buffers.size });
|
|
137
141
|
}
|
|
138
142
|
/**
|
|
139
143
|
* Manually trigger a flush
|
|
@@ -329,6 +333,12 @@ export class FlushScheduler {
|
|
|
329
333
|
}
|
|
330
334
|
catch (error) {
|
|
331
335
|
console.error('Error in flush handler:', error);
|
|
336
|
+
cleanupDebug('flushScheduler.doFlush:error', {
|
|
337
|
+
reason,
|
|
338
|
+
totalRows,
|
|
339
|
+
totalBuffers,
|
|
340
|
+
pendingBuffers: this.buffers.size,
|
|
341
|
+
});
|
|
332
342
|
// Do NOT reset buffers on failure to avoid data loss
|
|
333
343
|
}
|
|
334
344
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-async-writer.d.ts","sourceRoot":"","sources":["../../../src/lib/sqlite/sqlite-async-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"sqlite-async-writer.d.ts","sourceRoot":"","sources":["../../../src/lib/sqlite/sqlite-async-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAejD,OAAO,KAAK,EAAE,mBAAmB,EAAwB,MAAM,gBAAgB,CAAC;AAEhF,qBAAa,sBAAsB;IAKrB,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,eAAe,CAA2C;IAClE,OAAO,CAAC,WAAW,CAAS;gBAER,EAAE,EAAE,mBAAmB;YAE7B,IAAI;YAYJ,mBAAmB;YAUnB,aAAa;IAe3B,OAAO,CAAC,kBAAkB;IAYpB,KAAK,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLiteAsyncTraceWriter - Async SQLite persistence for span buffer trees.
|
|
3
|
+
*
|
|
4
|
+
* Works with async SQLite drivers (for example Cloudflare D1 adapters) while
|
|
5
|
+
* preserving the same `spans` table shape as the sync SQLiteTraceWriter.
|
|
6
|
+
*
|
|
7
|
+
* @module sqlite-async-writer
|
|
8
|
+
*/
|
|
9
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
10
|
import { buildAddColumnSql, buildInsertParams, buildInsertSql, extractSqliteColumnsFromTableInfo, getActiveUserFields, getInsertStatementCacheKey, getMissingSchemaColumns, isSqliteDuplicateColumnError, parseSqliteTableInfoRows, SPANS_TABLE_INFO_SQL, SPANS_TABLE_INIT_SQL, walkSpanSegments, } from './sqlite-common.js';
|
|
2
11
|
export class SQLiteAsyncTraceWriter {
|
|
3
12
|
db;
|
|
@@ -49,6 +58,10 @@ export class SQLiteAsyncTraceWriter {
|
|
|
49
58
|
return stmt;
|
|
50
59
|
}
|
|
51
60
|
async flush(rootBuffer) {
|
|
61
|
+
cleanupDebug('sqliteAsyncWriter.flush:start', {
|
|
62
|
+
initialized: this.initialized,
|
|
63
|
+
statementCacheSize: this.insertStmtCache.size,
|
|
64
|
+
});
|
|
52
65
|
await this.init();
|
|
53
66
|
for (const segment of walkSpanSegments(rootBuffer)) {
|
|
54
67
|
await this.ensureColumns(segment.buffer._logSchema);
|
|
@@ -58,8 +71,11 @@ export class SQLiteAsyncTraceWriter {
|
|
|
58
71
|
await insertStmt.run(...buildInsertParams(segment, row, activeUserFields));
|
|
59
72
|
}
|
|
60
73
|
}
|
|
74
|
+
cleanupDebug('sqliteAsyncWriter.flush:end', { statementCacheSize: this.insertStmtCache.size });
|
|
61
75
|
}
|
|
62
76
|
async close() {
|
|
77
|
+
cleanupDebug('sqliteAsyncWriter.close:start', { statementCacheSize: this.insertStmtCache.size });
|
|
63
78
|
await this.db.close();
|
|
79
|
+
cleanupDebug('sqliteAsyncWriter.close:end');
|
|
64
80
|
}
|
|
65
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-writer.d.ts","sourceRoot":"","sources":["../../../src/lib/sqlite/sqlite-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"sqlite-writer.d.ts","sourceRoot":"","sources":["../../../src/lib/sqlite/sqlite-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBjD,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,gBAAgB,CAAC;AAE9E,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;IAIhB,OAAO,CAAC,EAAE;IAHtB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,eAAe,CAA0C;gBAE7C,EAAE,EAAE,kBAAkB;IAI1C,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,mBAAmB;IAU3B,kEAAkE;IAClE,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAY1B,mDAAmD;IACnD,KAAK,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI;IActC,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLiteTraceWriter - General-purpose writer that persists span buffer trees to SQLite.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a SyncSQLiteDatabase instance (from bun:sqlite or better-sqlite3)
|
|
5
|
+
* and persists the full span tree as a flat `spans` table with dynamic column
|
|
6
|
+
* evolution based on the LogSchema fields found at flush time.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Single `spans` table — no runs/log_entries decomposition
|
|
10
|
+
* - trace_id IS the run identifier (one root span per trace)
|
|
11
|
+
* - Tree structure via span_id / parent_span_id (no depth column)
|
|
12
|
+
* - User schema columns added dynamically via ALTER TABLE
|
|
13
|
+
* - Per-buffer ensureColumns for cross-library schema merging
|
|
14
|
+
*
|
|
15
|
+
* @module sqlite-writer
|
|
16
|
+
*/
|
|
17
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
18
|
import { buildAddColumnSql, buildInsertParams, buildInsertSql, extractSqliteColumnsFromTableInfo, getActiveUserFields, getInsertStatementCacheKey, getMissingSchemaColumns, isSqliteDuplicateColumnError, parseSqliteTableInfoRows, SPANS_TABLE_INFO_SQL, SPANS_TABLE_INIT_SQL, walkSpanSegments, } from './sqlite-common.js';
|
|
2
19
|
export class SQLiteTraceWriter {
|
|
3
20
|
db;
|
|
@@ -62,17 +79,22 @@ export class SQLiteTraceWriter {
|
|
|
62
79
|
}
|
|
63
80
|
/** Write a root SpanBuffer tree to the database */
|
|
64
81
|
flush(rootBuffer) {
|
|
82
|
+
cleanupDebug('sqliteWriter.flush:start', { statementCacheSize: this.insertStmtCache.size });
|
|
65
83
|
this.db.exec('BEGIN IMMEDIATE');
|
|
66
84
|
try {
|
|
67
85
|
this.flushAllSegments(rootBuffer);
|
|
68
86
|
this.db.exec('COMMIT');
|
|
87
|
+
cleanupDebug('sqliteWriter.flush:end', { statementCacheSize: this.insertStmtCache.size });
|
|
69
88
|
}
|
|
70
89
|
catch (error) {
|
|
71
90
|
this.db.exec('ROLLBACK');
|
|
91
|
+
cleanupDebug('sqliteWriter.flush:error', { statementCacheSize: this.insertStmtCache.size });
|
|
72
92
|
throw error;
|
|
73
93
|
}
|
|
74
94
|
}
|
|
75
95
|
close() {
|
|
96
|
+
cleanupDebug('sqliteWriter.close:start', { statementCacheSize: this.insertStmtCache.size });
|
|
76
97
|
this.db.close();
|
|
98
|
+
cleanupDebug('sqliteWriter.close:end');
|
|
77
99
|
}
|
|
78
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-harness.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/bun-harness.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,OAAO,MAAM,UAAU,CAAC;AACpC,OAAO,EACL,QAAQ,IAAI,SAAS,EACrB,SAAS,IAAI,UAAU,EACvB,SAAS,IAAI,UAAU,EACvB,UAAU,IAAI,WAAW,EACzB,QAAQ,IAAI,SAAS,EACrB,MAAM,IAAI,OAAO,EACjB,EAAE,IAAI,GAAG,EAEV,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"bun-harness.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/bun-harness.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,6 +43,7 @@ import { Database } from 'bun:sqlite';
|
|
|
43
43
|
import * as bunTest from 'bun:test';
|
|
44
44
|
import { afterAll as _afterAll, afterEach as _afterEach, beforeAll as _beforeAll, beforeEach as _beforeEach, describe as _describe, expect as _expect, it as _it, mock, } from 'bun:test';
|
|
45
45
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
46
|
+
import { cleanupDebug, cleanupDebugActiveHandles } from '../cleanupDiagnostics.js';
|
|
46
47
|
import { defineOpContext } from '../defineOpContext.js';
|
|
47
48
|
import { JsBufferStrategy } from '../JsBufferStrategy.js';
|
|
48
49
|
import { S } from '../schema/builder.js';
|
|
@@ -162,7 +163,9 @@ function createRootTracer({ binding, sqlite, verbose, }) {
|
|
|
162
163
|
async function closeTracer(tracer) {
|
|
163
164
|
const close = Reflect.get(tracer, 'close');
|
|
164
165
|
if (typeof close === 'function') {
|
|
166
|
+
cleanupDebug('tracer.close:start', { tracer: tracer.constructor.name });
|
|
165
167
|
await close.call(tracer);
|
|
168
|
+
cleanupDebug('tracer.close:end', { tracer: tracer.constructor.name });
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
let _activeSuiteTracer = null;
|
|
@@ -335,17 +338,24 @@ function createTestTracerInstance(binding, options) {
|
|
|
335
338
|
});
|
|
336
339
|
});
|
|
337
340
|
_afterAll(async () => {
|
|
341
|
+
cleanupDebug('instance.afterAll:start');
|
|
342
|
+
cleanupDebugActiveHandles('instance.afterAll:handles:start');
|
|
338
343
|
if (resolveTestRun) {
|
|
344
|
+
cleanupDebug('instance.rootTrace:resolve');
|
|
339
345
|
resolveTestRun();
|
|
340
346
|
resolveTestRun = null;
|
|
341
347
|
}
|
|
342
348
|
if (rootTracePromise) {
|
|
349
|
+
cleanupDebug('instance.rootTrace:await:start');
|
|
343
350
|
await rootTracePromise;
|
|
351
|
+
cleanupDebug('instance.rootTrace:await:end');
|
|
344
352
|
rootTracePromise = null;
|
|
345
353
|
}
|
|
346
354
|
if (tracer) {
|
|
347
355
|
try {
|
|
356
|
+
cleanupDebug('instance.tracer.flush:start', { tracer: tracer.constructor.name });
|
|
348
357
|
await tracer.flush();
|
|
358
|
+
cleanupDebug('instance.tracer.flush:end', { tracer: tracer.constructor.name });
|
|
349
359
|
if (options?.sqlite && rootCtx) {
|
|
350
360
|
const traceId = rootCtx.buffer.trace_id;
|
|
351
361
|
const dbPath = options.sqlite.dbPath ?? '.trace-results.db';
|
|
@@ -357,6 +367,8 @@ function createTestTracerInstance(binding, options) {
|
|
|
357
367
|
}
|
|
358
368
|
finally {
|
|
359
369
|
await closeTracer(tracer);
|
|
370
|
+
cleanupDebugActiveHandles('instance.afterAll:handles:end');
|
|
371
|
+
cleanupDebug('instance.afterAll:end');
|
|
360
372
|
}
|
|
361
373
|
}
|
|
362
374
|
});
|
|
@@ -424,19 +436,26 @@ export function initTraceTestRun(opContext, options) {
|
|
|
424
436
|
});
|
|
425
437
|
// Register global teardown — resolve root, wait for span-end, then flush tracer outputs
|
|
426
438
|
_afterAll(async () => {
|
|
439
|
+
cleanupDebug('global.afterAll:start');
|
|
440
|
+
cleanupDebugActiveHandles('global.afterAll:handles:start');
|
|
427
441
|
// Resolve the root promise — triggers span-end write via _executeWithContext .then()
|
|
428
442
|
if (_resolveTestRun) {
|
|
443
|
+
cleanupDebug('global.rootTrace:resolve');
|
|
429
444
|
_resolveTestRun();
|
|
430
445
|
_resolveTestRun = null;
|
|
431
446
|
}
|
|
432
447
|
// Await the trace promise so span-end is written to the buffer before flushing
|
|
433
448
|
if (_rootTracePromise) {
|
|
449
|
+
cleanupDebug('global.rootTrace:await:start');
|
|
434
450
|
await _rootTracePromise;
|
|
451
|
+
cleanupDebug('global.rootTrace:await:end');
|
|
435
452
|
_rootTracePromise = null;
|
|
436
453
|
}
|
|
437
454
|
if (_tracer) {
|
|
438
455
|
try {
|
|
456
|
+
cleanupDebug('global.tracer.flush:start', { tracer: _tracer.constructor.name });
|
|
439
457
|
await _tracer.flush();
|
|
458
|
+
cleanupDebug('global.tracer.flush:end', { tracer: _tracer.constructor.name });
|
|
440
459
|
if (options?.sqlite && _rootCtx) {
|
|
441
460
|
const traceId = _rootCtx.buffer.trace_id;
|
|
442
461
|
const dbPath = options.sqlite.dbPath ?? '.trace-results.db';
|
|
@@ -448,6 +467,8 @@ export function initTraceTestRun(opContext, options) {
|
|
|
448
467
|
}
|
|
449
468
|
finally {
|
|
450
469
|
await closeTracer(_tracer);
|
|
470
|
+
cleanupDebugActiveHandles('global.afterAll:handles:end');
|
|
471
|
+
cleanupDebug('global.afterAll:end');
|
|
451
472
|
}
|
|
452
473
|
}
|
|
453
474
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeTracer.d.ts","sourceRoot":"","sources":["../../../src/lib/tracers/CompositeTracer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CompositeTracer.d.ts","sourceRoot":"","sources":["../../../src/lib/tracers/CompositeTracer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,CACnF,SAAQ,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC;IACnD,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,CAAE,SAAQ,MAAM,CAAC,CAAC,CAAC;IAC3F,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;gBAE5B,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAK1D,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IAMxE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IAMtE,WAAW,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IAMxE,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IAMtE,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IAM5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAY7B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
2
|
import { Tracer } from '../tracer.js';
|
|
2
3
|
function hasClose(value) {
|
|
3
4
|
return typeof value === 'object' && value !== null && typeof Reflect.get(value, 'close') === 'function';
|
|
@@ -41,7 +42,9 @@ export class CompositeTracer extends Tracer {
|
|
|
41
42
|
}
|
|
42
43
|
async flush() {
|
|
43
44
|
for (const tracer of this.delegates) {
|
|
45
|
+
cleanupDebug('compositeTracer.flush:delegate:start', { tracer: tracer.constructor.name });
|
|
44
46
|
await tracer.flush();
|
|
47
|
+
cleanupDebug('compositeTracer.flush:delegate:end', { tracer: tracer.constructor.name });
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
async close() {
|
|
@@ -49,7 +52,9 @@ export class CompositeTracer extends Tracer {
|
|
|
49
52
|
if (hasClose(tracer)) {
|
|
50
53
|
const { close } = tracer;
|
|
51
54
|
if (close) {
|
|
55
|
+
cleanupDebug('compositeTracer.close:delegate:start', { tracer: tracer.constructor.name });
|
|
52
56
|
await close.call(tracer);
|
|
57
|
+
cleanupDebug('compositeTracer.close:delegate:end', { tracer: tracer.constructor.name });
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLiteTracer.d.ts","sourceRoot":"","sources":["../../../src/lib/tracers/SQLiteTracer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SQLiteTracer.d.ts","sourceRoot":"","sources":["../../../src/lib/tracers/SQLiteTracer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
2
|
import { SQLiteAsyncTraceWriter } from '../sqlite/sqlite-async-writer.js';
|
|
2
3
|
import { SQLiteTraceWriter } from '../sqlite/sqlite-writer.js';
|
|
3
4
|
import { Tracer } from '../tracer.js';
|
|
@@ -14,7 +15,9 @@ export class SQLiteTracer extends Tracer {
|
|
|
14
15
|
// No-op
|
|
15
16
|
}
|
|
16
17
|
onTraceEnd(rootBuffer) {
|
|
18
|
+
cleanupDebug('sqliteTracer.onTraceEnd:flush:start', { rows: rootBuffer._writeIndex });
|
|
17
19
|
this.writer.flush(rootBuffer);
|
|
20
|
+
cleanupDebug('sqliteTracer.onTraceEnd:flush:end');
|
|
18
21
|
}
|
|
19
22
|
onSpanStart(_childBuffer) {
|
|
20
23
|
// No-op
|
|
@@ -26,7 +29,9 @@ export class SQLiteTracer extends Tracer {
|
|
|
26
29
|
// No-op
|
|
27
30
|
}
|
|
28
31
|
async close() {
|
|
32
|
+
cleanupDebug('sqliteTracer.close:start');
|
|
29
33
|
this.writer.close();
|
|
34
|
+
cleanupDebug('sqliteTracer.close:end');
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
/**
|
|
@@ -66,6 +71,7 @@ export class SQLiteAsyncTracer extends Tracer {
|
|
|
66
71
|
// No-op
|
|
67
72
|
}
|
|
68
73
|
async flush() {
|
|
74
|
+
cleanupDebug('sqliteAsyncTracer.flush:start');
|
|
69
75
|
await this.pendingWrites;
|
|
70
76
|
if (this.pendingErrors.length > 0) {
|
|
71
77
|
const errors = this.pendingErrors;
|
|
@@ -75,10 +81,13 @@ export class SQLiteAsyncTracer extends Tracer {
|
|
|
75
81
|
}
|
|
76
82
|
throw new AggregateError(errors, `SQLiteAsyncTracer flush failed for ${errors.length} trace writes`);
|
|
77
83
|
}
|
|
84
|
+
cleanupDebug('sqliteAsyncTracer.flush:end');
|
|
78
85
|
}
|
|
79
86
|
async close() {
|
|
87
|
+
cleanupDebug('sqliteAsyncTracer.close:start');
|
|
80
88
|
await this.flush();
|
|
81
89
|
const writer = await this.writerPromise;
|
|
82
90
|
await writer.close();
|
|
91
|
+
cleanupDebug('sqliteAsyncTracer.close:end');
|
|
83
92
|
}
|
|
84
93
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smoothbricks/lmao",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -126,7 +126,8 @@
|
|
|
126
126
|
"scripts": {
|
|
127
127
|
"bench": "bun run benchmarks/*.bench.ts",
|
|
128
128
|
"bench:wasm": "bun run benchmarks/js-vs-wasm.bench.ts",
|
|
129
|
-
"build:wasm": "zig build -Doptimize=ReleaseSmall"
|
|
129
|
+
"build:wasm": "zig build -Doptimize=ReleaseSmall",
|
|
130
|
+
"test": "nx run lmao:test --tui=false --outputStyle=stream"
|
|
130
131
|
},
|
|
131
132
|
"nx": {
|
|
132
133
|
"sourceRoot": "packages/lmao/src",
|
|
@@ -140,10 +141,12 @@
|
|
|
140
141
|
]
|
|
141
142
|
},
|
|
142
143
|
"test": {
|
|
143
|
-
"executor": "nx:
|
|
144
|
+
"executor": "@smoothbricks/nx-plugin:bounded-exec",
|
|
144
145
|
"options": {
|
|
145
146
|
"command": "bun test",
|
|
146
|
-
"cwd": "
|
|
147
|
+
"cwd": "{projectRoot}",
|
|
148
|
+
"timeoutMs": 120000,
|
|
149
|
+
"killAfterMs": 1e4
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/// <reference types="bun" />
|
|
2
|
+
|
|
3
|
+
function isTruthyEnvFlag(value: unknown): boolean {
|
|
4
|
+
return value === true || value === '1' || value === 'true';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isCleanupDebugEnabled(): boolean {
|
|
8
|
+
const globalDebug = Reflect.get(globalThis, '__LMAO_TEST_CLEANUP_DEBUG__');
|
|
9
|
+
if (isTruthyEnvFlag(globalDebug)) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return isTruthyEnvFlag(process.env.LMAO_TEST_CLEANUP_DEBUG);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function cleanupDebug(label: string, details?: Record<string, unknown>): void {
|
|
17
|
+
if (!isCleanupDebugEnabled()) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const suffix = details ? ` ${JSON.stringify(details)}` : '';
|
|
22
|
+
console.error(`[lmao/cleanup] ${label}${suffix}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function cleanupDebugActiveHandles(label: string): void {
|
|
26
|
+
if (!isCleanupDebugEnabled()) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const getActiveHandles = Reflect.get(process, '_getActiveHandles');
|
|
31
|
+
if (typeof getActiveHandles !== 'function') {
|
|
32
|
+
cleanupDebug(label, { activeHandles: 'unavailable' });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const handles = getActiveHandles.call(process);
|
|
37
|
+
if (!Array.isArray(handles)) {
|
|
38
|
+
cleanupDebug(label, { activeHandles: 'unavailable' });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const names = handles.map((handle) => {
|
|
43
|
+
if (typeof handle !== 'object' || handle === null) {
|
|
44
|
+
return typeof handle;
|
|
45
|
+
}
|
|
46
|
+
const constructor = Reflect.get(handle, 'constructor');
|
|
47
|
+
const name = typeof constructor === 'function' ? Reflect.get(constructor, 'name') : undefined;
|
|
48
|
+
return typeof name === 'string' && name.length > 0 ? name : 'Object';
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
cleanupDebug(label, { activeHandleCount: handles.length, activeHandles: names });
|
|
52
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { Column, type Table, tableFromColumns } from '@uwdata/flechette';
|
|
11
11
|
import type { CapacityStatsEntry } from './arrow/capacityStats.js';
|
|
12
|
+
import { cleanupDebug } from './cleanupDiagnostics.js';
|
|
12
13
|
import { convertSpanTreeToArrowTable } from './convertToArrow.js';
|
|
13
14
|
import type { SpanBufferConstructor } from './spanBuffer.js';
|
|
14
15
|
import type { AnySpanBuffer, OpMetadata } from './types.js';
|
|
@@ -178,6 +179,7 @@ export class FlushScheduler {
|
|
|
178
179
|
this.isRunning = true;
|
|
179
180
|
this.lastFlushTime = Date.now();
|
|
180
181
|
this.lastActivityTime = Date.now();
|
|
182
|
+
cleanupDebug('flushScheduler.start', this.config);
|
|
181
183
|
|
|
182
184
|
// Set up periodic flush timer
|
|
183
185
|
this.flushTimer = setInterval(() => {
|
|
@@ -208,6 +210,7 @@ export class FlushScheduler {
|
|
|
208
210
|
stop(): void {
|
|
209
211
|
if (!this.isRunning) return;
|
|
210
212
|
|
|
213
|
+
cleanupDebug('flushScheduler.stop:start', { pendingBuffers: this.buffers.size });
|
|
211
214
|
this.isRunning = false;
|
|
212
215
|
|
|
213
216
|
if (this.flushTimer) {
|
|
@@ -224,6 +227,7 @@ export class FlushScheduler {
|
|
|
224
227
|
clearInterval(this.memoryTimer);
|
|
225
228
|
this.memoryTimer = undefined;
|
|
226
229
|
}
|
|
230
|
+
cleanupDebug('flushScheduler.stop:end', { pendingBuffers: this.buffers.size });
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
/**
|
|
@@ -443,6 +447,12 @@ export class FlushScheduler {
|
|
|
443
447
|
}
|
|
444
448
|
} catch (error) {
|
|
445
449
|
console.error('Error in flush handler:', error);
|
|
450
|
+
cleanupDebug('flushScheduler.doFlush:error', {
|
|
451
|
+
reason,
|
|
452
|
+
totalRows,
|
|
453
|
+
totalBuffers,
|
|
454
|
+
pendingBuffers: this.buffers.size,
|
|
455
|
+
});
|
|
446
456
|
// Do NOT reset buffers on failure to avoid data loss
|
|
447
457
|
}
|
|
448
458
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @module sqlite-async-writer
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
10
11
|
import type { LogSchema } from '../schema/LogSchema.js';
|
|
11
12
|
import type { AnySpanBuffer } from '../types.js';
|
|
12
13
|
import {
|
|
@@ -82,6 +83,10 @@ export class SQLiteAsyncTraceWriter {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
async flush(rootBuffer: AnySpanBuffer): Promise<void> {
|
|
86
|
+
cleanupDebug('sqliteAsyncWriter.flush:start', {
|
|
87
|
+
initialized: this.initialized,
|
|
88
|
+
statementCacheSize: this.insertStmtCache.size,
|
|
89
|
+
});
|
|
85
90
|
await this.init();
|
|
86
91
|
for (const segment of walkSpanSegments(rootBuffer)) {
|
|
87
92
|
await this.ensureColumns(segment.buffer._logSchema);
|
|
@@ -93,9 +98,12 @@ export class SQLiteAsyncTraceWriter {
|
|
|
93
98
|
await insertStmt.run(...buildInsertParams(segment, row, activeUserFields));
|
|
94
99
|
}
|
|
95
100
|
}
|
|
101
|
+
cleanupDebug('sqliteAsyncWriter.flush:end', { statementCacheSize: this.insertStmtCache.size });
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
async close(): Promise<void> {
|
|
105
|
+
cleanupDebug('sqliteAsyncWriter.close:start', { statementCacheSize: this.insertStmtCache.size });
|
|
99
106
|
await this.db.close();
|
|
107
|
+
cleanupDebug('sqliteAsyncWriter.close:end');
|
|
100
108
|
}
|
|
101
109
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* @module sqlite-writer
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
18
19
|
import type { LogSchema } from '../schema/LogSchema.js';
|
|
19
20
|
import type { AnySpanBuffer } from '../types.js';
|
|
20
21
|
import {
|
|
@@ -112,17 +113,22 @@ export class SQLiteTraceWriter {
|
|
|
112
113
|
|
|
113
114
|
/** Write a root SpanBuffer tree to the database */
|
|
114
115
|
flush(rootBuffer: AnySpanBuffer): void {
|
|
116
|
+
cleanupDebug('sqliteWriter.flush:start', { statementCacheSize: this.insertStmtCache.size });
|
|
115
117
|
this.db.exec('BEGIN IMMEDIATE');
|
|
116
118
|
try {
|
|
117
119
|
this.flushAllSegments(rootBuffer);
|
|
118
120
|
this.db.exec('COMMIT');
|
|
121
|
+
cleanupDebug('sqliteWriter.flush:end', { statementCacheSize: this.insertStmtCache.size });
|
|
119
122
|
} catch (error) {
|
|
120
123
|
this.db.exec('ROLLBACK');
|
|
124
|
+
cleanupDebug('sqliteWriter.flush:error', { statementCacheSize: this.insertStmtCache.size });
|
|
121
125
|
throw error;
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
close(): void {
|
|
130
|
+
cleanupDebug('sqliteWriter.close:start', { statementCacheSize: this.insertStmtCache.size });
|
|
126
131
|
this.db.close();
|
|
132
|
+
cleanupDebug('sqliteWriter.close:end');
|
|
127
133
|
}
|
|
128
134
|
}
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
mock,
|
|
55
55
|
} from 'bun:test';
|
|
56
56
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
57
|
+
import { cleanupDebug, cleanupDebugActiveHandles } from '../cleanupDiagnostics.js';
|
|
57
58
|
import { defineOpContext } from '../defineOpContext.js';
|
|
58
59
|
import { JsBufferStrategy } from '../JsBufferStrategy.js';
|
|
59
60
|
import type { SpanContext } from '../opContext/spanContextTypes.js';
|
|
@@ -270,7 +271,9 @@ function createRootTracer<B extends OpContextBinding>({
|
|
|
270
271
|
async function closeTracer<B extends OpContextBinding>(tracer: Tracer<B>): Promise<void> {
|
|
271
272
|
const close = Reflect.get(tracer, 'close');
|
|
272
273
|
if (typeof close === 'function') {
|
|
274
|
+
cleanupDebug('tracer.close:start', { tracer: tracer.constructor.name });
|
|
273
275
|
await close.call(tracer);
|
|
276
|
+
cleanupDebug('tracer.close:end', { tracer: tracer.constructor.name });
|
|
274
277
|
}
|
|
275
278
|
}
|
|
276
279
|
|
|
@@ -531,19 +534,26 @@ function createTestTracerInstance<B extends OpContextBinding, TExt extends Schem
|
|
|
531
534
|
});
|
|
532
535
|
|
|
533
536
|
_afterAll(async () => {
|
|
537
|
+
cleanupDebug('instance.afterAll:start');
|
|
538
|
+
cleanupDebugActiveHandles('instance.afterAll:handles:start');
|
|
534
539
|
if (resolveTestRun) {
|
|
540
|
+
cleanupDebug('instance.rootTrace:resolve');
|
|
535
541
|
resolveTestRun();
|
|
536
542
|
resolveTestRun = null;
|
|
537
543
|
}
|
|
538
544
|
|
|
539
545
|
if (rootTracePromise) {
|
|
546
|
+
cleanupDebug('instance.rootTrace:await:start');
|
|
540
547
|
await rootTracePromise;
|
|
548
|
+
cleanupDebug('instance.rootTrace:await:end');
|
|
541
549
|
rootTracePromise = null;
|
|
542
550
|
}
|
|
543
551
|
|
|
544
552
|
if (tracer) {
|
|
545
553
|
try {
|
|
554
|
+
cleanupDebug('instance.tracer.flush:start', { tracer: tracer.constructor.name });
|
|
546
555
|
await tracer.flush();
|
|
556
|
+
cleanupDebug('instance.tracer.flush:end', { tracer: tracer.constructor.name });
|
|
547
557
|
if (options?.sqlite && rootCtx) {
|
|
548
558
|
const traceId = rootCtx.buffer.trace_id;
|
|
549
559
|
const dbPath = options.sqlite.dbPath ?? '.trace-results.db';
|
|
@@ -553,6 +563,8 @@ function createTestTracerInstance<B extends OpContextBinding, TExt extends Schem
|
|
|
553
563
|
console.error('[lmao/testing] SQLite flush error:', e);
|
|
554
564
|
} finally {
|
|
555
565
|
await closeTracer(tracer);
|
|
566
|
+
cleanupDebugActiveHandles('instance.afterAll:handles:end');
|
|
567
|
+
cleanupDebug('instance.afterAll:end');
|
|
556
568
|
}
|
|
557
569
|
}
|
|
558
570
|
});
|
|
@@ -635,20 +647,27 @@ export function initTraceTestRun<B extends OpContextBinding>(opContext: B, optio
|
|
|
635
647
|
|
|
636
648
|
// Register global teardown — resolve root, wait for span-end, then flush tracer outputs
|
|
637
649
|
_afterAll(async () => {
|
|
650
|
+
cleanupDebug('global.afterAll:start');
|
|
651
|
+
cleanupDebugActiveHandles('global.afterAll:handles:start');
|
|
638
652
|
// Resolve the root promise — triggers span-end write via _executeWithContext .then()
|
|
639
653
|
if (_resolveTestRun) {
|
|
654
|
+
cleanupDebug('global.rootTrace:resolve');
|
|
640
655
|
_resolveTestRun();
|
|
641
656
|
_resolveTestRun = null;
|
|
642
657
|
}
|
|
643
658
|
// Await the trace promise so span-end is written to the buffer before flushing
|
|
644
659
|
if (_rootTracePromise) {
|
|
660
|
+
cleanupDebug('global.rootTrace:await:start');
|
|
645
661
|
await _rootTracePromise;
|
|
662
|
+
cleanupDebug('global.rootTrace:await:end');
|
|
646
663
|
_rootTracePromise = null;
|
|
647
664
|
}
|
|
648
665
|
|
|
649
666
|
if (_tracer) {
|
|
650
667
|
try {
|
|
668
|
+
cleanupDebug('global.tracer.flush:start', { tracer: _tracer.constructor.name });
|
|
651
669
|
await _tracer.flush();
|
|
670
|
+
cleanupDebug('global.tracer.flush:end', { tracer: _tracer.constructor.name });
|
|
652
671
|
if (options?.sqlite && _rootCtx) {
|
|
653
672
|
const traceId = _rootCtx.buffer.trace_id;
|
|
654
673
|
const dbPath = options.sqlite.dbPath ?? '.trace-results.db';
|
|
@@ -658,6 +677,8 @@ export function initTraceTestRun<B extends OpContextBinding>(opContext: B, optio
|
|
|
658
677
|
console.error('[lmao/testing] SQLite flush error:', e);
|
|
659
678
|
} finally {
|
|
660
679
|
await closeTracer(_tracer);
|
|
680
|
+
cleanupDebugActiveHandles('global.afterAll:handles:end');
|
|
681
|
+
cleanupDebug('global.afterAll:end');
|
|
661
682
|
}
|
|
662
683
|
}
|
|
663
684
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
2
|
import type { OpContextBinding } from '../opContext/types.js';
|
|
2
3
|
import { Tracer, type TracerOptions } from '../tracer.js';
|
|
3
4
|
import type { SpanBuffer } from '../types.js';
|
|
@@ -59,7 +60,9 @@ export class CompositeTracer<B extends OpContextBinding = OpContextBinding> exte
|
|
|
59
60
|
|
|
60
61
|
override async flush(): Promise<void> {
|
|
61
62
|
for (const tracer of this.delegates) {
|
|
63
|
+
cleanupDebug('compositeTracer.flush:delegate:start', { tracer: tracer.constructor.name });
|
|
62
64
|
await tracer.flush();
|
|
65
|
+
cleanupDebug('compositeTracer.flush:delegate:end', { tracer: tracer.constructor.name });
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -68,7 +71,9 @@ export class CompositeTracer<B extends OpContextBinding = OpContextBinding> exte
|
|
|
68
71
|
if (hasClose(tracer)) {
|
|
69
72
|
const { close } = tracer;
|
|
70
73
|
if (close) {
|
|
74
|
+
cleanupDebug('compositeTracer.close:delegate:start', { tracer: tracer.constructor.name });
|
|
71
75
|
await close.call(tracer);
|
|
76
|
+
cleanupDebug('compositeTracer.close:delegate:end', { tracer: tracer.constructor.name });
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanupDebug } from '../cleanupDiagnostics.js';
|
|
1
2
|
import type { OpContextBinding } from '../opContext/types.js';
|
|
2
3
|
import { SQLiteAsyncTraceWriter } from '../sqlite/sqlite-async-writer.js';
|
|
3
4
|
import type { AsyncSQLiteDatabase, SyncSQLiteDatabase } from '../sqlite/sqlite-db.js';
|
|
@@ -33,7 +34,9 @@ export class SQLiteTracer<B extends OpContextBinding = OpContextBinding> extends
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
onTraceEnd(rootBuffer: SpanBuffer<B['logBinding']['logSchema']>): void {
|
|
37
|
+
cleanupDebug('sqliteTracer.onTraceEnd:flush:start', { rows: rootBuffer._writeIndex });
|
|
36
38
|
this.writer.flush(rootBuffer);
|
|
39
|
+
cleanupDebug('sqliteTracer.onTraceEnd:flush:end');
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
onSpanStart(_childBuffer: SpanBuffer<B['logBinding']['logSchema']>): void {
|
|
@@ -49,7 +52,9 @@ export class SQLiteTracer<B extends OpContextBinding = OpContextBinding> extends
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
async close(): Promise<void> {
|
|
55
|
+
cleanupDebug('sqliteTracer.close:start');
|
|
52
56
|
this.writer.close();
|
|
57
|
+
cleanupDebug('sqliteTracer.close:end');
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
|
|
@@ -96,6 +101,7 @@ export class SQLiteAsyncTracer<B extends OpContextBinding = OpContextBinding> ex
|
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
override async flush(): Promise<void> {
|
|
104
|
+
cleanupDebug('sqliteAsyncTracer.flush:start');
|
|
99
105
|
await this.pendingWrites;
|
|
100
106
|
if (this.pendingErrors.length > 0) {
|
|
101
107
|
const errors = this.pendingErrors;
|
|
@@ -105,11 +111,14 @@ export class SQLiteAsyncTracer<B extends OpContextBinding = OpContextBinding> ex
|
|
|
105
111
|
}
|
|
106
112
|
throw new AggregateError(errors, `SQLiteAsyncTracer flush failed for ${errors.length} trace writes`);
|
|
107
113
|
}
|
|
114
|
+
cleanupDebug('sqliteAsyncTracer.flush:end');
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
async close(): Promise<void> {
|
|
118
|
+
cleanupDebug('sqliteAsyncTracer.close:start');
|
|
111
119
|
await this.flush();
|
|
112
120
|
const writer = await this.writerPromise;
|
|
113
121
|
await writer.close();
|
|
122
|
+
cleanupDebug('sqliteAsyncTracer.close:end');
|
|
114
123
|
}
|
|
115
124
|
}
|