@aztec/telemetry-client 0.0.0-test.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.
Files changed (93) hide show
  1. package/dest/attributes.d.ts +99 -0
  2. package/dest/attributes.d.ts.map +1 -0
  3. package/dest/attributes.js +67 -0
  4. package/dest/bench.d.ts +29 -0
  5. package/dest/bench.d.ts.map +1 -0
  6. package/dest/bench.js +98 -0
  7. package/dest/config.d.ts +12 -0
  8. package/dest/config.d.ts.map +1 -0
  9. package/dest/config.js +39 -0
  10. package/dest/event_loop_monitor.d.ts +18 -0
  11. package/dest/event_loop_monitor.d.ts.map +1 -0
  12. package/dest/event_loop_monitor.js +93 -0
  13. package/dest/index.d.ts +10 -0
  14. package/dest/index.d.ts.map +1 -0
  15. package/dest/index.js +9 -0
  16. package/dest/lmdb_metrics.d.ts +16 -0
  17. package/dest/lmdb_metrics.d.ts.map +1 -0
  18. package/dest/lmdb_metrics.js +42 -0
  19. package/dest/metrics.d.ts +129 -0
  20. package/dest/metrics.d.ts.map +1 -0
  21. package/dest/metrics.js +126 -0
  22. package/dest/noop.d.ts +14 -0
  23. package/dest/noop.d.ts.map +1 -0
  24. package/dest/noop.js +71 -0
  25. package/dest/otel.d.ts +32 -0
  26. package/dest/otel.d.ts.map +1 -0
  27. package/dest/otel.js +319 -0
  28. package/dest/otel_filter_metric_exporter.d.ts +12 -0
  29. package/dest/otel_filter_metric_exporter.d.ts.map +1 -0
  30. package/dest/otel_filter_metric_exporter.js +33 -0
  31. package/dest/otel_logger_provider.d.ts +4 -0
  32. package/dest/otel_logger_provider.d.ts.map +1 -0
  33. package/dest/otel_logger_provider.js +25 -0
  34. package/dest/otel_propagation.d.ts +3 -0
  35. package/dest/otel_propagation.d.ts.map +1 -0
  36. package/dest/otel_propagation.js +44 -0
  37. package/dest/otel_resource.d.ts +3 -0
  38. package/dest/otel_resource.d.ts.map +1 -0
  39. package/dest/otel_resource.js +12 -0
  40. package/dest/prom_otel_adapter.d.ts +127 -0
  41. package/dest/prom_otel_adapter.d.ts.map +1 -0
  42. package/dest/prom_otel_adapter.js +183 -0
  43. package/dest/start.d.ts +6 -0
  44. package/dest/start.d.ts.map +1 -0
  45. package/dest/start.js +24 -0
  46. package/dest/telemetry.d.ts +118 -0
  47. package/dest/telemetry.d.ts.map +1 -0
  48. package/dest/telemetry.js +116 -0
  49. package/dest/vendor/attributes.d.ts +5 -0
  50. package/dest/vendor/attributes.d.ts.map +1 -0
  51. package/dest/vendor/attributes.js +5 -0
  52. package/dest/vendor/otel-pino-stream.d.ts +41 -0
  53. package/dest/vendor/otel-pino-stream.d.ts.map +1 -0
  54. package/dest/vendor/otel-pino-stream.js +229 -0
  55. package/dest/with_tracer.d.ts +33 -0
  56. package/dest/with_tracer.d.ts.map +1 -0
  57. package/dest/with_tracer.js +32 -0
  58. package/dest/wrappers/fetch.d.ts +16 -0
  59. package/dest/wrappers/fetch.d.ts.map +1 -0
  60. package/dest/wrappers/fetch.js +39 -0
  61. package/dest/wrappers/index.d.ts +4 -0
  62. package/dest/wrappers/index.d.ts.map +1 -0
  63. package/dest/wrappers/index.js +3 -0
  64. package/dest/wrappers/json_rpc_server.d.ts +4 -0
  65. package/dest/wrappers/json_rpc_server.d.ts.map +1 -0
  66. package/dest/wrappers/json_rpc_server.js +11 -0
  67. package/dest/wrappers/l2_block_stream.d.ts +15 -0
  68. package/dest/wrappers/l2_block_stream.d.ts.map +1 -0
  69. package/dest/wrappers/l2_block_stream.js +26 -0
  70. package/package.json +89 -0
  71. package/src/attributes.ts +115 -0
  72. package/src/bench.ts +147 -0
  73. package/src/config.ts +56 -0
  74. package/src/event_loop_monitor.ts +119 -0
  75. package/src/index.ts +9 -0
  76. package/src/lmdb_metrics.ts +45 -0
  77. package/src/metrics.ts +153 -0
  78. package/src/noop.ts +91 -0
  79. package/src/otel.ts +286 -0
  80. package/src/otel_filter_metric_exporter.ts +38 -0
  81. package/src/otel_logger_provider.ts +31 -0
  82. package/src/otel_propagation.ts +50 -0
  83. package/src/otel_resource.ts +16 -0
  84. package/src/prom_otel_adapter.ts +326 -0
  85. package/src/start.ts +33 -0
  86. package/src/telemetry.ts +267 -0
  87. package/src/vendor/attributes.ts +5 -0
  88. package/src/vendor/otel-pino-stream.ts +282 -0
  89. package/src/with_tracer.ts +35 -0
  90. package/src/wrappers/fetch.ts +52 -0
  91. package/src/wrappers/index.ts +3 -0
  92. package/src/wrappers/json_rpc_server.ts +15 -0
  93. package/src/wrappers/l2_block_stream.ts +37 -0
