@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 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-u20.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/telemetry@0.6.2...@agoric/telemetry@0.6.3-u20.0) (2025-04-16)
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-u20.0",
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": "^0.4.0-u20.0",
26
- "@agoric/store": "^0.9.3-u20.0",
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": "^9.1.1",
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.2",
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": "^18.12 || ^20.9"
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.87
70
+ "atLeast": 88.83
70
71
  },
71
- "gitHead": "8e4207fa19dabf76c1f91f8779b5b5b93570ecea"
72
+ "gitHead": "16519b2de1eb2afda2b4ec866f55eadd4bb18223"
72
73
  }
@@ -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 = fs.readSync(file.fd, outbuf, {
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
- fs.readSync(file.fd, outbuf, {
236
+ const length = outbuf.byteLength - firstReadLength;
237
+ const { bytesRead: bytesRead2 } = await file.read(outbuf, {
237
238
  offset: firstReadLength,
238
- length: outbuf.byteLength - firstReadLength,
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;
@@ -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
  );
@@ -10,7 +10,8 @@ import {
10
10
  } from '@agoric/internal/src/metrics.js';
11
11
 
12
12
  /**
13
- * @import {MeterProvider, MetricOptions, ObservableCounter, ObservableUpDownCounter} from '@opentelemetry/api';
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
  };
@@ -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: Function}} input
15
+ * @param {{makeBuffer: typeof makeSimpleCircularBuffer}} input
17
16
  */
18
17
  async (t, input) => {
19
18
  const BUFFER_SIZE = 512;
20
19
 
21
- const {
22
- name: tmpFile,
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
- const { readCircBuf, writeCircBuf } = await input.makeBuffer({
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');