@agoric/telemetry 0.6.3-other-dev-8f8782b.0 → 0.6.3-other-dev-fbe72e7.0.fbe72e7

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/src/otel-trace.js CHANGED
@@ -22,16 +22,26 @@ export const SPAN_EXPORT_DELAY_MS = 1_000;
22
22
  export const makeOtelTracingProvider = opts => {
23
23
  const { env = process.env } = opts || {};
24
24
 
25
+ // https://opentelemetry.io/docs/concepts/signals/
26
+ // https://opentelemetry.io/docs/specs/otel/protocol/exporter/#endpoint-urls-for-otlphttp
27
+ // https://github.com/open-telemetry/opentelemetry-js/blob/experimental/v0.57.1/experimental/packages/exporter-trace-otlp-http/README.md#configuration-options-as-environment-variables
25
28
  const { OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT } =
26
29
  env;
27
30
  if (!OTEL_EXPORTER_OTLP_ENDPOINT && !OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) {
31
+ console.debug(
32
+ 'Not enabling OTLP Traces Exporter; enable with OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=<target URL> or OTEL_EXPORTER_OTLP_ENDPOINT=<target URL prefix>',
33
+ );
28
34
  return undefined;
29
35
  }
30
36
 
31
37
  const resource = new Resource(getResourceAttributes(opts));
32
38
 
33
39
  const exporter = new OTLPTraceExporter();
34
- console.info('Enabling OTLP Traces Exporter to', exporter.getDefaultUrl({}));
40
+ console.info(
41
+ 'Enabling OTLP Traces Exporter to',
42
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||
43
+ `${OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces`,
44
+ );
35
45
 
36
46
  const provider = new BasicTracerProvider({ resource });
37
47
  provider.addSpanProcessor(
@@ -0,0 +1,18 @@
1
+ import { Fail } from '@endo/errors';
2
+
3
+ import { getPrometheusMeterProvider } from './index.js';
4
+ import { makeSlogSender as makeOtelMetricsSender } from './otel-metrics.js';
5
+
6
+ /** @param {import('./index.js').MakeSlogSenderOptions & {otelMeterName?: string}} opts */
7
+ export const makeSlogSender = async (opts = {}) => {
8
+ const { env, otelMeterName, serviceName } = opts;
9
+ if (!otelMeterName) throw Fail`OTel meter name is required`;
10
+ const otelMeterProvider = getPrometheusMeterProvider({
11
+ console,
12
+ env,
13
+ serviceName,
14
+ });
15
+ if (!otelMeterProvider) return;
16
+
17
+ return makeOtelMetricsSender({ ...opts, otelMeterName, otelMeterProvider });
18
+ };
@@ -1,4 +1,32 @@
1
- export const serializeSlogObj = slogObj =>
2
- JSON.stringify(slogObj, (_, arg) =>
3
- typeof arg === 'bigint' ? Number(arg) : arg,
4
- );
1
+ const { hasOwn } = Object;
2
+
3
+ const replacer = (_key, value) => {
4
+ switch (typeof value) {
5
+ case 'object': {
6
+ if (value instanceof Error) {
7
+ // Represent each error as a serialization-friendly
8
+ // { errorType, message, cause?, errors?, stack? } object
9
+ // (itself subject to recursive replacement, particularly in `cause` and
10
+ // `errors`).
11
+ const obj = { errorType: value.name, message: value.message };
12
+ if (hasOwn(value, 'cause')) obj.cause = value.cause;
13
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
+ // @ts-ignore TS2339 property "errors" is only on AggregateError
15
+ if (hasOwn(value, 'errors')) obj.errors = value.errors;
16
+ const stack = value.stack;
17
+ if (stack) obj.stack = stack;
18
+ return obj;
19
+ }
20
+ break;
21
+ }
22
+ case 'bigint':
23
+ // Represent each bigint as a JSON-serializable number, accepting the
24
+ // possible loss of precision.
25
+ return Number(value);
26
+ default:
27
+ break;
28
+ }
29
+ return value;
30
+ };
31
+
32
+ export const serializeSlogObj = slogObj => JSON.stringify(slogObj, replacer);
package/src/slog-file.js CHANGED
@@ -11,7 +11,7 @@ export const makeSlogSender = async ({ env: { SLOGFILE } = {} } = {}) => {
11
11
 
12
12
  const slogSender = (slogObj, jsonObj = serializeSlogObj(slogObj)) => {
13
13
  // eslint-disable-next-line prefer-template
14
- void stream.write(jsonObj + '\n');
14
+ stream.write(jsonObj + '\n').catch(() => {});
15
15
  };
16
16
 
17
17
  return Object.assign(slogSender, {
@@ -1,33 +1,34 @@
1
- /* global process */
1
+ /* eslint-env node */
2
+ /**
3
+ * @file Run as a child process of {@link ./slog-sender-pipe.js} to isolate an
4
+ * aggregate slog sender (@see {@link ./make-slog-sender.js}). Communicates
5
+ * with its parent via Node.js IPC with advanced (structured clone)
6
+ * serialization.
7
+ * https://nodejs.org/docs/latest/api/child_process.html#advanced-serialization
8
+ */
9
+
2
10
  import '@endo/init';
3
11
 
4
- import { makeAggregateError } from '@agoric/internal';
5
12
  import anylogger from 'anylogger';
13
+ import { Fail } from '@endo/errors';
6
14
  import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
7
15
 
8
16
  import { makeSlogSender } from './make-slog-sender.js';
9
17
 
10
18
  const logger = anylogger('slog-sender-pipe-entrypoint');
11
19
 
12
- /** @type {(msg: import('./slog-sender-pipe.js').SlogSenderPipeWaitReplies) => void} */
20
+ /** @type {(msg: import('./slog-sender-pipe.js').PipeAPIReply) => void} */
13
21
  const send = Function.prototype.bind.call(process.send, process);
14
22
 
15
23
  /**
16
- * @typedef {object} InitMessage
17
- * @property {'init'} type
18
- * @property {import('./index.js').MakeSlogSenderOptions} options
19
- */
20
- /**
21
- * @typedef {object} SendMessage
22
- * @property {'send'} type
23
- * @property {object} obj
24
+ * @typedef {{type: 'init', options: import('./index.js').MakeSlogSenderOptions }} InitMessage
25
+ * @typedef {{type: 'flush' }} FlushMessage
26
+ * @typedef {{type: 'send', obj: Record<string, unknown> }} SendMessage
27
+ *
28
+ * @typedef {InitMessage | FlushMessage} PipeAPIResponsefulMessage
29
+ * @typedef {SendMessage} PipeAPIResponselessMessage
30
+ * @typedef {PipeAPIResponsefulMessage | PipeAPIResponselessMessage} PipeAPIMessage
24
31
  */
25
- /**
26
- * @typedef {object} FlushMessage
27
- * @property {'flush'} type
28
- */
29
- /** @typedef {InitMessage | FlushMessage} SlogSenderPipeWaitMessages */
30
- /** @typedef {SlogSenderPipeWaitMessages | SendMessage } SlogSenderPipeMessages */
31
32
 
32
33
  const main = async () => {
33
34
  /** @type {import('./index.js').SlogSender | undefined} */
@@ -45,9 +46,7 @@ const main = async () => {
45
46
 
46
47
  /** @param {import('./index.js').MakeSlogSenderOptions} opts */
47
48
  const init = async ({ env, ...otherOpts } = {}) => {
48
- if (slogSender) {
49
- assert.fail('Already initialized');
50
- }
49
+ !slogSender || Fail`Already initialized`;
51
50
 
52
51
  slogSender = await makeSlogSender({
53
52
  ...otherOpts,
@@ -58,9 +57,7 @@ const main = async () => {
58
57
  };
59
58
 
60
59
  const flush = async () => {
61
- if (!slogSender) {
62
- assert.fail('No sender available');
63
- }
60
+ if (!slogSender) throw Fail`No sender available`;
64
61
 
65
62
  await slogSender.forceFlush?.();
66
63
  };
@@ -75,62 +72,67 @@ const main = async () => {
75
72
  sendErrors.unshift(actualFlushError);
76
73
  }
77
74
 
78
- return makeAggregateError(sendErrors.splice(0));
75
+ return AggregateError(sendErrors.splice(0));
79
76
  };
80
77
 
81
- process.on(
82
- 'message',
83
- /** @param {SlogSenderPipeMessages} msg */ msg => {
84
- if (!msg || typeof msg !== 'object') {
85
- logger.warn('received invalid message', msg);
86
- return;
87
- }
78
+ /** @param {PipeAPIMessage} msg */
79
+ const onMessage = msg => {
80
+ if (!msg || typeof msg !== 'object') {
81
+ logger.warn('Received invalid message', msg);
82
+ return;
83
+ }
88
84
 
89
- switch (msg.type) {
90
- case 'init': {
91
- void init(msg.options).then(
92
- hasSender => {
93
- send({ type: 'initReply', hasSender });
94
- },
95
- error => {
96
- send({ type: 'initReply', hasSender: false, error });
97
- },
98
- );
99
- break;
100
- }
101
- case 'flush': {
102
- void flush().then(
103
- () => {
104
- send({ type: 'flushReply', error: generateFlushError() });
105
- },
106
- error => {
107
- send({ type: 'flushReply', error: generateFlushError(error) });
108
- },
109
- );
110
- break;
111
- }
112
- case 'send': {
113
- if (!slogSender) {
114
- logger.warn('received send with no sender available');
115
- } else {
116
- try {
117
- slogSender(msg.obj);
118
- } catch (e) {
119
- sendErrors.push(e);
120
- }
85
+ switch (msg.type) {
86
+ case 'init': {
87
+ void init(msg.options).then(
88
+ hasSender => {
89
+ send({ type: 'initReply', hasSender });
90
+ },
91
+ error => {
92
+ send({ type: 'initReply', hasSender: false, error });
93
+ },
94
+ );
95
+ break;
96
+ }
97
+ case 'flush': {
98
+ void flush().then(
99
+ () => {
100
+ send({ type: 'flushReply', error: generateFlushError() });
101
+ },
102
+ error => {
103
+ send({ type: 'flushReply', error: generateFlushError(error) });
104
+ },
105
+ );
106
+ break;
107
+ }
108
+ case 'send': {
109
+ if (!slogSender) {
110
+ logger.warn('Received send with no sender available');
111
+ } else {
112
+ try {
113
+ slogSender(harden(msg.obj));
114
+ } catch (e) {
115
+ sendErrors.push(e);
121
116
  }
122
- break;
123
- }
124
- default: {
125
- // @ts-expect-error exhaustive type check
126
- logger.warn('received unknown message type', msg.type);
127
117
  }
118
+ break;
119
+ }
120
+ default: {
121
+ // @ts-expect-error exhaustive type check
122
+ logger.warn('Received unknown message type', msg.type);
128
123
  }
129
- },
130
- );
124
+ }
125
+ };
126
+ process.on('message', onMessage);
131
127
  };
132
128
 
133
- main().catch(e => {
134
- logger.error(e);
135
- process.exitCode = 1;
136
- });
129
+ process.exitCode = 1;
130
+ main().then(
131
+ () => {
132
+ process.exitCode = 0;
133
+ },
134
+ err => {
135
+ logger.error('Failed with', err);
136
+ process.exit(process.exitCode || 1);
137
+ },
138
+ );
@@ -1,16 +1,28 @@
1
+ /**
2
+ * @file Export a `makeSlogSender` that spawns a
3
+ * {@link ./slog-sender-pipe-entrypoint.js} child process to which it forwards
4
+ * all slog entries via Node.js IPC with advanced (structured clone)
5
+ * serialization.
6
+ * https://nodejs.org/docs/latest/api/child_process.html#advanced-serialization
7
+ */
8
+
1
9
  import { fork } from 'child_process';
2
10
  import path from 'path';
11
+ import { promisify } from 'util';
3
12
  import anylogger from 'anylogger';
4
13
 
14
+ import { q, Fail } from '@endo/errors';
15
+ import { makePromiseKit } from '@endo/promise-kit';
5
16
  import { makeQueue } from '@endo/stream';
6
17
 
7
18
  import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
8
19
 
9
- const filename = new URL(import.meta.url).pathname;
10
- const dirname = path.dirname(filename);
20
+ const dirname = path.dirname(new URL(import.meta.url).pathname);
11
21
 
12
22
  const logger = anylogger('slog-sender-pipe');
13
23
 
24
+ const sink = () => {};
25
+
14
26
  /**
15
27
  * @template {any[]} T
16
28
  * @template R
@@ -24,168 +36,131 @@ const withMutex = operation => {
24
36
  return async (...args) => {
25
37
  await mutex.get();
26
38
  const result = operation(...args);
27
- mutex.put(
28
- result.then(
29
- () => {},
30
- () => {},
31
- ),
32
- );
39
+ mutex.put(result.then(sink, sink));
33
40
  return result;
34
41
  };
35
42
  };
36
43
 
37
44
  /**
38
- * @typedef {object} SlogSenderInitReply
39
- * @property {'initReply'} type
40
- * @property {boolean} hasSender
41
- * @property {Error} [error]
45
+ * @template [P=unknown]
46
+ * @typedef {{ type: string, error?: Error } & P} PipeReply
42
47
  */
48
+
43
49
  /**
44
- * @typedef {object} SlogSenderFlushReply
45
- * @property {'flushReply'} type
46
- * @property {Error} [error]
50
+ * @typedef {{
51
+ * init: {
52
+ * message: import('./slog-sender-pipe-entrypoint.js').InitMessage;
53
+ * reply: PipeReply<{ hasSender: boolean }>;
54
+ * };
55
+ * flush: {
56
+ * message: import('./slog-sender-pipe-entrypoint.js').FlushMessage;
57
+ * reply: PipeReply<{}>;
58
+ * };
59
+ * }} SlogSenderPipeAPI
60
+ *
61
+ * @typedef {keyof SlogSenderPipeAPI} PipeAPICommand
62
+ * @typedef {SlogSenderPipeAPI[PipeAPICommand]["reply"]} PipeAPIReply
47
63
  */
48
- /** @typedef {SlogSenderInitReply | SlogSenderFlushReply} SlogSenderPipeWaitReplies */
49
64
 
50
- /** @param {import('.').MakeSlogSenderOptions} opts */
51
- export const makeSlogSender = async opts => {
65
+ /** @param {import('.').MakeSlogSenderOptions} options */
66
+ export const makeSlogSender = async options => {
67
+ const { env = {} } = options;
52
68
  const { registerShutdown } = makeShutdown();
69
+
53
70
  const cp = fork(path.join(dirname, 'slog-sender-pipe-entrypoint.js'), [], {
54
- stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
71
+ stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
55
72
  serialization: 'advanced',
73
+ env,
56
74
  });
57
75
  // logger.log('done fork');
58
76
 
59
- const pipeSend = withMutex(
60
- /**
61
- * @template {{type: string}} T
62
- * @param {T} msg
63
- */
64
- msg =>
65
- /** @type {Promise<void>} */ (
66
- new Promise((resolve, reject) => {
67
- cp.send(msg, err => {
68
- if (err) {
69
- reject(err);
70
- } else {
71
- resolve();
72
- }
73
- });
74
- })
75
- ),
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
+
86
+ /** @type {(msg: Record<string, unknown> & {type: string}) => Promise<void>} */
87
+ const rawSend = promisify(cp.send.bind(cp));
88
+ const pipeSend = withMutex(rawSend);
77
89
 
78
- /**
79
- * @typedef {{
80
- * init: {
81
- * message: import('./slog-sender-pipe-entrypoint').InitMessage;
82
- * reply: SlogSenderInitReply;
83
- * };
84
- * flush: {
85
- * message: import('./slog-sender-pipe-entrypoint').FlushMessage;
86
- * reply: SlogSenderFlushReply;
87
- * };
88
- * }} SlogSenderWaitMessagesAndReplies
89
- */
90
-
91
- /** @typedef {keyof SlogSenderWaitMessagesAndReplies} SendWaitCommands */
92
- /**
93
- * @template {SlogSenderPipeWaitReplies} T
94
- * @typedef {Omit<T, 'type' | 'error'>} ReplyPayload
95
- */
96
-
97
- /** @type {import('@endo/stream').AsyncQueue<SlogSenderPipeWaitReplies>} */
90
+ /** @type {import('@endo/stream').AsyncQueue<PipeAPIReply>} */
98
91
  const sendWaitQueue = makeQueue();
99
- /** @type {SendWaitCommands | undefined} */
92
+ /** @type {PipeAPICommand | undefined} */
100
93
  let sendWaitType;
101
94
 
102
95
  const sendWaitReply = withMutex(
103
96
  /**
104
- * @template {SendWaitCommands} T
97
+ * @template {PipeAPICommand} T
105
98
  * @param {T} type
106
- * @param {Omit<SlogSenderWaitMessagesAndReplies[T]["message"], 'type'>} payload
107
- * @returns {Promise<ReplyPayload<SlogSenderWaitMessagesAndReplies[T]["reply"]>>}
99
+ * @param {Omit<SlogSenderPipeAPI[T]["message"], 'type'>} payload
100
+ * @returns {Promise<Omit<SlogSenderPipeAPI[T]["reply"], keyof PipeReply>>}
108
101
  */
109
102
  async (type, payload) => {
110
- !sendWaitType || assert.fail('Invalid mutex state');
103
+ !sendWaitType || Fail`Invalid mutex state`;
111
104
 
112
105
  const msg = { ...payload, type };
113
106
 
114
107
  sendWaitType = type;
115
- return pipeSend(msg)
116
- .then(async () => sendWaitQueue.get())
117
- .then(
118
- /** @param {SlogSenderWaitMessagesAndReplies[T]["reply"]} reply */ ({
119
- type: replyType,
120
- error,
121
- ...rest
122
- }) => {
123
- replyType === `${type}Reply` ||
124
- assert.fail(`Unexpected reply ${replyType}`);
125
- if (error) {
126
- throw error;
127
- }
128
- return rest;
129
- },
130
- )
131
- .finally(() => {
132
- sendWaitType = undefined;
133
- });
134
- },
135
- );
136
-
137
- cp.on(
138
- 'message',
139
- /** @param { SlogSenderPipeWaitReplies } msg */
140
- msg => {
141
- // logger.log('received', msg);
142
- if (
143
- !msg ||
144
- typeof msg !== 'object' ||
145
- msg.type !== `${sendWaitType}Reply`
146
- ) {
147
- logger.warn('Received unexpected message', msg);
148
- return;
108
+ await null;
109
+ try {
110
+ await pipeSend(msg);
111
+ /** @type {SlogSenderPipeAPI[T]["reply"]} */
112
+ const reply = await sendWaitQueue.get();
113
+ const { type: replyType, error, ...rest } = reply;
114
+ replyType === `${type}Reply` ||
115
+ Fail`Unexpected reply type ${q(replyType)}`;
116
+ if (error) throw error;
117
+ return rest;
118
+ } finally {
119
+ sendWaitType = undefined;
149
120
  }
150
-
151
- sendWaitQueue.put(msg);
152
121
  },
153
122
  );
154
123
 
155
- const flush = async () => sendWaitReply('flush', {});
156
- /** @param {import('./index.js').MakeSlogSenderOptions} options */
157
- const init = async options => sendWaitReply('init', { options });
124
+ /** @param {PipeReply} msg */
125
+ const onMessage = msg => {
126
+ // logger.log('received', msg);
127
+ if (!msg || msg.type !== `${sendWaitType}Reply`) {
128
+ logger.warn('Received unexpected message', msg);
129
+ return;
130
+ }
131
+
132
+ sendWaitQueue.put(msg);
133
+ };
134
+ cp.on('message', onMessage);
158
135
 
159
- const send = obj => {
160
- void pipeSend({ type: 'send', obj }).catch(() => {});
136
+ const flush = async () => {
137
+ await sendWaitReply('flush', {});
161
138
  };
162
139
 
163
140
  const shutdown = async () => {
164
141
  // logger.log('shutdown');
165
- if (!cp.connected) {
166
- return;
167
- }
142
+ if (!cp.connected) return;
168
143
 
169
144
  await flush();
170
145
  cp.disconnect();
146
+ await exitKit.promise;
171
147
  };
172
148
  registerShutdown(shutdown);
173
149
 
174
- const { hasSender } = await init(opts).catch(err => {
150
+ const { hasSender } = await sendWaitReply('init', { options }).catch(err => {
175
151
  cp.disconnect();
176
152
  throw err;
177
153
  });
178
-
179
154
  if (!hasSender) {
180
155
  cp.disconnect();
181
156
  return undefined;
182
157
  }
183
158
 
184
- const slogSender = send;
159
+ const slogSender = obj => {
160
+ void pipeSend({ type: 'send', obj }).catch(sink);
161
+ };
185
162
  return Object.assign(slogSender, {
186
- forceFlush: async () => {
187
- await flush();
188
- },
163
+ forceFlush: flush,
189
164
  shutdown,
190
165
  usesJsonObject: false,
191
166
  });
@@ -1,7 +1,7 @@
1
1
  import otel, { SpanStatusCode } from '@opentelemetry/api';
2
2
 
3
+ import { Fail, q } from '@endo/errors';
3
4
  import { makeMarshal, Remotable } from '@endo/marshal';
4
- import { Fail, q } from '@agoric/assert';
5
5
 
6
6
  import { makeLegacyMap } from '@agoric/store';
7
7
  import {
@@ -14,11 +14,8 @@ import {
14
14
 
15
15
  // diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.VERBOSE);
16
16
 
17
- /** @typedef {import('@opentelemetry/api').Span} Span */
18
- /** @typedef {import('@opentelemetry/api').Link} SpanLink */
19
- /** @typedef {import('@opentelemetry/api').SpanContext} SpanContext */
20
- /** @typedef {import('@opentelemetry/api').SpanOptions} SpanOptions */
21
- /** @typedef {import('@opentelemetry/api').SpanAttributes} SpanAttributes */
17
+ /** @import {Span, Link as SpanLink} from '@opentelemetry/api' */
18
+ /** @import {SpanContext, SpanOptions} from '@opentelemetry/api' */
22
19
 
23
20
  const { assign } = Object;
24
21
 
@@ -54,9 +51,9 @@ const serializeInto = (value, prefix, target = {}, depth = 3) => {
54
51
  } else {
55
52
  const proto = Object.getPrototypeOf(value);
56
53
  if (proto == null || proto === Object.prototype) {
57
- Object.entries(value).forEach(([key, nested]) =>
58
- serializeInto(nested, `${prefix}.${key}`, target, depth),
59
- );
54
+ for (const [key, nested] of Object.entries(value)) {
55
+ serializeInto(nested, `${prefix}.${key}`, target, depth);
56
+ }
60
57
  return target;
61
58
  }
62
59
  }
@@ -142,7 +139,10 @@ export const makeSlogToOtelKit = (tracer, overrideAttrs = {}) => {
142
139
  serializeBodyFormat: 'smallcaps',
143
140
  });
144
141
 
145
- /** @param {import('@agoric/swingset-vat').SwingSetCapData} data */
142
+ /**
143
+ * @param {import('@agoric/swingset-vat').SwingSetCapData} data
144
+ * @returns {any}
145
+ */
146
146
  const unserialize = data => {
147
147
  try {
148
148
  const body = rawUnserialize(data);
@@ -915,7 +915,7 @@ export const makeSlogToOtelKit = (tracer, overrideAttrs = {}) => {
915
915
  break;
916
916
  }
917
917
  case 'cosmic-swingset-upgrade-finish': {
918
- spans.pop(['slogAttrs.blockHeight', slogAttrs.blockHeight]);
918
+ spans.pop(['upgrade', slogAttrs.blockHeight]);
919
919
  dbTransactionManager.end();
920
920
  break;
921
921
  }
@@ -971,6 +971,21 @@ export const makeSlogToOtelKit = (tracer, overrideAttrs = {}) => {
971
971
  spans.pop('bridge-inbound');
972
972
  break;
973
973
  }
974
+ case 'cosmic-swingset-timer-poll': {
975
+ spans.push(['timer-poll', slogAttrs.blockTime]);
976
+ spans.pop('timer-poll');
977
+ break;
978
+ }
979
+ case 'cosmic-swingset-inject-kernel-upgrade-events': {
980
+ spans.push('kernel-upgrade-events');
981
+ spans.pop('kernel-upgrade-events');
982
+ break;
983
+ }
984
+ case 'cosmic-swingset-install-bundle': {
985
+ spans.push(['install-bundle', slogAttrs.endoZipBase64Sha512]);
986
+ spans.pop('install-bundle');
987
+ break;
988
+ }
974
989
  case 'cosmic-swingset-end-block-start': {
975
990
  // Add `end-block` as an event onto the encompassing `block` span
976
991
  spans.top()?.addEvent('end-block-action', cleanAttrs(slogAttrs), now);