@@ -0,0 +1,229 @@
1
+ /*
2
+ * Adapted from open-telemetry/opentelemetry-js-contrib
3
+ * All changes are prefixed with [aztec] to make them easy to identify
4
+ *
5
+ * Copyright The OpenTelemetry Authors
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * https://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */ import { SeverityNumber, logs } from '@opentelemetry/api-logs';
19
+ import { millisToHrTime } from '@opentelemetry/core';
20
+ import { Writable } from 'stream';
21
+ import { registerOtelLoggerProvider } from '../otel_logger_provider.js';
22
+ import { getOtelResource } from '../otel_resource.js';
23
+ /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable camelcase */ // This block is a copy (modulo code style and TypeScript types) of the Pino
24
+ // code that defines log level value and names. This file is part of
25
+ // *instrumenting* Pino, so we want to avoid a dependency on the library.
26
+ const DEFAULT_LEVELS = {
27
+ trace: 10,
28
+ debug: 20,
29
+ info: 30,
30
+ warn: 40,
31
+ error: 50,
32
+ fatal: 60
33
+ };
34
+ const OTEL_SEV_NUM_FROM_PINO_LEVEL = {
35
+ [DEFAULT_LEVELS.trace]: SeverityNumber.TRACE,
36
+ [DEFAULT_LEVELS.debug]: SeverityNumber.DEBUG,
37
+ [DEFAULT_LEVELS.info]: SeverityNumber.INFO,
38
+ [DEFAULT_LEVELS.warn]: SeverityNumber.WARN,
39
+ [DEFAULT_LEVELS.error]: SeverityNumber.ERROR,
40
+ [DEFAULT_LEVELS.fatal]: SeverityNumber.FATAL
41
+ };
42
+ const EXTRA_SEV_NUMS = [
43
+ SeverityNumber.TRACE2,
44
+ SeverityNumber.TRACE3,
45
+ SeverityNumber.TRACE4,
46
+ SeverityNumber.DEBUG2,
47
+ SeverityNumber.DEBUG3,
48
+ SeverityNumber.DEBUG4,
49
+ SeverityNumber.INFO2,
50
+ SeverityNumber.INFO3,
51
+ SeverityNumber.INFO4,
52
+ SeverityNumber.WARN2,
53
+ SeverityNumber.WARN3,
54
+ SeverityNumber.WARN4,
55
+ SeverityNumber.ERROR2,
56
+ SeverityNumber.ERROR3,
57
+ SeverityNumber.ERROR4,
58
+ SeverityNumber.FATAL2,
59
+ SeverityNumber.FATAL3,
60
+ SeverityNumber.FATAL4
61
+ ];
62
+ function severityNumberFromPinoLevel(lvl) {
63
+ // Fast common case: one of the known levels
64
+ const sev = OTEL_SEV_NUM_FROM_PINO_LEVEL[lvl];
65
+ if (sev !== undefined) {
66
+ return sev;
67
+ }
68
+ // Otherwise, scale the Pino level range -- 10 (trace) to 70 (fatal+10)
69
+ // -- onto the extra OTel severity numbers (TRACE2, TRACE3, ..., FATAL4).
70
+ // Values below trace (10) map to SeverityNumber.TRACE2, which may be
71
+ // considered a bit weird, but it means the unnumbered levels are always
72
+ // just for exactly matching values.
73
+ const relativeLevelWeight = (lvl - 10) / (70 - 10);
74
+ const otelSevIdx = Math.floor(relativeLevelWeight * EXTRA_SEV_NUMS.length);
75
+ const cappedOTelIdx = Math.min(EXTRA_SEV_NUMS.length - 1, Math.max(0, otelSevIdx));
76
+ const otelSevValue = EXTRA_SEV_NUMS[cappedOTelIdx];
77
+ return otelSevValue;
78
+ }
79
+ // [aztec] Custom function to map Aztec logging levels to OpenTelemetry severity numbers
80
+ function severityNumberFromAztecPinoLevel(lvl) {
81
+ return OTEL_SEV_NUM_FROM_PINO_LEVEL[lvl] ?? /* verbose */ (lvl === 25 ? SeverityNumber.DEBUG3 : undefined) ?? severityNumberFromPinoLevel(lvl);
82
+ }
83
+ /**
84
+ * Return a function that knows how to convert the "time" field value on a
85
+ * Pino log record to an OTel LogRecord timestamp value.
86
+ *
87
+ * How to convert the serialized "time" on a Pino log record
88
+ * depends on the Logger's `Symbol(pino.time)` prop, configurable
89
+ * via https://getpino.io/#/docs/api?id=timestamp-boolean-function
90
+ *
91
+ * For example:
92
+ * const logger = pino({timestamp: pino.stdTimeFunctions.isoTime})
93
+ * results in log record entries of the form:
94
+ * ,"time":"2024-05-17T22:03:25.969Z"
95
+ * `otelTimestampFromTime` will be given the value of the "time" field:
96
+ * "2024-05-17T22:03:25.969Z"
97
+ * which should be parsed to a number of milliseconds since the epoch.
98
+ */ export function getTimeConverter(pinoLogger, pinoMod) {
99
+ const stdTimeFns = pinoMod.stdTimeFunctions;
100
+ const loggerTimeFn = pinoLogger[pinoMod.symbols.timeSym];
101
+ if (loggerTimeFn === stdTimeFns.epochTime) {
102
+ return (time)=>time;
103
+ } else if (loggerTimeFn === stdTimeFns.unixTime) {
104
+ return (time)=>time * 1e3;
105
+ } else if (loggerTimeFn === stdTimeFns.isoTime) {
106
+ return (time)=>new Date(time).getTime();
107
+ } else if (loggerTimeFn === stdTimeFns.nullTime) {
108
+ return ()=>Date.now();
109
+ } else {
110
+ // The logger has a custom time function. Don't guess.
111
+ return ()=>NaN;
112
+ }
113
+ }
114
+ /**
115
+ * A Pino stream for sending records to the OpenTelemetry Logs API.
116
+ *
117
+ * - This stream emits an 'unknown' event on an unprocessable pino record.
118
+ * The event arguments are: `logLine: string`, `err: string | Error`.
119
+ */ export class OTelPinoStream extends Writable {
120
+ _otelLogger;
121
+ _messageKey;
122
+ _levels;
123
+ _otelTimestampFromTime;
124
+ constructor(options){
125
+ super();
126
+ // Note: A PINO_CONFIG event was added to pino (2024-04-04) to send config
127
+ // to transports. Eventually OTelPinoStream might be able to use this
128
+ // for auto-configuration in newer pino versions. The event currently does
129
+ // not include the `timeSym` value that is needed here, however.
130
+ this._messageKey = options.messageKey ?? 'msg';
131
+ this._levels = options.levels;
132
+ // [aztec] The following will break if we set up a custom time function in our logger
133
+ this._otelTimestampFromTime = options.otelTimestampFromTime ?? ((time)=>time);
134
+ // Cannot use `instrumentation.logger` until have delegating LoggerProvider:
135
+ // https://github.com/open-telemetry/opentelemetry-js/issues/4399
136
+ // [aztec] Use the name of this package
137
+ this._otelLogger = logs.getLogger('@aztec/telemetry-client/otel-pino-stream', '0.1.0');
138
+ }
139
+ _write(s, _encoding, callback) {
140
+ try {
141
+ /* istanbul ignore if */ if (!s) {
142
+ return;
143
+ }
144
+ // Parse, and handle edge cases similar to how `pino-abtract-transport` does:
145
+ // https://github.com/pinojs/pino-abstract-transport/blob/v1.2.0/index.js#L28-L45
146
+ // - Emitting an 'unknown' event on parse error mimicks pino-abstract-transport.
147
+ let recObj;
148
+ try {
149
+ recObj = JSON.parse(s);
150
+ } catch (parseErr) {
151
+ // Invalid JSON suggests a bug in Pino, or a logger configuration bug
152
+ // (a bogus `options.timestamp` or serializer).
153
+ this.emit('unknown', s.toString(), parseErr);
154
+ callback();
155
+ return;
156
+ }
157
+ /* istanbul ignore if */ if (recObj === null) {
158
+ this.emit('unknown', s.toString(), 'Null value ignored');
159
+ callback();
160
+ return;
161
+ }
162
+ /* istanbul ignore if */ if (typeof recObj !== 'object') {
163
+ recObj = {
164
+ data: recObj
165
+ };
166
+ }
167
+ const { time, [this._messageKey]: body, level, // The typical Pino `hostname` and `pid` fields are removed because they
168
+ // are redundant with the OpenTelemetry `host.name` and `process.pid`
169
+ // Resource attributes, respectively. This code cannot change the
170
+ // LoggerProvider's `resource`, so getting the OpenTelemetry equivalents
171
+ // depends on the user using the OpenTelemetry HostDetector and
172
+ // ProcessDetector.
173
+ // https://getpino.io/#/docs/api?id=opt-base
174
+ hostname, pid, // The `trace_id` et al fields that may have been added by the
175
+ // "log correlation" feature are stripped, because they are redundant.
176
+ // trace_id, // eslint-disable-line @typescript-eslint/no-unused-vars
177
+ // span_id, // eslint-disable-line @typescript-eslint/no-unused-vars
178
+ // trace_flags, // eslint-disable-line @typescript-eslint/no-unused-vars
179
+ // [aztec] They are not redundant, we depend on them for correlation.
180
+ // The instrumentation package seems to be adding these fields via a custom hook.
181
+ // We push them from the logger module in foundation, so we don't want to clear them here.
182
+ ...attributes } = recObj;
183
+ let timestamp = this._otelTimestampFromTime(time);
184
+ if (isNaN(timestamp)) {
185
+ attributes['time'] = time; // save the unexpected "time" field to attributes
186
+ timestamp = Date.now();
187
+ }
188
+ // This avoids a possible subtle bug when a Pino logger uses
189
+ // `time: pino.stdTimeFunctions.unixTime` and logs in the first half-second
190
+ // since process start. The rounding involved results in:
191
+ // timestamp < performance.timeOrigin
192
+ // If that is passed to Logger.emit() it will be misinterpreted by
193
+ // `timeInputToHrTime` as a `performance.now()` value.
194
+ const timestampHrTime = millisToHrTime(timestamp);
195
+ // Prefer using `stream.lastLevel`, because `recObj.level` can be customized
196
+ // to anything via `formatters.level`
197
+ // (https://getpino.io/#/docs/api?id=formatters-object).
198
+ // const lastLevel = (this as any).lastLevel;
199
+ // [aztec] We do not prefer stream.lastLevel since it's undefined here, as we are running
200
+ // on a worker thread, so we use recObj.level because we know that we won't customize it.
201
+ const lastLevel = recObj.level;
202
+ const otelRec = {
203
+ timestamp: timestampHrTime,
204
+ observedTimestamp: timestampHrTime,
205
+ severityNumber: severityNumberFromAztecPinoLevel(lastLevel),
206
+ severityText: this._levels.labels[lastLevel],
207
+ body,
208
+ attributes
209
+ };
210
+ this._otelLogger.emit(otelRec);
211
+ } catch (err) {
212
+ // [aztec] Log errors to stderr
213
+ // eslint-disable-next-line no-console
214
+ console.error(`Error in OTelPinoStream: ${err}`);
215
+ }
216
+ callback();
217
+ }
218
+ }
219
+ // [aztec] Default export that loads the resource information and creates a new otel pino stream.
220
+ // Invoked by pino when creating a transport in a worker thread out of this stream.
221
+ // Note that the original open-telemetry/opentelemetry-js-contrib was set up to run on the main
222
+ // nodejs loop, as opposed to in a worker as pino recommends.
223
+ export default function(options) {
224
+ const url = process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
225
+ const resource = getOtelResource();
226
+ // We re-register here because this runs on a worker thread
227
+ registerOtelLoggerProvider(resource, url ? new URL(url) : undefined);
228
+ return new OTelPinoStream(options);
229
+ }
@@ -0,0 +1,33 @@
1
+ import type { TelemetryClient, Tracer } from './telemetry.js';
2
+ /**
3
+ * A minimal class that enables recording metrics with a telemetry client.
4
+ * This base class enables tracing
5
+ *
6
+ * In other words:
7
+ * Enables the ability to call `@trackSpan` on methods.
8
+ *
9
+ * Example:
10
+ *
11
+ * ```
12
+ * import {Attributes, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
13
+ *
14
+ * class MyClass extends WithTracer {
15
+ * // Constructor is required to be passed the TelemetryClient implementation.
16
+ * constructor(client: TelemetryClient) {
17
+ * super(client, 'MyClass');
18
+ * }
19
+ *
20
+ * @trackSpan('MyClass.myMethod', (arg: string) => ({
21
+ * [Attributes.ARG]: arg,
22
+ * }))
23
+ * public myMethod(arg: string) {
24
+ * // ...
25
+ * }
26
+ * }
27
+ * ```
28
+ */
29
+ export declare class WithTracer {
30
+ readonly tracer: Tracer;
31
+ constructor(client: TelemetryClient, name: string);
32
+ }
33
+ //# sourceMappingURL=with_tracer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_tracer.d.ts","sourceRoot":"","sources":["../src/with_tracer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,UAAU;IACrB,SAAgB,MAAM,EAAE,MAAM,CAAC;gBACnB,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM;CAGlD"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A minimal class that enables recording metrics with a telemetry client.
3
+ * This base class enables tracing
4
+ *
5
+ * In other words:
6
+ * Enables the ability to call `@trackSpan` on methods.
7
+ *
8
+ * Example:
9
+ *
10
+ * ```
11
+ * import {Attributes, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
12
+ *
13
+ * class MyClass extends WithTracer {
14
+ * // Constructor is required to be passed the TelemetryClient implementation.
15
+ * constructor(client: TelemetryClient) {
16
+ * super(client, 'MyClass');
17
+ * }
18
+ *
19
+ * @trackSpan('MyClass.myMethod', (arg: string) => ({
20
+ * [Attributes.ARG]: arg,
21
+ * }))
22
+ * public myMethod(arg: string) {
23
+ * // ...
24
+ * }
25
+ * }
26
+ * ```
27
+ */ export class WithTracer {
28
+ tracer;
29
+ constructor(client, name){
30
+ this.tracer = client.getTracer(name);
31
+ }
32
+ }
@@ -0,0 +1,16 @@
1
+ import { defaultFetch } from '@aztec/foundation/json-rpc/client';
2
+ import type { Logger } from '@aztec/foundation/log';
3
+ /**
4
+ * Makes a fetch function that retries based on the given attempts and propagates trace information.
5
+ * @param retries - Sequence of intervals (in seconds) to retry.
6
+ * @param noRetry - Whether to stop retries on server errors.
7
+ * @param log - Optional logger for logging attempts.
8
+ * @returns A fetch function.
9
+ */
10
+ export declare function makeTracedFetch(retries: number[], defaultNoRetry: boolean, fetch?: typeof defaultFetch, log?: Logger): (host: string, rpcMethod: string, body: any, useApiEndpoints: boolean, extraHeaders?: Record<string, string>, noRetry?: boolean) => Promise<{
11
+ response: any;
12
+ headers: {
13
+ get: (header: string) => string | null | undefined;
14
+ };
15
+ }>;
16
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/wrappers/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAQpD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,sBAAe,EAAE,GAAG,CAAC,EAAE,MAAM,UAEpG,MAAM,aACD,MAAM,QACX,GAAG,mBACQ,OAAO,iBACV,OAAO,MAAM,EAAE,MAAM,CAAC,YAC1B,OAAO;;;;;GA4BpB"}
@@ -0,0 +1,39 @@
1
+ import { defaultFetch } from '@aztec/foundation/json-rpc/client';
2
+ import { makeBackoff, retry } from '@aztec/foundation/retry';
3
+ import { SpanKind, SpanStatusCode, context, propagation } from '@opentelemetry/api';
4
+ import { getTelemetryClient } from '../start.js';
5
+ import { ATTR_JSONRPC_METHOD, ATTR_JSONRPC_REQUEST_ID } from '../vendor/attributes.js';
6
+ /**
7
+ * Makes a fetch function that retries based on the given attempts and propagates trace information.
8
+ * @param retries - Sequence of intervals (in seconds) to retry.
9
+ * @param noRetry - Whether to stop retries on server errors.
10
+ * @param log - Optional logger for logging attempts.
11
+ * @returns A fetch function.
12
+ */ export function makeTracedFetch(retries, defaultNoRetry, fetch = defaultFetch, log) {
13
+ return (host, rpcMethod, body, useApiEndpoints, extraHeaders = {}, noRetry)=>{
14
+ const telemetry = getTelemetryClient();
15
+ return telemetry.getTracer('fetch').startActiveSpan(`JsonRpcClient.${rpcMethod}`, {
16
+ kind: SpanKind.CLIENT
17
+ }, async (span)=>{
18
+ try {
19
+ if (body && typeof body.id === 'number') {
20
+ span.setAttribute(ATTR_JSONRPC_REQUEST_ID, body.id);
21
+ }
22
+ span.setAttribute(ATTR_JSONRPC_METHOD, rpcMethod);
23
+ const headers = {
24
+ ...extraHeaders
25
+ };
26
+ propagation.inject(context.active(), headers);
27
+ return await retry(()=>fetch(host, rpcMethod, body, useApiEndpoints, headers, noRetry ?? defaultNoRetry), `JsonRpcClient request ${rpcMethod} to ${host}`, makeBackoff(retries), log, false);
28
+ } catch (err) {
29
+ span.setStatus({
30
+ code: SpanStatusCode.ERROR,
31
+ message: err?.message ?? String(err)
32
+ });
33
+ throw err;
34
+ } finally{
35
+ span.end();
36
+ }
37
+ });
38
+ };
39
+ }
@@ -0,0 +1,4 @@
1
+ export * from './l2_block_stream.js';
2
+ export * from './fetch.js';
3
+ export * from './json_rpc_server.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wrappers/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './l2_block_stream.js';
2
+ export * from './fetch.js';
3
+ export * from './json_rpc_server.js';
@@ -0,0 +1,4 @@
1
+ import { type SafeJsonRpcServerOptions } from '@aztec/foundation/json-rpc/server';
2
+ import type { ApiSchemaFor } from '@aztec/stdlib/schemas';
3
+ export declare function createTracedJsonRpcServer<T extends object = any>(handler: T, schema: ApiSchemaFor<T>, options?: Partial<SafeJsonRpcServerOptions>): import("@aztec/foundation/json-rpc/server").SafeJsonRpcServer;
4
+ //# sourceMappingURL=json_rpc_server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json_rpc_server.d.ts","sourceRoot":"","sources":["../../src/wrappers/json_rpc_server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAA2B,MAAM,mCAAmC,CAAC;AAC3G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,EAC9D,OAAO,EAAE,CAAC,EACV,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,OAAO,GAAE,OAAO,CAAC,wBAAwB,CAAM,iEAMhD"}
@@ -0,0 +1,11 @@
1
+ import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
2
+ import { getOtelJsonRpcPropagationMiddleware } from '../otel_propagation.js';
3
+ export function createTracedJsonRpcServer(handler, schema, options = {}) {
4
+ return createSafeJsonRpcServer(handler, schema, {
5
+ ...options,
6
+ middlewares: [
7
+ ...options.middlewares ?? [],
8
+ getOtelJsonRpcPropagationMiddleware()
9
+ ]
10
+ });
11
+ }
@@ -0,0 +1,15 @@
1
+ import { type L2BlockSource, L2BlockStream, type L2BlockStreamEventHandler, type L2BlockStreamLocalDataProvider } from '@aztec/stdlib/block';
2
+ import { type Traceable, type Tracer } from '@aztec/telemetry-client';
3
+ /** Extends an L2BlockStream with a tracer to create a new trace per iteration. */
4
+ export declare class TraceableL2BlockStream extends L2BlockStream implements Traceable {
5
+ readonly tracer: Tracer;
6
+ private readonly name;
7
+ constructor(l2BlockSource: Pick<L2BlockSource, 'getBlocks' | 'getBlockHeader' | 'getL2Tips'>, localData: L2BlockStreamLocalDataProvider, handler: L2BlockStreamEventHandler, tracer: Tracer, name?: string, log?: import("@aztec/foundation/log").Logger, opts?: {
8
+ proven?: boolean;
9
+ pollIntervalMS?: number;
10
+ batchSize?: number;
11
+ startingBlock?: number;
12
+ });
13
+ work(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=l2_block_stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"l2_block_stream.d.ts","sourceRoot":"","sources":["../../src/wrappers/l2_block_stream.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACpC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,EAAa,MAAM,yBAAyB,CAAC;AAEjF,kFAAkF;AAClF,qBAAa,sBAAuB,SAAQ,aAAc,YAAW,SAAS;aAK1D,MAAM,EAAE,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAJrB,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,gBAAgB,GAAG,WAAW,CAAC,EAChF,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,yBAAyB,EAClB,MAAM,EAAE,MAAM,EACb,IAAI,GAAE,MAAwB,EAC/C,GAAG,yCAAqC,EACxC,IAAI,GAAE;QACJ,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;KACnB;IAUC,IAAI;CAGd"}
@@ -0,0 +1,26 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ import { createLogger } from '@aztec/foundation/log';
8
+ import { L2BlockStream } from '@aztec/stdlib/block';
9
+ import { trackSpan } from '@aztec/telemetry-client';
10
+ /** Extends an L2BlockStream with a tracer to create a new trace per iteration. */ export class TraceableL2BlockStream extends L2BlockStream {
11
+ tracer;
12
+ name;
13
+ constructor(l2BlockSource, localData, handler, tracer, name = 'L2BlockStream', log = createLogger('types:block_stream'), opts = {}){
14
+ super(l2BlockSource, localData, handler, log, opts), this.tracer = tracer, this.name = name;
15
+ }
16
+ // We need to use a non-arrow function to be able to access `this`
17
+ // See https://www.typescriptlang.org/docs/handbook/2/functions.html#declaring-this-in-a-function
18
+ work() {
19
+ return super.work();
20
+ }
21
+ }
22
+ _ts_decorate([
23
+ trackSpan(function() {
24
+ return `${this.name}.work`;
25
+ })
26
+ ], TraceableL2BlockStream.prototype, "work", null);
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@aztec/telemetry-client",
3
+ "inherits": [
4
+ "../package.common.json"
5
+ ],
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./dest/index.js",
9
+ "./bench": "./dest/bench.js",
10
+ "./otel-pino-stream": "./dest/vendor/otel-pino-stream.js"
11
+ },
12
+ "scripts": {
13
+ "build": "yarn clean && tsc -b",
14
+ "build:dev": "tsc -b --watch",
15
+ "clean": "rm -rf ./dest .tsbuildinfo",
16
+ "formatting": "run -T prettier --check ./src && run -T eslint ./src",
17
+ "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
18
+ "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
19
+ },
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "files": [
24
+ "dest",
25
+ "src",
26
+ "!*.test.*"
27
+ ],
28
+ "dependencies": {
29
+ "@aztec/foundation": "0.0.0-test.0",
30
+ "@aztec/stdlib": "0.0.0-test.0",
31
+ "@opentelemetry/api": "^1.9.0",
32
+ "@opentelemetry/api-logs": "^0.55.0",
33
+ "@opentelemetry/core": "^1.28.0",
34
+ "@opentelemetry/exporter-logs-otlp-http": "^0.55.0",
35
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.55.0",
36
+ "@opentelemetry/exporter-trace-otlp-http": "^0.55.0",
37
+ "@opentelemetry/host-metrics": "^0.35.4",
38
+ "@opentelemetry/otlp-exporter-base": "^0.55.0",
39
+ "@opentelemetry/resource-detector-gcp": "^0.32.0",
40
+ "@opentelemetry/resources": "^1.28.0",
41
+ "@opentelemetry/sdk-logs": "^0.55.0",
42
+ "@opentelemetry/sdk-metrics": "^1.28.0",
43
+ "@opentelemetry/sdk-trace-node": "^1.28.0",
44
+ "@opentelemetry/semantic-conventions": "^1.28.0",
45
+ "prom-client": "^15.1.3"
46
+ },
47
+ "devDependencies": {
48
+ "@jest/globals": "^29.5.0",
49
+ "@types/jest": "^29.5.0",
50
+ "@types/koa": "^2.15.0",
51
+ "jest": "^29.5.0",
52
+ "ts-node": "^10.9.1",
53
+ "typescript": "^5.0.4"
54
+ },
55
+ "jest": {
56
+ "extensionsToTreatAsEsm": [
57
+ ".ts"
58
+ ],
59
+ "transform": {
60
+ "^.+\\.tsx?$": [
61
+ "@swc/jest",
62
+ {
63
+ "jsc": {
64
+ "parser": {
65
+ "syntax": "typescript",
66
+ "decorators": true
67
+ },
68
+ "transform": {
69
+ "decoratorVersion": "2022-03"
70
+ }
71
+ }
72
+ }
73
+ ]
74
+ },
75
+ "moduleNameMapper": {
76
+ "^(\\.{1,2}/.*)\\.[cm]?js$": "$1"
77
+ },
78
+ "reporters": [
79
+ "default"
80
+ ],
81
+ "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$",
82
+ "rootDir": "./src",
83
+ "testTimeout": 120000,
84
+ "setupFiles": [
85
+ "../../foundation/src/jest/setup.mjs"
86
+ ]
87
+ },
88
+ "version": "0.0.0-test.0"
89
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @overview This file contains the custom attributes used in telemetry events.
3
+ * Attribute names exist in a global namespace, alongside metric names. Use this file to ensure that attribute names are unique.
4
+ *
5
+ * To define a new attribute follow these steps:
6
+ * 1. Make sure it's not a semantic attribute that's already been defined by {@link @opentelemetry/semantic-conventions | OpenTelemetry} (e.g. `service.name`)
7
+ * 2. Come up with a unique name for it so that it doesn't clash with other attributes or metrics.
8
+ * 3. Prefix the attribute name with `aztec` to make it clear that it's a custom attribute.
9
+ * 4. Add a description of what the attribute represents and examples of what it might contain.
10
+ * 5. Start using it.
11
+ *
12
+ * @note Attributes and metric names exist in a hierarchy of namespaces. If a name has been used as a namespace, then it can not be used as a name for an attribute or metric.
13
+ * @example If `aztec.circuit.name` has been defined as an attribute then `aztec.circuit` alone can not be re-used for a metric or attribute because it is already a namespace.
14
+ * @see {@link https://opentelemetry.io/docs/specs/semconv/general/attribute-naming/}
15
+ */
16
+
17
+ /** The Aztec network identifier */
18
+ export const NETWORK_NAME = 'aztec.network_name';
19
+
20
+ /**
21
+ * The name of the protocol circuit being run (e.g. public-kernel-setup or base-rollup)
22
+ * @see {@link @aztec/stdlib/stats:CircuitName}
23
+ */
24
+ export const PROTOCOL_CIRCUIT_NAME = 'aztec.circuit.protocol_circuit_name';
25
+
26
+ /**
27
+ * The type of protocol circuit being run: server or client
28
+ */
29
+ export const PROTOCOL_CIRCUIT_TYPE = 'aztec.circuit.protocol_circuit_type';
30
+
31
+ /**
32
+ * For an app circuit, the contract:function being run (e.g. Token:transfer)
33
+ */
34
+ export const APP_CIRCUIT_NAME = 'aztec.circuit.app_circuit_name';
35
+
36
+ /**
37
+ * The type of app circuit being run: server or client
38
+ */
39
+ export const APP_CIRCUIT_TYPE = 'aztec.circuit.app_circuit_type';
40
+
41
+ /** The block archive */
42
+ export const BLOCK_ARCHIVE = 'aztec.block.archive';
43
+ /** The block number */
44
+ export const BLOCK_NUMBER = 'aztec.block.number';
45
+ /** The slot number */
46
+ export const SLOT_NUMBER = 'aztec.slot.number';
47
+ /** The parent's block number */
48
+ export const BLOCK_PARENT = 'aztec.block.parent';
49
+ /** How many txs are being processed to build this block */
50
+ export const BLOCK_CANDIDATE_TXS_COUNT = 'aztec.block.candidate_txs_count';
51
+ /** How many actual txs were included in this block */
52
+ export const BLOCK_TXS_COUNT = 'aztec.block.txs_count';
53
+ /** The block size */
54
+ export const BLOCK_SIZE = 'aztec.block.size';
55
+ /** How many blocks are included in this epoch */
56
+ export const EPOCH_SIZE = 'aztec.epoch.size';
57
+ /** The proposer of a block */
58
+ export const BLOCK_PROPOSER = 'aztec.block.proposer';
59
+ /** The epoch number */
60
+ export const EPOCH_NUMBER = 'aztec.epoch.number';
61
+ /** The tx hash */
62
+ export const TX_HASH = 'aztec.tx.hash';
63
+ /** Generic attribute representing whether the action was successful or not */
64
+ export const OK = 'aztec.ok';
65
+ /** Generic status attribute */
66
+ export const STATUS = 'aztec.status';
67
+ /** Generic error type attribute */
68
+ export const ERROR_TYPE = 'aztec.error_type';
69
+ /** The type of the transaction */
70
+ export const L1_TX_TYPE = 'aztec.l1.tx_type';
71
+ /** The L1 address of the entity that sent a transaction to L1 */
72
+ export const L1_SENDER = 'aztec.l1.sender';
73
+ /** The phase of the transaction */
74
+ export const TX_PHASE_NAME = 'aztec.tx.phase_name';
75
+ /** The reason for disconnecting a peer */
76
+ export const P2P_GOODBYE_REASON = 'aztec.p2p.goodbye.reason';
77
+ /** The proving job type */
78
+ export const PROVING_JOB_TYPE = 'aztec.proving.job_type';
79
+ /** The proving job id */
80
+ export const PROVING_JOB_ID = 'aztec.proving.job_id';
81
+
82
+ export const MERKLE_TREE_NAME = 'aztec.merkle_tree.name';
83
+ /** The prover-id in a root rollup proof. */
84
+ export const ROLLUP_PROVER_ID = 'aztec.rollup.prover_id';
85
+ /** Whether the proof submission was timed out (delayed more than 20 min) */
86
+ export const PROOF_TIMED_OUT = 'aztec.proof.timed_out';
87
+
88
+ export const P2P_ID = 'aztec.p2p.id';
89
+ export const P2P_REQ_RESP_PROTOCOL = 'aztec.p2p.req_resp.protocol';
90
+ export const P2P_REQ_RESP_BATCH_REQUESTS_COUNT = 'aztec.p2p.req_resp.batch_requests_count';
91
+ export const POOL_NAME = 'aztec.pool.name';
92
+
93
+ export const SEQUENCER_STATE = 'aztec.sequencer.state';
94
+
95
+ export const SIMULATOR_PHASE = 'aztec.simulator.phase';
96
+ export const TARGET_ADDRESS = 'aztec.address.target';
97
+ export const SENDER_ADDRESS = 'aztec.address.sender';
98
+ export const MANA_USED = 'aztec.mana.used';
99
+
100
+ /** Whether a sync process is the initial run, which is usually slower than iterative ones. */
101
+ export const INITIAL_SYNC = 'aztec.initial_sync';
102
+
103
+ /** Identifier for the tables in a world state DB */
104
+ export const WS_DB_DATA_TYPE = 'aztec.world_state.db_type';
105
+
106
+ /** Identifier for component database (e.g. archiver, tx pool) */
107
+ export const DB_DATA_TYPE = 'aztec.db_type';
108
+
109
+ export const REVERTIBILITY = 'aztec.revertibility';
110
+
111
+ export const GAS_DIMENSION = 'aztec.gas_dimension';
112
+
113
+ export const WORLD_STATE_REQUEST_TYPE = 'aztec.world_state_request';
114
+
115
+ export const NODEJS_EVENT_LOOP_STATE = 'nodejs.eventloop.state';