@smoothbricks/lmao 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -206
- package/dist/allocator.wasm +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/JsBufferStrategy.d.ts +4 -3
- package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
- package/dist/lib/JsBufferStrategy.js +18 -11
- package/dist/lib/arrow/lease.d.ts +10 -0
- package/dist/lib/arrow/lease.d.ts.map +1 -0
- package/dist/lib/arrow/lease.js +33 -0
- package/dist/lib/arrow/utils.d.ts +3 -4
- package/dist/lib/arrow/utils.d.ts.map +1 -1
- package/dist/lib/arrow/utils.js +12 -13
- package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
- package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
- package/dist/lib/arrow/vocabularyDictionary.js +95 -0
- package/dist/lib/bufferStrategy.d.ts +3 -2
- package/dist/lib/bufferStrategy.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.js +3 -2
- package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/evaluatorGenerator.js +12 -11
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
- package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
- package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
- package/dist/lib/convertToArrow.d.ts +7 -2
- package/dist/lib/convertToArrow.d.ts.map +1 -1
- package/dist/lib/convertToArrow.js +499 -285
- package/dist/lib/defineOpContext.js +1 -1
- package/dist/lib/enumMetadata.d.ts +19 -0
- package/dist/lib/enumMetadata.d.ts.map +1 -0
- package/dist/lib/enumMetadata.js +86 -0
- package/dist/lib/flushScheduler.d.ts.map +1 -1
- package/dist/lib/flushScheduler.js +13 -4
- package/dist/lib/library.d.ts +16 -98
- package/dist/lib/library.d.ts.map +1 -1
- package/dist/lib/library.js +32 -525
- package/dist/lib/logBinding.d.ts +21 -27
- package/dist/lib/logBinding.d.ts.map +1 -1
- package/dist/lib/op.d.ts +30 -30
- package/dist/lib/op.d.ts.map +1 -1
- package/dist/lib/op.js +15 -22
- package/dist/lib/opContext/createOpGroup.d.ts +1 -1
- package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
- package/dist/lib/opContext/createOpGroup.js +22 -29
- package/dist/lib/opContext/defineOp.d.ts +4 -4
- package/dist/lib/opContext/defineOp.d.ts.map +1 -1
- package/dist/lib/opContext/defineOp.js +53 -10
- package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
- package/dist/lib/opContext/opTypes.d.ts +1 -1
- package/dist/lib/opContext/opTypes.d.ts.map +1 -1
- package/dist/lib/opContext/spanContextTypes.d.ts +33 -18
- package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
- package/dist/lib/opContext/types.d.ts +4 -4
- package/dist/lib/opContext/types.d.ts.map +1 -1
- package/dist/lib/physicalLayoutPlan.d.ts +89 -0
- package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
- package/dist/lib/physicalLayoutPlan.js +442 -0
- package/dist/lib/resolveMessage.d.ts +9 -0
- package/dist/lib/resolveMessage.d.ts.map +1 -0
- package/dist/lib/resolveMessage.js +63 -0
- package/dist/lib/result.d.ts +5 -7
- package/dist/lib/result.d.ts.map +1 -1
- package/dist/lib/result.js +19 -26
- package/dist/lib/runtimeHint.d.ts +35 -0
- package/dist/lib/runtimeHint.d.ts.map +1 -0
- package/dist/lib/runtimeHint.js +79 -0
- package/dist/lib/schema/typeGuards.d.ts +7 -47
- package/dist/lib/schema/typeGuards.d.ts.map +1 -1
- package/dist/lib/schema/typeGuards.js +7 -123
- package/dist/lib/schema/types.d.ts +1 -1
- package/dist/lib/schema/types.d.ts.map +1 -1
- package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
- package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
- package/dist/lib/span-buffer/aot/v1.js +24 -0
- package/dist/lib/spanBuffer.d.ts +33 -4
- package/dist/lib/spanBuffer.d.ts.map +1 -1
- package/dist/lib/spanBuffer.js +583 -91
- package/dist/lib/spanBufferStats.d.ts +1 -1
- package/dist/lib/spanBufferStats.d.ts.map +1 -1
- package/dist/lib/spanContext.d.ts +27 -51
- package/dist/lib/spanContext.d.ts.map +1 -1
- package/dist/lib/spanContext.js +822 -344
- package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
- package/dist/lib/sqlite/sqlite-common.js +20 -21
- package/dist/lib/testing/bun-harness.d.ts +8 -3
- package/dist/lib/testing/bun-harness.d.ts.map +1 -1
- package/dist/lib/testing/bun-harness.js +30 -18
- package/dist/lib/testing/extractFacts.d.ts +1 -1
- package/dist/lib/testing/extractFacts.d.ts.map +1 -1
- package/dist/lib/testing/extractFacts.js +55 -63
- package/dist/lib/testing/facts.d.ts +1 -1
- package/dist/lib/testing/facts.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.d.ts +1 -1
- package/dist/lib/testing/queryable-span.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.js +26 -28
- package/dist/lib/testing/span-query.d.ts.map +1 -1
- package/dist/lib/testing/span-query.js +19 -22
- package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
- package/dist/lib/testing/stdio-replay.js +19 -8
- package/dist/lib/threadId.d.ts.map +1 -1
- package/dist/lib/threadId.js +6 -3
- package/dist/lib/traceContext.d.ts.map +1 -1
- package/dist/lib/traceContext.js +1 -4
- package/dist/lib/traceRoot.d.ts +30 -8
- package/dist/lib/traceRoot.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.d.ts +17 -15
- package/dist/lib/traceRoot.es.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.js +68 -34
- package/dist/lib/traceRoot.js +11 -0
- package/dist/lib/traceRoot.node.d.ts +17 -19
- package/dist/lib/traceRoot.node.d.ts.map +1 -1
- package/dist/lib/traceRoot.node.js +66 -38
- package/dist/lib/traceTopology.d.ts +42 -0
- package/dist/lib/traceTopology.d.ts.map +1 -0
- package/dist/lib/traceTopology.js +260 -0
- package/dist/lib/tracer.d.ts +9 -5
- package/dist/lib/tracer.d.ts.map +1 -1
- package/dist/lib/tracer.js +65 -71
- package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
- package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
- package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
- package/dist/lib/tracers/StdioTracer.js +15 -13
- package/dist/lib/tracers/TestTracer.d.ts +4 -6
- package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
- package/dist/lib/tracers/TestTracer.js +6 -8
- package/dist/lib/types.d.ts +49 -32
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vocabularyRegistry.d.ts +25 -0
- package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
- package/dist/lib/vocabularyRegistry.js +372 -0
- package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
- package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
- package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
- package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
- package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
- package/dist/lib/wasm/wasmAllocator.js +66 -44
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
- package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
- package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
- package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
- package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
- package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
- package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
- package/dist/lib/wasm/wasmTraceRoot.js +110 -71
- package/dist/vocabulary/register/v1.d.ts +2 -0
- package/dist/vocabulary/register/v1.d.ts.map +1 -0
- package/dist/vocabulary/register/v1.js +1 -0
- package/dist/wasm.d.ts +5 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +4 -0
- package/package.json +54 -6
- package/src/index.ts +1 -0
- package/src/lib/JsBufferStrategy.ts +27 -9
- package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
- package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
- package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
- package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
- package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
- package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
- package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
- package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
- package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
- package/src/lib/__tests__/capability-span-context.test.ts +505 -0
- package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
- package/src/lib/__tests__/eager-columns.test.ts +345 -0
- package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
- package/src/lib/__tests__/enum-metadata.test.ts +177 -0
- package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
- package/src/lib/__tests__/flushScheduler.test.ts +5 -1
- package/src/lib/__tests__/identity-view.property.test.ts +179 -0
- package/src/lib/__tests__/library.test.ts +19 -235
- package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
- package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
- package/src/lib/__tests__/op-metadata.test.ts +1 -1
- package/src/lib/__tests__/op-type-safety.test.ts +5 -16
- package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
- package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
- package/src/lib/__tests__/root-context-construction.test.ts +414 -0
- package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
- package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
- package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
- package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
- package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
- package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
- package/src/lib/__tests__/test-helpers.ts +67 -12
- package/src/lib/__tests__/threadId.test.ts +62 -0
- package/src/lib/__tests__/timestamp.test.ts +221 -93
- package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
- package/src/lib/__tests__/type-narrowing.test.ts +63 -0
- package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
- package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
- package/src/lib/arrow/lease.ts +43 -0
- package/src/lib/arrow/utils.ts +10 -14
- package/src/lib/arrow/vocabularyDictionary.ts +123 -0
- package/src/lib/bufferStrategy.ts +9 -1
- package/src/lib/cloudflare/traceRows.ts +3 -2
- package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
- package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
- package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
- package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
- package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
- package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
- package/src/lib/codegen/evaluatorGenerator.ts +18 -13
- package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
- package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
- package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
- package/src/lib/convertToArrow.ts +598 -311
- package/src/lib/defineOpContext.ts +1 -1
- package/src/lib/enumMetadata.ts +121 -0
- package/src/lib/flushScheduler.ts +11 -5
- package/src/lib/library.ts +37 -595
- package/src/lib/logBinding.ts +21 -27
- package/src/lib/op.ts +75 -18
- package/src/lib/opContext/__tests__/retry.test.ts +27 -21
- package/src/lib/opContext/createOpGroup.ts +33 -31
- package/src/lib/opContext/defineOp.ts +88 -11
- package/src/lib/opContext/opGroupTypes.ts +2 -2
- package/src/lib/opContext/opTypes.ts +1 -1
- package/src/lib/opContext/spanContextTypes.ts +122 -24
- package/src/lib/opContext/types.ts +7 -3
- package/src/lib/physicalLayoutPlan.ts +598 -0
- package/src/lib/resolveMessage.ts +67 -0
- package/src/lib/result.ts +20 -33
- package/src/lib/runtimeHint.ts +98 -0
- package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
- package/src/lib/schema/builder.ts +1 -1
- package/src/lib/schema/typeGuards.ts +7 -151
- package/src/lib/schema/types.ts +1 -1
- package/src/lib/span-buffer/aot/v1.ts +26 -0
- package/src/lib/spanBuffer.ts +658 -92
- package/src/lib/spanBufferStats.ts +1 -1
- package/src/lib/spanContext.ts +1350 -861
- package/src/lib/sqlite/sqlite-common.ts +20 -31
- package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
- package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
- package/src/lib/testing/bun-harness.ts +94 -43
- package/src/lib/testing/extractFacts.ts +64 -78
- package/src/lib/testing/facts.ts +1 -1
- package/src/lib/testing/queryable-span.ts +23 -30
- package/src/lib/testing/span-query.ts +16 -20
- package/src/lib/testing/stdio-replay.ts +25 -8
- package/src/lib/testing/vitest-harness.ts +1 -1
- package/src/lib/threadId.ts +6 -3
- package/src/lib/traceContext.ts +1 -6
- package/src/lib/traceRoot.es.ts +77 -42
- package/src/lib/traceRoot.node.ts +75 -46
- package/src/lib/traceRoot.ts +41 -14
- package/src/lib/traceTopology.ts +279 -0
- package/src/lib/tracer.ts +109 -98
- package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
- package/src/lib/tracers/StdioTracer.ts +15 -13
- package/src/lib/tracers/TestTracer.ts +6 -8
- package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
- package/src/lib/tracers/__tests__/CompositeTracer.test.ts +150 -0
- package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
- package/src/lib/types.ts +64 -33
- package/src/lib/vocabularyRegistry.ts +439 -0
- package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
- package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
- package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
- package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
- package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
- package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
- package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
- package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
- package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
- package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
- package/src/lib/wasm/wasmAllocator.ts +131 -96
- package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
- package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
- package/src/lib/wasm/wasmTraceRoot.ts +140 -78
- package/src/vocabulary/register/v1.ts +1 -0
- package/src/wasm.ts +19 -0
- package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
- package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
- package/src/lib/wasm/allocator.zig +0 -948
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { afterEach, beforeAll, describe, expect, it } from 'bun:test';
|
|
14
|
+
import { convertToArrowTable } from '../../convertToArrow.js';
|
|
14
15
|
import { defineOpContext } from '../../defineOpContext.js';
|
|
16
|
+
import { JsBufferStrategy } from '../../JsBufferStrategy.js';
|
|
17
|
+
import { resolveEntryType, resolveMessage } from '../../resolveMessage.js';
|
|
15
18
|
import { S } from '../../schema/builder.js';
|
|
16
19
|
import { defineLogSchema } from '../../schema/defineLogSchema.js';
|
|
17
20
|
import {
|
|
@@ -24,9 +27,11 @@ import {
|
|
|
24
27
|
ENTRY_TYPE_SPAN_START,
|
|
25
28
|
ENTRY_TYPE_WARN,
|
|
26
29
|
} from '../../schema/systemSchema.js';
|
|
30
|
+
import { createTraceRoot as createNodeTraceRoot } from '../../traceRoot.node.js';
|
|
27
31
|
import { TestTracer } from '../../tracers/TestTracer.js';
|
|
32
|
+
import { iterateSpanChildren } from '../../traceTopology.js';
|
|
28
33
|
import { WasmBufferStrategy } from '../WasmBufferStrategy.js';
|
|
29
|
-
import {
|
|
34
|
+
import { createWasmTraceRoot } from '../wasmTraceRoot.js';
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* Type for accessing WASM-specific internal buffer properties.
|
|
@@ -51,12 +56,22 @@ function asWasm<T>(buffer: T): T & WasmBufferInternals {
|
|
|
51
56
|
return buffer as T & WasmBufferInternals;
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
function requireOnlySpanChild(parent: Parameters<typeof iterateSpanChildren>[0], label: string) {
|
|
60
|
+
const children = iterateSpanChildren(parent);
|
|
61
|
+
const first = children.next();
|
|
62
|
+
if (first.done) throw new Error(`${label} has no child span`);
|
|
63
|
+
const extra = children.next();
|
|
64
|
+
if (!extra.done) throw new Error(`${label} has more than one child span`);
|
|
65
|
+
return first.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
54
68
|
describe('WASM Integration Tests', () => {
|
|
55
69
|
// Test schema with various field types
|
|
56
70
|
const schema = defineLogSchema({
|
|
57
71
|
userId: S.category(),
|
|
58
72
|
latency: S.number(),
|
|
59
73
|
operation: S.enum(['CREATE', 'READ', 'UPDATE', 'DELETE']),
|
|
74
|
+
success: S.boolean(),
|
|
60
75
|
});
|
|
61
76
|
|
|
62
77
|
// Define op context - env is optional (undefined by default, not null-sentinel)
|
|
@@ -77,14 +92,14 @@ describe('WASM Integration Tests', () => {
|
|
|
77
92
|
|
|
78
93
|
tracer = new TestTracer(opContext, {
|
|
79
94
|
bufferStrategy: strategy,
|
|
80
|
-
createTraceRoot:
|
|
95
|
+
createTraceRoot: (traceId, lifecycle) => createWasmTraceRoot(strategy.allocator, traceId, lifecycle),
|
|
81
96
|
});
|
|
82
97
|
});
|
|
83
98
|
|
|
84
99
|
afterEach(() => {
|
|
85
100
|
// Release all WASM memory for buffers
|
|
86
101
|
for (const buffer of tracer.rootBuffers) {
|
|
87
|
-
strategy.releaseBuffer(buffer);
|
|
102
|
+
if (buffer._traceRoot._topology.count !== 0) strategy.releaseBuffer(buffer);
|
|
88
103
|
}
|
|
89
104
|
// Clear tracer state
|
|
90
105
|
tracer.clear();
|
|
@@ -94,7 +109,7 @@ describe('WASM Integration Tests', () => {
|
|
|
94
109
|
// Create fresh tracer for next test
|
|
95
110
|
tracer = new TestTracer(opContext, {
|
|
96
111
|
bufferStrategy: strategy,
|
|
97
|
-
createTraceRoot:
|
|
112
|
+
createTraceRoot: (traceId, lifecycle) => createWasmTraceRoot(strategy.allocator, traceId, lifecycle),
|
|
98
113
|
});
|
|
99
114
|
});
|
|
100
115
|
|
|
@@ -108,15 +123,15 @@ describe('WASM Integration Tests', () => {
|
|
|
108
123
|
const buffer = tracer.rootBuffers[0];
|
|
109
124
|
|
|
110
125
|
// Verify entry types
|
|
111
|
-
expect(buffer
|
|
112
|
-
expect(buffer
|
|
126
|
+
expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
|
|
127
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
|
|
113
128
|
|
|
114
129
|
// Verify timestamps are valid
|
|
115
130
|
expect(buffer.timestamp[0]).toBeGreaterThan(0n);
|
|
116
131
|
expect(buffer.timestamp[1]).toBeGreaterThanOrEqual(buffer.timestamp[0]);
|
|
117
132
|
|
|
118
133
|
// Verify span name is set
|
|
119
|
-
expect(buffer
|
|
134
|
+
expect(resolveMessage(buffer, 0)).toBe('test-op');
|
|
120
135
|
});
|
|
121
136
|
|
|
122
137
|
it('writes trace_id correctly', async () => {
|
|
@@ -182,14 +197,10 @@ describe('WASM Integration Tests', () => {
|
|
|
182
197
|
});
|
|
183
198
|
|
|
184
199
|
const parent = tracer.rootBuffers[0];
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const child = parent._children[0];
|
|
188
|
-
// Child should share trace_id with parent
|
|
200
|
+
if (!parent) throw new Error('nested trace did not produce a root buffer');
|
|
201
|
+
const child = requireOnlySpanChild(parent, 'nested trace root');
|
|
189
202
|
expect(child.trace_id).toBe(parent.trace_id);
|
|
190
|
-
// Child's parent_span_id should be parent's span_id
|
|
191
203
|
expect(child.parent_span_id).toBe(parent.span_id);
|
|
192
|
-
// Child should have its own span_id
|
|
193
204
|
expect(child.span_id).not.toBe(parent.span_id);
|
|
194
205
|
});
|
|
195
206
|
|
|
@@ -205,13 +216,11 @@ describe('WASM Integration Tests', () => {
|
|
|
205
216
|
});
|
|
206
217
|
|
|
207
218
|
const root = tracer.rootBuffers[0];
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const level1 = root._children[0];
|
|
211
|
-
expect(level1._children).toHaveLength(1);
|
|
219
|
+
if (!root) throw new Error('deep trace did not produce a root buffer');
|
|
220
|
+
const level1 = requireOnlySpanChild(root, 'deep trace root');
|
|
212
221
|
expect(level1.parent_span_id).toBe(root.span_id);
|
|
213
222
|
|
|
214
|
-
const level2 = level1
|
|
223
|
+
const level2 = requireOnlySpanChild(level1, 'level-1 span');
|
|
215
224
|
expect(level2.parent_span_id).toBe(level1.span_id);
|
|
216
225
|
expect(level2.trace_id).toBe(root.trace_id);
|
|
217
226
|
});
|
|
@@ -224,14 +233,19 @@ describe('WASM Integration Tests', () => {
|
|
|
224
233
|
});
|
|
225
234
|
|
|
226
235
|
const parent = tracer.rootBuffers[0];
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
if (!parent) throw new Error('sibling trace did not produce a root buffer');
|
|
237
|
+
const children = iterateSpanChildren(parent);
|
|
238
|
+
const first = children.next();
|
|
239
|
+
if (first.done) throw new Error('sibling trace did not produce its first child');
|
|
240
|
+
const second = children.next();
|
|
241
|
+
if (second.done) throw new Error('sibling trace did not produce its second child');
|
|
242
|
+
if (!children.next().done) throw new Error('sibling trace produced an unexpected extra child');
|
|
243
|
+
const child1 = first.value;
|
|
244
|
+
const child2 = second.value;
|
|
245
|
+
expect(resolveMessage(child1, 0)).toBe('child-1');
|
|
246
|
+
expect(resolveMessage(child2, 0)).toBe('child-2');
|
|
232
247
|
expect(child1.parent_span_id).toBe(parent.span_id);
|
|
233
248
|
expect(child2.parent_span_id).toBe(parent.span_id);
|
|
234
|
-
// Siblings should have different span IDs
|
|
235
249
|
expect(child1.span_id).not.toBe(child2.span_id);
|
|
236
250
|
});
|
|
237
251
|
});
|
|
@@ -247,12 +261,10 @@ describe('WASM Integration Tests', () => {
|
|
|
247
261
|
}
|
|
248
262
|
|
|
249
263
|
const buffer = asWasm(tracer.rootBuffers[0]);
|
|
250
|
-
expect(buffer
|
|
251
|
-
expect(buffer
|
|
264
|
+
expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
|
|
265
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_EXCEPTION);
|
|
252
266
|
|
|
253
|
-
|
|
254
|
-
const messageValues = buffer.message_values;
|
|
255
|
-
const messages = messageValues.slice(0, buffer._writeIndex).filter((m: string) => m !== undefined);
|
|
267
|
+
const messages = Array.from({ length: buffer._writeIndex }, (_, row) => resolveMessage(buffer, row));
|
|
256
268
|
expect(messages).toContain('test error');
|
|
257
269
|
});
|
|
258
270
|
|
|
@@ -279,8 +291,8 @@ describe('WASM Integration Tests', () => {
|
|
|
279
291
|
});
|
|
280
292
|
|
|
281
293
|
const buffer = tracer.rootBuffers[0];
|
|
282
|
-
expect(buffer
|
|
283
|
-
expect(buffer
|
|
294
|
+
expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
|
|
295
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_ERR);
|
|
284
296
|
});
|
|
285
297
|
|
|
286
298
|
it('writes error code for typed errors', async () => {
|
|
@@ -289,7 +301,7 @@ describe('WASM Integration Tests', () => {
|
|
|
289
301
|
});
|
|
290
302
|
|
|
291
303
|
const buffer = asWasm(tracer.rootBuffers[0]);
|
|
292
|
-
expect(buffer
|
|
304
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_ERR);
|
|
293
305
|
// Error code should be written to error_code column
|
|
294
306
|
expect(buffer.error_code_values?.[1]).toBe('VALIDATION_ERROR');
|
|
295
307
|
});
|
|
@@ -310,21 +322,18 @@ describe('WASM Integration Tests', () => {
|
|
|
310
322
|
expect(buffer._writeIndex).toBeGreaterThan(2);
|
|
311
323
|
|
|
312
324
|
// Row 0 = span-start, Row 1 = span-ok (written at end)
|
|
313
|
-
expect(buffer
|
|
314
|
-
expect(buffer
|
|
325
|
+
expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
|
|
326
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
|
|
315
327
|
|
|
316
328
|
// Log entries are written at indices 2+
|
|
317
|
-
const entryTypes = Array.from(buffer.
|
|
329
|
+
const entryTypes = Array.from({ length: buffer._writeIndex }, (_, row) => resolveEntryType(buffer, row));
|
|
318
330
|
|
|
319
331
|
// Use entry type constants from systemSchema
|
|
320
332
|
expect(entryTypes).toContain(ENTRY_TYPE_INFO);
|
|
321
333
|
expect(entryTypes).toContain(ENTRY_TYPE_DEBUG);
|
|
322
334
|
expect(entryTypes).toContain(ENTRY_TYPE_WARN);
|
|
323
335
|
|
|
324
|
-
|
|
325
|
-
// Access via the getter since that's what SpanLogger writes to
|
|
326
|
-
const messageValues = buffer.message_values;
|
|
327
|
-
const messages = messageValues.slice(0, buffer._writeIndex).filter((m: string) => m !== undefined);
|
|
336
|
+
const messages = Array.from({ length: buffer._writeIndex }, (_, row) => resolveMessage(buffer, row));
|
|
328
337
|
expect(messages).toContain('info message');
|
|
329
338
|
expect(messages).toContain('debug message');
|
|
330
339
|
expect(messages).toContain('warn message');
|
|
@@ -338,11 +347,176 @@ describe('WASM Integration Tests', () => {
|
|
|
338
347
|
|
|
339
348
|
const buffer = asWasm(tracer.rootBuffers[0]);
|
|
340
349
|
// Use entry type constant from systemSchema
|
|
341
|
-
const entryTypes = Array.from(buffer.
|
|
350
|
+
const entryTypes = Array.from({ length: buffer._writeIndex }, (_, row) => resolveEntryType(buffer, row));
|
|
342
351
|
expect(entryTypes).toContain(ENTRY_TYPE_ERROR);
|
|
343
352
|
});
|
|
344
353
|
});
|
|
345
354
|
|
|
355
|
+
describe('Identity ownership', () => {
|
|
356
|
+
it('invalidates released root and child handles before recycled memory is reused', async () => {
|
|
357
|
+
await tracer.trace('owned-root', async (ctx) => {
|
|
358
|
+
await ctx.span('released-child', async (child) => child.ok('child done'));
|
|
359
|
+
return ctx.ok('root done');
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const root = tracer.rootBuffers[0];
|
|
363
|
+
if (!root) throw new Error('released trace did not produce a root buffer');
|
|
364
|
+
const child = requireOnlySpanChild(root, 'released trace root');
|
|
365
|
+
const topology = root._traceRoot._topology;
|
|
366
|
+
const rootTraceId = root.trace_id;
|
|
367
|
+
const rootSpanId = root.span_id;
|
|
368
|
+
expect(child.trace_id).toBe(rootTraceId);
|
|
369
|
+
expect(child.span_id).not.toBe(rootSpanId);
|
|
370
|
+
expect(child.parent_span_id).toBe(rootSpanId);
|
|
371
|
+
expect(child._identity).not.toEqual(root._identity);
|
|
372
|
+
|
|
373
|
+
strategy.releaseBuffer(root);
|
|
374
|
+
expect(topology.count).toBe(0);
|
|
375
|
+
expect(() => topology.assertLive(root)).toThrow(/stale/);
|
|
376
|
+
expect(() => topology.assertLive(child)).toThrow(/stale/);
|
|
377
|
+
expect(() => iterateSpanChildren(root).next()).toThrow(/stale/);
|
|
378
|
+
|
|
379
|
+
await tracer.trace('recycled-child-identity', async (ctx) => ctx.ok('done'));
|
|
380
|
+
const recycled = tracer.rootBuffers[1];
|
|
381
|
+
if (!recycled) throw new Error('recycled trace did not produce a root buffer');
|
|
382
|
+
expect(recycled.trace_id).not.toBe(rootTraceId);
|
|
383
|
+
expect(resolveMessage(recycled, 0)).toBe('recycled-child-identity');
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('preserves logical span identity and linkage across overflow segments', async () => {
|
|
387
|
+
await tracer.trace('overflow-root', async (ctx) => {
|
|
388
|
+
for (let i = 0; i < 64; i++) {
|
|
389
|
+
ctx.log.info(`root-log-${i}`);
|
|
390
|
+
}
|
|
391
|
+
await ctx.span('overflow-child', async (child) => {
|
|
392
|
+
for (let i = 0; i < 64; i++) {
|
|
393
|
+
child.log.info(`child-log-${i}`);
|
|
394
|
+
}
|
|
395
|
+
return child.ok('child done');
|
|
396
|
+
});
|
|
397
|
+
return ctx.ok('root done');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const root = tracer.rootBuffers[0];
|
|
401
|
+
const rootOverflow = root._overflow;
|
|
402
|
+
if (!rootOverflow) throw new Error('root logs did not create an overflow segment');
|
|
403
|
+
expect(rootOverflow.trace_id).toBe(root.trace_id);
|
|
404
|
+
expect(rootOverflow.span_id).toBe(root.span_id);
|
|
405
|
+
expect(rootOverflow.parent_span_id).toBe(root.parent_span_id);
|
|
406
|
+
expect(rootOverflow._identity).toEqual(root._identity);
|
|
407
|
+
|
|
408
|
+
const child = requireOnlySpanChild(root, 'overflow trace root');
|
|
409
|
+
const childOverflow = child._overflow;
|
|
410
|
+
if (!childOverflow) throw new Error('child logs did not create an overflow segment');
|
|
411
|
+
expect(child.trace_id).toBe(root.trace_id);
|
|
412
|
+
expect(child.span_id).not.toBe(root.span_id);
|
|
413
|
+
expect(child.parent_span_id).toBe(root.span_id);
|
|
414
|
+
expect(childOverflow.trace_id).toBe(child.trace_id);
|
|
415
|
+
expect(childOverflow.span_id).toBe(child.span_id);
|
|
416
|
+
expect(childOverflow.parent_span_id).toBe(child.parent_span_id);
|
|
417
|
+
expect(childOverflow._identity).toEqual(child._identity);
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('Released memory ownership', () => {
|
|
422
|
+
it('keeps two new traces independent after repeated tree release', async () => {
|
|
423
|
+
await tracer.trace('released-tree', async (ctx) => {
|
|
424
|
+
await ctx.span('released-child', async (child) => {
|
|
425
|
+
child.tag.latency(1);
|
|
426
|
+
return child.ok('done');
|
|
427
|
+
});
|
|
428
|
+
return ctx.ok('done');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const released = tracer.rootBuffers[0];
|
|
432
|
+
strategy.releaseBuffer(released);
|
|
433
|
+
expect(() => strategy.releaseBuffer(released)).toThrow(/stale/);
|
|
434
|
+
|
|
435
|
+
await tracer.trace('first-new-owner', async (ctx) => {
|
|
436
|
+
ctx.tag.latency(11.5);
|
|
437
|
+
return ctx.ok('done');
|
|
438
|
+
});
|
|
439
|
+
await tracer.trace('second-new-owner', async (ctx) => {
|
|
440
|
+
ctx.tag.latency(22.5);
|
|
441
|
+
return ctx.ok('done');
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const firstTable = strategy.toArrowTable(tracer.rootBuffers[1]);
|
|
445
|
+
const secondTable = strategy.toArrowTable(tracer.rootBuffers[2]);
|
|
446
|
+
expect(firstTable.getChild('message')?.get(0)).toBe('first-new-owner');
|
|
447
|
+
expect(firstTable.getChild('latency')?.get(0)).toBe(11.5);
|
|
448
|
+
expect(secondTable.getChild('message')?.get(0)).toBe('second-new-owner');
|
|
449
|
+
expect(secondTable.getChild('latency')?.get(0)).toBe(22.5);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('keeps single-buffer Arrow output isolated from recycled WASM memory', async () => {
|
|
453
|
+
await tracer.trace('arrow-first', async (ctx) => {
|
|
454
|
+
ctx.tag.latency(91.25).success(true).operation('READ');
|
|
455
|
+
return ctx.ok('done');
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const firstBuffer = tracer.rootBuffers[0];
|
|
459
|
+
const firstTable = convertToArrowTable(firstBuffer);
|
|
460
|
+
expect(firstTable.numRows).toBe(2);
|
|
461
|
+
expect(firstTable.getChild('message')?.get(0)).toBe('arrow-first');
|
|
462
|
+
expect(firstTable.getChild('latency')?.get(0)).toBe(91.25);
|
|
463
|
+
expect(firstTable.getChild('success')?.get(0)).toBe(true);
|
|
464
|
+
expect(firstTable.getChild('operation')?.get(0)).toBe('READ');
|
|
465
|
+
|
|
466
|
+
strategy.releaseBuffer(firstBuffer);
|
|
467
|
+
await tracer.trace('arrow-second', async (ctx) => {
|
|
468
|
+
ctx.tag.latency(-17.5).success(false).operation('DELETE');
|
|
469
|
+
return ctx.ok('done');
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const secondTable = convertToArrowTable(tracer.rootBuffers[1]);
|
|
473
|
+
expect(secondTable.getChild('latency')?.get(0)).toBe(-17.5);
|
|
474
|
+
expect(secondTable.getChild('success')?.get(0)).toBe(false);
|
|
475
|
+
expect(secondTable.getChild('operation')?.get(0)).toBe('DELETE');
|
|
476
|
+
expect(firstTable.getChild('message')?.get(0)).toBe('arrow-first');
|
|
477
|
+
expect(firstTable.getChild('latency')?.get(0)).toBe(91.25);
|
|
478
|
+
expect(firstTable.getChild('success')?.get(0)).toBe(true);
|
|
479
|
+
expect(firstTable.getChild('operation')?.get(0)).toBe('READ');
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it('keeps span-tree Arrow output isolated from recycled WASM memory', async () => {
|
|
483
|
+
await tracer.trace('tree-first', async (ctx) => {
|
|
484
|
+
ctx.tag.latency(1.25);
|
|
485
|
+
await ctx.span('child-first', async (child) => {
|
|
486
|
+
child.tag.latency(2.5);
|
|
487
|
+
return child.ok('done');
|
|
488
|
+
});
|
|
489
|
+
return ctx.ok('done');
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
const firstBuffer = tracer.rootBuffers[0];
|
|
493
|
+
const firstTable = strategy.toArrowTable(firstBuffer);
|
|
494
|
+
expect(firstTable.numRows).toBe(4);
|
|
495
|
+
expect(firstTable.getChild('message')?.get(0)).toBe('tree-first');
|
|
496
|
+
expect(firstTable.getChild('message')?.get(2)).toBe('child-first');
|
|
497
|
+
expect(firstTable.getChild('latency')?.get(0)).toBe(1.25);
|
|
498
|
+
expect(firstTable.getChild('latency')?.get(2)).toBe(2.5);
|
|
499
|
+
|
|
500
|
+
strategy.releaseBuffer(firstBuffer);
|
|
501
|
+
await tracer.trace('tree-second', async (ctx) => {
|
|
502
|
+
ctx.tag.latency(101.25);
|
|
503
|
+
await ctx.span('child-second', async (child) => {
|
|
504
|
+
child.tag.latency(202.5);
|
|
505
|
+
return child.ok('done');
|
|
506
|
+
});
|
|
507
|
+
return ctx.ok('done');
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
const secondTable = strategy.toArrowTable(tracer.rootBuffers[1]);
|
|
511
|
+
expect(secondTable.getChild('latency')?.get(0)).toBe(101.25);
|
|
512
|
+
expect(secondTable.getChild('latency')?.get(2)).toBe(202.5);
|
|
513
|
+
expect(firstTable.getChild('message')?.get(0)).toBe('tree-first');
|
|
514
|
+
expect(firstTable.getChild('message')?.get(2)).toBe('child-first');
|
|
515
|
+
expect(firstTable.getChild('latency')?.get(0)).toBe(1.25);
|
|
516
|
+
expect(firstTable.getChild('latency')?.get(2)).toBe(2.5);
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
|
|
346
520
|
describe('Memory reuse', () => {
|
|
347
521
|
it('tracks allocation stats', async () => {
|
|
348
522
|
const statsBefore = strategy.getStats();
|
|
@@ -422,7 +596,7 @@ describe('WASM Integration Tests', () => {
|
|
|
422
596
|
}
|
|
423
597
|
|
|
424
598
|
const buffer = tracer.rootBuffers[0];
|
|
425
|
-
expect(buffer
|
|
599
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
|
|
426
600
|
});
|
|
427
601
|
|
|
428
602
|
it('handles async functions correctly', async () => {
|
|
@@ -438,12 +612,211 @@ describe('WASM Integration Tests', () => {
|
|
|
438
612
|
}
|
|
439
613
|
|
|
440
614
|
const buffer = tracer.rootBuffers[0];
|
|
441
|
-
expect(buffer
|
|
615
|
+
expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
|
|
442
616
|
// Timestamps should reflect the delay
|
|
443
617
|
expect(buffer.timestamp[1]).toBeGreaterThan(buffer.timestamp[0]);
|
|
444
618
|
});
|
|
445
619
|
});
|
|
446
620
|
|
|
621
|
+
describe('JS/WASM timestamp output parity', () => {
|
|
622
|
+
it('emits identical timestamped lifecycle rows across overflow and child spans', async () => {
|
|
623
|
+
const jsSchema = defineLogSchema({
|
|
624
|
+
userId: S.category(),
|
|
625
|
+
latency: S.number(),
|
|
626
|
+
operation: S.enum(['CREATE', 'READ', 'UPDATE', 'DELETE']),
|
|
627
|
+
success: S.boolean(),
|
|
628
|
+
});
|
|
629
|
+
const jsOpContext = defineOpContext({
|
|
630
|
+
logSchema: jsSchema,
|
|
631
|
+
ctx: { env: undefined as { region: string } | undefined },
|
|
632
|
+
});
|
|
633
|
+
const jsStrategy = new JsBufferStrategy<typeof jsSchema>();
|
|
634
|
+
const jsTracer = new TestTracer(jsOpContext, {
|
|
635
|
+
bufferStrategy: jsStrategy,
|
|
636
|
+
createTraceRoot: createNodeTraceRoot,
|
|
637
|
+
});
|
|
638
|
+
const originalDateNow = Date.now;
|
|
639
|
+
const originalHrtime = process.hrtime.bigint;
|
|
640
|
+
const originalPerformanceNow = performance.now;
|
|
641
|
+
const epochMillis = 1_700_000_000_000;
|
|
642
|
+
const nodeAnchor = 5_000_000n;
|
|
643
|
+
const performanceAnchor = 1_000;
|
|
644
|
+
|
|
645
|
+
try {
|
|
646
|
+
Date.now = () => epochMillis;
|
|
647
|
+
let nodeTick = 0n;
|
|
648
|
+
process.hrtime.bigint = () => nodeAnchor + nodeTick++ * 125_000n;
|
|
649
|
+
await jsTracer.trace('parity-root', async (root) => {
|
|
650
|
+
for (let i = 0; i < 70; i++) root.log.info(`root-${i}`);
|
|
651
|
+
await root.span('parity-child', async (child) => {
|
|
652
|
+
for (let i = 0; i < 70; i++) child.log.info(`child-${i}`);
|
|
653
|
+
return child.ok('child done');
|
|
654
|
+
});
|
|
655
|
+
return root.ok('root done');
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
let performanceTick = 0;
|
|
659
|
+
Object.defineProperty(performance, 'now', {
|
|
660
|
+
configurable: true,
|
|
661
|
+
value: () => performanceAnchor + performanceTick++ * 0.125,
|
|
662
|
+
});
|
|
663
|
+
await tracer.trace('parity-root', async (root) => {
|
|
664
|
+
for (let i = 0; i < 70; i++) root.log.info(`root-${i}`);
|
|
665
|
+
await root.span('parity-child', async (child) => {
|
|
666
|
+
for (let i = 0; i < 70; i++) child.log.info(`child-${i}`);
|
|
667
|
+
return child.ok('child done');
|
|
668
|
+
});
|
|
669
|
+
return root.ok('root done');
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
const jsTable = jsStrategy.toArrowTable(jsTracer.rootBuffers[0]);
|
|
673
|
+
const wasmTable = strategy.toArrowTable(tracer.rootBuffers[0]);
|
|
674
|
+
expect(wasmTable.numRows).toBe(jsTable.numRows);
|
|
675
|
+
for (const columnName of ['entry_type', 'message', 'timestamp'] as const) {
|
|
676
|
+
const jsColumn = jsTable.getChild(columnName);
|
|
677
|
+
const wasmColumn = wasmTable.getChild(columnName);
|
|
678
|
+
if (!jsColumn || !wasmColumn) throw new Error(`missing parity column: ${columnName}`);
|
|
679
|
+
const jsValues = Array.from({ length: jsTable.numRows }, (_, row) => jsColumn.get(row));
|
|
680
|
+
const wasmValues = Array.from({ length: wasmTable.numRows }, (_, row) => wasmColumn.get(row));
|
|
681
|
+
expect(wasmValues).toEqual(jsValues);
|
|
682
|
+
}
|
|
683
|
+
} finally {
|
|
684
|
+
Date.now = originalDateNow;
|
|
685
|
+
process.hrtime.bigint = originalHrtime;
|
|
686
|
+
Object.defineProperty(performance, 'now', { configurable: true, value: originalPerformanceNow });
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
it('preserves ordered Arrow rows for root, child, grandchild, random, and overflow workloads', async () => {
|
|
691
|
+
const jsStrategy = new JsBufferStrategy<typeof schema>();
|
|
692
|
+
const jsTracer = new TestTracer(opContext, {
|
|
693
|
+
bufferStrategy: jsStrategy,
|
|
694
|
+
createTraceRoot: createNodeTraceRoot,
|
|
695
|
+
});
|
|
696
|
+
const workloads = [
|
|
697
|
+
{
|
|
698
|
+
name: 'root',
|
|
699
|
+
run: async (target: typeof tracer) => {
|
|
700
|
+
await target.trace('ordered-root', async (root) => {
|
|
701
|
+
root.tag.latency(1.25).success(true).operation('CREATE');
|
|
702
|
+
root.log.info('ordered-root-log');
|
|
703
|
+
return root.ok('root done');
|
|
704
|
+
});
|
|
705
|
+
return ['ordered-root'];
|
|
706
|
+
},
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
name: 'child',
|
|
710
|
+
run: async (target: typeof tracer) => {
|
|
711
|
+
await target.trace('ordered-parent', async (root) => {
|
|
712
|
+
await root.span('ordered-child-0', async (child) => child.ok('first child done'));
|
|
713
|
+
await root.span('ordered-child-1', async (child) => child.ok('second child done'));
|
|
714
|
+
return root.ok('parent done');
|
|
715
|
+
});
|
|
716
|
+
return ['ordered-parent', 'ordered-child-0', 'ordered-child-1'];
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'grandchild',
|
|
721
|
+
run: async (target: typeof tracer) => {
|
|
722
|
+
await target.trace('ordered-grand-root', async (root) => {
|
|
723
|
+
await root.span('ordered-branch', async (child) => {
|
|
724
|
+
await child.span('ordered-grandchild', async (grandchild) => grandchild.ok('grandchild done'));
|
|
725
|
+
return child.ok('branch done');
|
|
726
|
+
});
|
|
727
|
+
await root.span('ordered-sibling', async (child) => child.ok('sibling done'));
|
|
728
|
+
return root.ok('grand root done');
|
|
729
|
+
});
|
|
730
|
+
return ['ordered-grand-root', 'ordered-branch', 'ordered-grandchild', 'ordered-sibling'];
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
name: 'random',
|
|
735
|
+
run: async (target: typeof tracer) => {
|
|
736
|
+
let state = 0x6d2b_79f5;
|
|
737
|
+
const next = () => {
|
|
738
|
+
state = (Math.imul(state, 1_664_525) + 1_013_904_223) >>> 0;
|
|
739
|
+
return state;
|
|
740
|
+
};
|
|
741
|
+
const expected = ['random-root'];
|
|
742
|
+
await target.trace('random-root', async (root) => {
|
|
743
|
+
for (let childIndex = 0; childIndex < 24; childIndex++) {
|
|
744
|
+
const childName = `random-child-${childIndex}`;
|
|
745
|
+
expected.push(childName);
|
|
746
|
+
await root.span(childName, async (child) => {
|
|
747
|
+
const logCount = next() % 6;
|
|
748
|
+
for (let logIndex = 0; logIndex < logCount; logIndex++) {
|
|
749
|
+
child.log.info(`random-log-${childIndex}-${logIndex}`);
|
|
750
|
+
}
|
|
751
|
+
const grandchildCount = next() % 4;
|
|
752
|
+
for (let grandchildIndex = 0; grandchildIndex < grandchildCount; grandchildIndex++) {
|
|
753
|
+
const grandchildName = `random-grandchild-${childIndex}-${grandchildIndex}`;
|
|
754
|
+
expected.push(grandchildName);
|
|
755
|
+
await child.span(grandchildName, async (grandchild) => {
|
|
756
|
+
grandchild.tag.latency(next() % 10_000).operation('UPDATE');
|
|
757
|
+
return grandchild.ok('random grandchild done');
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
return child.ok('random child done');
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
return root.ok('random root done');
|
|
764
|
+
});
|
|
765
|
+
return expected;
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
name: 'overflow',
|
|
770
|
+
run: async (target: typeof tracer) => {
|
|
771
|
+
await target.trace('overflow-parity-root', async (root) => {
|
|
772
|
+
for (let index = 0; index < 70; index++) root.log.info(`overflow-root-${index}`);
|
|
773
|
+
await root.span('overflow-parity-child', async (child) => {
|
|
774
|
+
for (let index = 0; index < 70; index++) child.log.info(`overflow-child-${index}`);
|
|
775
|
+
return child.ok('overflow child done');
|
|
776
|
+
});
|
|
777
|
+
return root.ok('overflow root done');
|
|
778
|
+
});
|
|
779
|
+
return ['overflow-parity-root', 'overflow-parity-child'];
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
];
|
|
783
|
+
|
|
784
|
+
for (const workload of workloads) {
|
|
785
|
+
const jsRootIndex = jsTracer.rootBuffers.length;
|
|
786
|
+
const wasmRootIndex = tracer.rootBuffers.length;
|
|
787
|
+
const jsExpected = await workload.run(jsTracer);
|
|
788
|
+
const wasmExpected = await workload.run(tracer);
|
|
789
|
+
expect(wasmExpected).toEqual(jsExpected);
|
|
790
|
+
|
|
791
|
+
const jsRoot = jsTracer.rootBuffers[jsRootIndex];
|
|
792
|
+
if (!jsRoot) throw new Error(`${workload.name} JS workload did not produce a root buffer`);
|
|
793
|
+
const wasmRoot = tracer.rootBuffers[wasmRootIndex];
|
|
794
|
+
if (!wasmRoot) throw new Error(`${workload.name} WASM workload did not produce a root buffer`);
|
|
795
|
+
const jsTable = jsStrategy.toArrowTable(jsRoot);
|
|
796
|
+
const wasmTable = strategy.toArrowTable(wasmRoot);
|
|
797
|
+
expect(wasmTable.numRows).toBe(jsTable.numRows);
|
|
798
|
+
|
|
799
|
+
for (const columnName of ['entry_type', 'message', 'latency', 'success', 'operation']) {
|
|
800
|
+
const jsColumn = jsTable.getChild(columnName);
|
|
801
|
+
const wasmColumn = wasmTable.getChild(columnName);
|
|
802
|
+
if (!jsColumn || !wasmColumn) throw new Error(`${workload.name} is missing parity column ${columnName}`);
|
|
803
|
+
const jsValues = Array.from({ length: jsTable.numRows }, (_, row) => jsColumn.get(row));
|
|
804
|
+
const wasmValues = Array.from({ length: wasmTable.numRows }, (_, row) => wasmColumn.get(row));
|
|
805
|
+
expect(wasmValues).toEqual(jsValues);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
const entryTypes = wasmTable.getChild('entry_type');
|
|
809
|
+
const messages = wasmTable.getChild('message');
|
|
810
|
+
if (!entryTypes || !messages) throw new Error(`${workload.name} is missing ordered span columns`);
|
|
811
|
+
const spanOrder: unknown[] = [];
|
|
812
|
+
for (let row = 0; row < wasmTable.numRows; row++) {
|
|
813
|
+
if (entryTypes.get(row) === 'span-start') spanOrder.push(messages.get(row));
|
|
814
|
+
}
|
|
815
|
+
expect(spanOrder).toEqual(wasmExpected);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
|
|
447
820
|
describe('Multiple traces', () => {
|
|
448
821
|
it('maintains separate buffers for each trace', async () => {
|
|
449
822
|
await tracer.trace('trace-1', async (ctx) => {
|
|
@@ -465,8 +838,8 @@ describe('WASM Integration Tests', () => {
|
|
|
465
838
|
expect(buffer1.trace_id).not.toBe(buffer2.trace_id);
|
|
466
839
|
|
|
467
840
|
// Different span names
|
|
468
|
-
expect(buffer1
|
|
469
|
-
expect(buffer2
|
|
841
|
+
expect(resolveMessage(buffer1, 0)).toBe('trace-1');
|
|
842
|
+
expect(resolveMessage(buffer2, 0)).toBe('trace-2');
|
|
470
843
|
|
|
471
844
|
// Different user IDs
|
|
472
845
|
expect(buffer1.userId_values?.[0]).toBe('user-1');
|