@agoric/telemetry 0.6.3-u20.0 → 0.6.3-u21.0.1
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/CHANGELOG.md +5 -1
- package/package.json +12 -11
- package/src/flight-recorder.js +12 -9
- package/src/frcat-entrypoint.js +2 -2
- package/src/otel-metrics.js +7 -1
- package/src/slog-sender-pipe.js +12 -0
- package/test/flight-recorder.test.js +10 -16
- package/yarn-error.log +20902 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
### [0.6.3-
|
|
6
|
+
### [0.6.3-u21.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/telemetry@0.6.2...@agoric/telemetry@0.6.3-u21.0) (2025-06-19)
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
### Features
|
|
@@ -24,9 +24,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|
|
24
24
|
* ensure script main rejections exit with error ([abdab87](https://github.com/Agoric/agoric-sdk/commit/abdab879014a5c3124ebd0e9246995ac6b1ce6e5))
|
|
25
25
|
* Properly synchronize slog sender termination ([f83c01d](https://github.com/Agoric/agoric-sdk/commit/f83c01d89d80798e0922acdb498fcc7250560977))
|
|
26
26
|
* **telemetry:** add missing slog type ([1aec8d0](https://github.com/Agoric/agoric-sdk/commit/1aec8d05036f6b3c3e3730339d1829da6b4a9051))
|
|
27
|
+
* **telemetry:** async flight recorder read ([b7a19dd](https://github.com/Agoric/agoric-sdk/commit/b7a19dd9c106d9b31e6f9188f5d4df0bbb5132bf))
|
|
27
28
|
* **telemetry:** avoid polluting stdout in ingest-slog ([d4b8dfa](https://github.com/Agoric/agoric-sdk/commit/d4b8dfa91155789f7ceda5cc3cef06019b9527e7))
|
|
28
29
|
* **telemetry:** Empty context persisted when remaining beans are negative after run finish ([#10635](https://github.com/Agoric/agoric-sdk/issues/10635)) ([ad4e83e](https://github.com/Agoric/agoric-sdk/commit/ad4e83e0b6dff9716da91fd65d367d3acad1772e))
|
|
29
30
|
* **telemetry:** event name typo ([9e19321](https://github.com/Agoric/agoric-sdk/commit/9e19321ea8fed32d445d44169b32f5d94a93d61e))
|
|
31
|
+
* **telemetry:** Extend shutdown logic for slog-sender-pipe and otel-metrics ([7b8ccc8](https://github.com/Agoric/agoric-sdk/commit/7b8ccc82e641e5d11ccc6b8aebe524f75af829fe)), closes [#11175](https://github.com/Agoric/agoric-sdk/issues/11175)
|
|
32
|
+
* **telemetry:** flight recorder flush does sync ([d270202](https://github.com/Agoric/agoric-sdk/commit/d2702028d77c06f3b4de91ca711a3c45c685a477))
|
|
33
|
+
* **telemetry:** flight-recorder check second read size ([bfbacb2](https://github.com/Agoric/agoric-sdk/commit/bfbacb2b9f8de36f8f66b8cba8a88603fb7225e2))
|
|
30
34
|
* **telemetry:** flight-recorder ignores write after shutdown ([3d2bcb3](https://github.com/Agoric/agoric-sdk/commit/3d2bcb3c56ac24a0f991200b223e6af8514dc5b8))
|
|
31
35
|
* **telemetry:** handle new trigger slog events ([d32cb7e](https://github.com/Agoric/agoric-sdk/commit/d32cb7e9f406c25399321dc32e827b5018c38b69))
|
|
32
36
|
* **telemetry:** ingest-slog avoid writing progress file for stdin ([62589ca](https://github.com/Agoric/agoric-sdk/commit/62589ca7b6d4aaa9eb7042f95ec7aec633db27f9))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/telemetry",
|
|
3
|
-
"version": "0.6.3-
|
|
3
|
+
"version": "0.6.3-u21.0.1",
|
|
4
4
|
"description": "Agoric's telemetry implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/Agoric/agoric-sdk",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"test:c8": "c8 --all $C8_OPTIONS ava",
|
|
12
12
|
"test:xs": "exit 0",
|
|
13
13
|
"lint-fix": "yarn lint:eslint --fix",
|
|
14
|
-
"lint": "run-s --continue-on-error lint:*",
|
|
15
|
-
"lint:types": "tsc",
|
|
16
|
-
"lint:eslint": "eslint ."
|
|
14
|
+
"lint": "yarn run -T run-s --continue-on-error 'lint:*'",
|
|
15
|
+
"lint:types": "yarn run -T tsc",
|
|
16
|
+
"lint:eslint": "yarn run -T eslint ."
|
|
17
17
|
},
|
|
18
18
|
"bin": {
|
|
19
19
|
"frcat": "./src/frcat-entrypoint.js"
|
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
"author": "Agoric",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agoric/internal": "
|
|
26
|
-
"@agoric/store": "
|
|
25
|
+
"@agoric/internal": "0.4.0-u21.0.1",
|
|
26
|
+
"@agoric/store": "0.9.3-u21.0.1",
|
|
27
27
|
"@endo/errors": "^1.2.10",
|
|
28
28
|
"@endo/init": "^1.1.9",
|
|
29
29
|
"@endo/marshal": "^1.6.4",
|
|
30
|
+
"@endo/promise-kit": "^1.1.10",
|
|
30
31
|
"@endo/stream": "^1.2.10",
|
|
31
32
|
"@opentelemetry/api": "~1.9.0",
|
|
32
33
|
"@opentelemetry/api-logs": "0.57.1",
|
|
@@ -39,21 +40,21 @@
|
|
|
39
40
|
"@opentelemetry/sdk-trace-base": "~1.30.1",
|
|
40
41
|
"@opentelemetry/semantic-conventions": "~1.28.0",
|
|
41
42
|
"anylogger": "^0.21.0",
|
|
42
|
-
"better-sqlite3": "^
|
|
43
|
+
"better-sqlite3": "^10.1.0",
|
|
43
44
|
"tmp": "^0.2.1"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@endo/lockdown": "^1.0.15",
|
|
47
48
|
"@endo/ses-ava": "^1.2.10",
|
|
48
49
|
"ava": "^5.3.0",
|
|
49
|
-
"c8": "^10.1.
|
|
50
|
+
"c8": "^10.1.3",
|
|
50
51
|
"tmp": "^0.2.1"
|
|
51
52
|
},
|
|
52
53
|
"publishConfig": {
|
|
53
54
|
"access": "public"
|
|
54
55
|
},
|
|
55
56
|
"engines": {
|
|
56
|
-
"node": "^
|
|
57
|
+
"node": "^20.9 || ^22.11"
|
|
57
58
|
},
|
|
58
59
|
"ava": {
|
|
59
60
|
"files": [
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"workerThreads": false
|
|
67
68
|
},
|
|
68
69
|
"typeCoverage": {
|
|
69
|
-
"atLeast": 88.
|
|
70
|
+
"atLeast": 88.83
|
|
70
71
|
},
|
|
71
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "16519b2de1eb2afda2b4ec866f55eadd4bb18223"
|
|
72
73
|
}
|
package/src/flight-recorder.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
/* eslint-env node */
|
|
3
3
|
/// <reference types="ses" />
|
|
4
4
|
|
|
5
|
-
import fs from 'node:fs';
|
|
6
5
|
import fsp from 'node:fs/promises';
|
|
7
6
|
import path from 'node:path';
|
|
8
7
|
import { Fail } from '@endo/errors';
|
|
@@ -80,7 +79,7 @@ const initializeCircularBuffer = async (bufferFile, circularBufferSize) => {
|
|
|
80
79
|
* @param {(record: Uint8Array, firstWriteLength: number, circEnd: bigint) => Promise<void>} writeRecord
|
|
81
80
|
*/
|
|
82
81
|
function makeCircBufMethods(arenaSize, header, readRecord, writeRecord) {
|
|
83
|
-
const readCircBuf = (outbuf, offset = 0) => {
|
|
82
|
+
const readCircBuf = async (outbuf, offset = 0) => {
|
|
84
83
|
offset + outbuf.byteLength <= arenaSize ||
|
|
85
84
|
Fail`Reading past end of circular buffer`;
|
|
86
85
|
|
|
@@ -102,7 +101,7 @@ function makeCircBufMethods(arenaSize, header, readRecord, writeRecord) {
|
|
|
102
101
|
// The data is contiguous, like ---AAABBB---
|
|
103
102
|
return { done: true, value: undefined };
|
|
104
103
|
}
|
|
105
|
-
readRecord(outbuf, readStart, firstReadLength);
|
|
104
|
+
await readRecord(outbuf, readStart, firstReadLength);
|
|
106
105
|
return { done: false, value: outbuf };
|
|
107
106
|
};
|
|
108
107
|
|
|
@@ -146,9 +145,10 @@ function makeCircBufMethods(arenaSize, header, readRecord, writeRecord) {
|
|
|
146
145
|
|
|
147
146
|
// Advance the start pointer until we have space to write the record.
|
|
148
147
|
let overlap = BigInt(record.byteLength) - capacity;
|
|
148
|
+
await null;
|
|
149
149
|
while (overlap > 0n) {
|
|
150
150
|
const startRecordLength = new Uint8Array(RECORD_HEADER_SIZE);
|
|
151
|
-
const { done } = readCircBuf(startRecordLength);
|
|
151
|
+
const { done } = await readCircBuf(startRecordLength);
|
|
152
152
|
if (done) {
|
|
153
153
|
break;
|
|
154
154
|
}
|
|
@@ -224,20 +224,22 @@ export const makeSimpleCircularBuffer = async ({
|
|
|
224
224
|
arenaSize === hdrArenaSize ||
|
|
225
225
|
Fail`${filename} arena size mismatch; wanted ${arenaSize}, got ${hdrArenaSize}`;
|
|
226
226
|
|
|
227
|
-
/** @type {(outbuf: Uint8Array, readStart: number, firstReadLength: number) => void} */
|
|
228
|
-
const readRecord = (outbuf, readStart, firstReadLength) => {
|
|
229
|
-
const bytesRead =
|
|
227
|
+
/** @type {(outbuf: Uint8Array, readStart: number, firstReadLength: number) => Promise<void>} */
|
|
228
|
+
const readRecord = async (outbuf, readStart, firstReadLength) => {
|
|
229
|
+
const { bytesRead } = await file.read(outbuf, {
|
|
230
230
|
length: firstReadLength,
|
|
231
231
|
position: Number(readStart) + I_ARENA_START,
|
|
232
232
|
});
|
|
233
233
|
assert.equal(bytesRead, firstReadLength, 'Too few bytes read');
|
|
234
234
|
|
|
235
235
|
if (bytesRead < outbuf.byteLength) {
|
|
236
|
-
|
|
236
|
+
const length = outbuf.byteLength - firstReadLength;
|
|
237
|
+
const { bytesRead: bytesRead2 } = await file.read(outbuf, {
|
|
237
238
|
offset: firstReadLength,
|
|
238
|
-
length
|
|
239
|
+
length,
|
|
239
240
|
position: I_ARENA_START,
|
|
240
241
|
});
|
|
242
|
+
assert.equal(bytesRead2, length, 'Too few bytes read');
|
|
241
243
|
}
|
|
242
244
|
};
|
|
243
245
|
|
|
@@ -294,6 +296,7 @@ export const makeSlogSenderFromBuffer = ({ fileHandle, writeCircBuf }) => {
|
|
|
294
296
|
return Object.assign(writeJSON, {
|
|
295
297
|
forceFlush: async () => {
|
|
296
298
|
await toWrite;
|
|
299
|
+
await fileHandle.datasync();
|
|
297
300
|
},
|
|
298
301
|
shutdown: async () => {
|
|
299
302
|
const lastWritten = toWrite;
|
package/src/frcat-entrypoint.js
CHANGED
|
@@ -22,7 +22,7 @@ const main = async () => {
|
|
|
22
22
|
let offset = 0;
|
|
23
23
|
for (;;) {
|
|
24
24
|
const lenBuf = new Uint8Array(BigUint64Array.BYTES_PER_ELEMENT);
|
|
25
|
-
const { done } = readCircBuf(lenBuf, offset);
|
|
25
|
+
const { done } = await readCircBuf(lenBuf, offset);
|
|
26
26
|
if (done) {
|
|
27
27
|
break;
|
|
28
28
|
}
|
|
@@ -30,7 +30,7 @@ const main = async () => {
|
|
|
30
30
|
const dv = new DataView(lenBuf.buffer);
|
|
31
31
|
const len = Number(dv.getBigUint64(0));
|
|
32
32
|
|
|
33
|
-
const { done: done2, value: buf } = readCircBuf(
|
|
33
|
+
const { done: done2, value: buf } = await readCircBuf(
|
|
34
34
|
new Uint8Array(len),
|
|
35
35
|
offset,
|
|
36
36
|
);
|
package/src/otel-metrics.js
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
} from '@agoric/internal/src/metrics.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* @import {
|
|
13
|
+
* @import {MetricOptions, ObservableCounter, ObservableUpDownCounter} from '@opentelemetry/api';
|
|
14
|
+
* @import {MeterProvider} from '@opentelemetry/sdk-metrics';
|
|
14
15
|
* @import {TotalMap} from '@agoric/internal';
|
|
15
16
|
*/
|
|
16
17
|
|
|
@@ -22,6 +23,10 @@ export const makeSlogSender = async (opts = /** @type {any} */ ({})) => {
|
|
|
22
23
|
if (!otelMeterName) throw Fail`OTel meter name is required`;
|
|
23
24
|
if (!otelMeterProvider) return;
|
|
24
25
|
|
|
26
|
+
const shutdown = async () => {
|
|
27
|
+
await otelMeterProvider.shutdown();
|
|
28
|
+
};
|
|
29
|
+
|
|
25
30
|
const otelMeter = otelMeterProvider.getMeter(otelMeterName);
|
|
26
31
|
|
|
27
32
|
const processedInboundActionCounter = otelMeter.createCounter(
|
|
@@ -218,6 +223,7 @@ export const makeSlogSender = async (opts = /** @type {any} */ ({})) => {
|
|
|
218
223
|
}
|
|
219
224
|
};
|
|
220
225
|
return Object.assign(slogSender, {
|
|
226
|
+
shutdown,
|
|
221
227
|
usesJsonObject: false,
|
|
222
228
|
});
|
|
223
229
|
};
|
package/src/slog-sender-pipe.js
CHANGED
|
@@ -12,6 +12,7 @@ import { promisify } from 'util';
|
|
|
12
12
|
import anylogger from 'anylogger';
|
|
13
13
|
|
|
14
14
|
import { q, Fail } from '@endo/errors';
|
|
15
|
+
import { makePromiseKit } from '@endo/promise-kit';
|
|
15
16
|
import { makeQueue } from '@endo/stream';
|
|
16
17
|
|
|
17
18
|
import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
|
|
@@ -72,6 +73,16 @@ export const makeSlogSender = async options => {
|
|
|
72
73
|
env,
|
|
73
74
|
});
|
|
74
75
|
// logger.log('done fork');
|
|
76
|
+
|
|
77
|
+
const exitKit = makePromiseKit();
|
|
78
|
+
cp.on('error', error => {
|
|
79
|
+
// An exit event *might* be coming, so wait a tick.
|
|
80
|
+
setImmediate(() => exitKit.resolve({ error }));
|
|
81
|
+
});
|
|
82
|
+
cp.on('exit', (exitCode, signal) => {
|
|
83
|
+
exitKit.resolve({ exitCode, signal });
|
|
84
|
+
});
|
|
85
|
+
|
|
75
86
|
/** @type {(msg: Record<string, unknown> & {type: string}) => Promise<void>} */
|
|
76
87
|
const rawSend = promisify(cp.send.bind(cp));
|
|
77
88
|
const pipeSend = withMutex(rawSend);
|
|
@@ -132,6 +143,7 @@ export const makeSlogSender = async options => {
|
|
|
132
143
|
|
|
133
144
|
await flush();
|
|
134
145
|
cp.disconnect();
|
|
146
|
+
await exitKit.promise;
|
|
135
147
|
};
|
|
136
148
|
registerShutdown(shutdown);
|
|
137
149
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
2
|
import tmp from 'tmp';
|
|
4
3
|
import { test } from './prepare-test-env-ava.js';
|
|
5
4
|
|
|
@@ -13,21 +12,16 @@ const bufferTests = test.macro(
|
|
|
13
12
|
/**
|
|
14
13
|
*
|
|
15
14
|
* @param {*} t
|
|
16
|
-
* @param {{makeBuffer:
|
|
15
|
+
* @param {{makeBuffer: typeof makeSimpleCircularBuffer}} input
|
|
17
16
|
*/
|
|
18
17
|
async (t, input) => {
|
|
19
18
|
const BUFFER_SIZE = 512;
|
|
20
19
|
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
fd,
|
|
24
|
-
removeCallback,
|
|
25
|
-
} = tmp.fileSync({ detachDescriptor: true });
|
|
26
|
-
t.teardown(removeCallback);
|
|
27
|
-
const fileHandle = /** @type {import('fs/promises').FileHandle} */ ({
|
|
28
|
-
close: promisify(fs.close.bind(fs, fd)),
|
|
20
|
+
const { name: tmpFile, removeCallback } = tmp.fileSync({
|
|
21
|
+
discardDescriptor: true,
|
|
29
22
|
});
|
|
30
|
-
|
|
23
|
+
t.teardown(removeCallback);
|
|
24
|
+
const { fileHandle, readCircBuf, writeCircBuf } = await input.makeBuffer({
|
|
31
25
|
circularBufferSize: BUFFER_SIZE,
|
|
32
26
|
circularBufferFilename: tmpFile,
|
|
33
27
|
});
|
|
@@ -55,11 +49,11 @@ const bufferTests = test.macro(
|
|
|
55
49
|
t.is(fs.readFileSync(tmpFile, { encoding: 'utf8' }).length, BUFFER_SIZE);
|
|
56
50
|
|
|
57
51
|
const len0 = new Uint8Array(BigUint64Array.BYTES_PER_ELEMENT);
|
|
58
|
-
const { done: done0 } = readCircBuf(len0);
|
|
52
|
+
const { done: done0 } = await readCircBuf(len0);
|
|
59
53
|
t.false(done0, 'readCircBuf should not be done');
|
|
60
54
|
const dv0 = new DataView(len0.buffer);
|
|
61
55
|
const buf0 = new Uint8Array(Number(dv0.getBigUint64(0)));
|
|
62
|
-
const { done: done0b } = readCircBuf(buf0, len0.byteLength);
|
|
56
|
+
const { done: done0b } = await readCircBuf(buf0, len0.byteLength);
|
|
63
57
|
t.false(done0b, 'readCircBuf should not be done');
|
|
64
58
|
const buf0Str = new TextDecoder().decode(buf0);
|
|
65
59
|
t.is(buf0Str, `\n{"type":"start"}`, `start compare failed`);
|
|
@@ -78,12 +72,12 @@ const bufferTests = test.macro(
|
|
|
78
72
|
let offset = 0;
|
|
79
73
|
const len1 = new Uint8Array(BigUint64Array.BYTES_PER_ELEMENT);
|
|
80
74
|
for (let i = 490; i < last; i += 1) {
|
|
81
|
-
const { done: done1 } = readCircBuf(len1, offset);
|
|
75
|
+
const { done: done1 } = await readCircBuf(len1, offset);
|
|
82
76
|
offset += len1.byteLength;
|
|
83
77
|
t.false(done1, `readCircBuf ${i} should not be done`);
|
|
84
78
|
const dv1 = new DataView(len1.buffer);
|
|
85
79
|
const buf1 = new Uint8Array(Number(dv1.getBigUint64(0)));
|
|
86
|
-
const { done: done1b } = readCircBuf(buf1, offset);
|
|
80
|
+
const { done: done1b } = await readCircBuf(buf1, offset);
|
|
87
81
|
offset += buf1.byteLength;
|
|
88
82
|
t.false(done1b, `readCircBuf ${i} should not be done`);
|
|
89
83
|
const buf1Str = new TextDecoder().decode(buf1);
|
|
@@ -94,7 +88,7 @@ const bufferTests = test.macro(
|
|
|
94
88
|
);
|
|
95
89
|
}
|
|
96
90
|
|
|
97
|
-
const { done: done2 } = readCircBuf(len1, offset);
|
|
91
|
+
const { done: done2 } = await readCircBuf(len1, offset);
|
|
98
92
|
t.assert(done2, `readCircBuf ${last} should be done`);
|
|
99
93
|
|
|
100
94
|
slogSender(null, 'PRE-SERIALIZED');
|