@struct-ai/sdk 0.2.1 → 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.
@@ -65,6 +65,8 @@ export declare class StructSDK {
65
65
  private _initialized;
66
66
  private _tracerProvider;
67
67
  private _loggerProvider;
68
+ private _spanFanout;
69
+ private _logFanout;
68
70
  private _ingestKey;
69
71
  private _endpoint;
70
72
  private _contentCapture;
@@ -37,6 +37,43 @@ const defaultInternalLogger = {
37
37
  * so consumers cannot reach it via the package's public API surface.
38
38
  */
39
39
  exports.firstFailureLogged = new Set();
40
+ /**
41
+ * OTel SDK 2.x providers accept processors only at construction time —
42
+ * `addSpanProcessor` / `addLogRecordProcessor` no longer exist on the
43
+ * providers. These fan-outs are registered at construction and delegate to a
44
+ * mutable list, preserving the SDK's test-only `addSpanProcessor` /
45
+ * `addLogRecordProcessor` hooks.
46
+ */
47
+ class FanoutSpanProcessor {
48
+ delegates = [];
49
+ onStart(...args) {
50
+ for (const p of this.delegates)
51
+ p.onStart(...args);
52
+ }
53
+ onEnd(...args) {
54
+ for (const p of this.delegates)
55
+ p.onEnd(...args);
56
+ }
57
+ forceFlush() {
58
+ return Promise.all(this.delegates.map((p) => p.forceFlush())).then(() => undefined);
59
+ }
60
+ shutdown() {
61
+ return Promise.all(this.delegates.map((p) => p.shutdown())).then(() => undefined);
62
+ }
63
+ }
64
+ class FanoutLogRecordProcessor {
65
+ delegates = [];
66
+ onEmit(...args) {
67
+ for (const p of this.delegates)
68
+ p.onEmit(...args);
69
+ }
70
+ forceFlush() {
71
+ return Promise.all(this.delegates.map((p) => p.forceFlush())).then(() => undefined);
72
+ }
73
+ shutdown() {
74
+ return Promise.all(this.delegates.map((p) => p.shutdown())).then(() => undefined);
75
+ }
76
+ }
40
77
  /**
41
78
  * Run `fn`; swallow any exception. The first failure per `site` logs at WARN
42
79
  * (with the error attached); subsequent failures at the same site log at
@@ -64,6 +101,8 @@ class StructSDK {
64
101
  _initialized = false;
65
102
  _tracerProvider;
66
103
  _loggerProvider;
104
+ _spanFanout;
105
+ _logFanout;
67
106
  _ingestKey = "";
68
107
  _endpoint = exports.DEFAULT_ENDPOINT;
69
108
  _contentCapture = content_capture_js_1.ContentCaptureMode.EventOnly;
@@ -137,26 +176,31 @@ class StructSDK {
137
176
  maxExportBatchSize: 100,
138
177
  scheduledDelayMillis: 1000,
139
178
  });
140
- const resource = new resources_1.Resource({
179
+ const resource = (0, resources_1.resourceFromAttributes)({
141
180
  "service.name": serviceName,
142
181
  "service.version": serviceVersion,
143
182
  "deployment.environment": environment,
144
183
  });
184
+ this._spanFanout = new FanoutSpanProcessor();
145
185
  this._tracerProvider = new sdk_trace_node_1.NodeTracerProvider({
146
186
  resource,
147
- spanProcessors: [spanProcessor],
187
+ spanProcessors: [spanProcessor, this._spanFanout],
148
188
  });
149
189
  const logExporter = new exporter_logs_otlp_proto_1.OTLPLogExporter({
150
190
  url: `${this._endpoint}/v1/logs`,
151
191
  headers,
152
192
  });
153
- const logProcessor = new sdk_logs_1.BatchLogRecordProcessor(logExporter, {
193
+ const logProcessor = new sdk_logs_1.BatchLogRecordProcessor({
194
+ exporter: logExporter,
154
195
  maxQueueSize: 10000,
155
196
  maxExportBatchSize: 100,
156
197
  scheduledDelayMillis: 1000,
157
198
  });
158
- this._loggerProvider = new sdk_logs_1.LoggerProvider({ resource });
159
- this._loggerProvider.addLogRecordProcessor(logProcessor);
199
+ this._logFanout = new FanoutLogRecordProcessor();
200
+ this._loggerProvider = new sdk_logs_1.LoggerProvider({
201
+ resource,
202
+ processors: [logProcessor, this._logFanout],
203
+ });
160
204
  this._initialized = true;
161
205
  this._shutdownHook = () => {
162
206
  void this.shutdown();
@@ -176,6 +220,8 @@ class StructSDK {
176
220
  this._initialized = false;
177
221
  this._tracerProvider = undefined;
178
222
  this._loggerProvider = undefined;
223
+ this._spanFanout = undefined;
224
+ this._logFanout = undefined;
179
225
  this._shutdownHook = undefined;
180
226
  this._readyPromise = Promise.resolve();
181
227
  return;
@@ -199,11 +245,11 @@ class StructSDK {
199
245
  }
200
246
  /** Test-only: attach a custom span processor to the internal provider. */
201
247
  addSpanProcessor(processor) {
202
- this._tracerProvider?.addSpanProcessor(processor);
248
+ this._spanFanout?.delegates.push(processor);
203
249
  }
204
250
  /** Test-only: attach a custom log record processor. */
205
251
  addLogRecordProcessor(processor) {
206
- this._loggerProvider?.addLogRecordProcessor(processor);
252
+ this._logFanout?.delegates.push(processor);
207
253
  }
208
254
  /**
209
255
  * Shut down the SDK and flush pending telemetry.
@@ -65,6 +65,8 @@ export declare class StructSDK {
65
65
  private _initialized;
66
66
  private _tracerProvider;
67
67
  private _loggerProvider;
68
+ private _spanFanout;
69
+ private _logFanout;
68
70
  private _ingestKey;
69
71
  private _endpoint;
70
72
  private _contentCapture;
package/dist/esm/core.js CHANGED
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { context as otelContext, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
3
3
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-proto";
4
4
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
5
- import { Resource } from "@opentelemetry/resources";
5
+ import { resourceFromAttributes } from "@opentelemetry/resources";
6
6
  import { BatchLogRecordProcessor, LoggerProvider, } from "@opentelemetry/sdk-logs";
7
7
  import { BatchSpanProcessor, NodeTracerProvider, } from "@opentelemetry/sdk-trace-node";
8
8
  import { ContentCaptureMode, captureContentFor, emitEventsFor, emitSpanContentFor, } from "./content-capture.js";
@@ -33,6 +33,43 @@ const defaultInternalLogger = {
33
33
  * so consumers cannot reach it via the package's public API surface.
34
34
  */
35
35
  export const firstFailureLogged = new Set();
36
+ /**
37
+ * OTel SDK 2.x providers accept processors only at construction time —
38
+ * `addSpanProcessor` / `addLogRecordProcessor` no longer exist on the
39
+ * providers. These fan-outs are registered at construction and delegate to a
40
+ * mutable list, preserving the SDK's test-only `addSpanProcessor` /
41
+ * `addLogRecordProcessor` hooks.
42
+ */
43
+ class FanoutSpanProcessor {
44
+ delegates = [];
45
+ onStart(...args) {
46
+ for (const p of this.delegates)
47
+ p.onStart(...args);
48
+ }
49
+ onEnd(...args) {
50
+ for (const p of this.delegates)
51
+ p.onEnd(...args);
52
+ }
53
+ forceFlush() {
54
+ return Promise.all(this.delegates.map((p) => p.forceFlush())).then(() => undefined);
55
+ }
56
+ shutdown() {
57
+ return Promise.all(this.delegates.map((p) => p.shutdown())).then(() => undefined);
58
+ }
59
+ }
60
+ class FanoutLogRecordProcessor {
61
+ delegates = [];
62
+ onEmit(...args) {
63
+ for (const p of this.delegates)
64
+ p.onEmit(...args);
65
+ }
66
+ forceFlush() {
67
+ return Promise.all(this.delegates.map((p) => p.forceFlush())).then(() => undefined);
68
+ }
69
+ shutdown() {
70
+ return Promise.all(this.delegates.map((p) => p.shutdown())).then(() => undefined);
71
+ }
72
+ }
36
73
  /**
37
74
  * Run `fn`; swallow any exception. The first failure per `site` logs at WARN
38
75
  * (with the error attached); subsequent failures at the same site log at
@@ -60,6 +97,8 @@ export class StructSDK {
60
97
  _initialized = false;
61
98
  _tracerProvider;
62
99
  _loggerProvider;
100
+ _spanFanout;
101
+ _logFanout;
63
102
  _ingestKey = "";
64
103
  _endpoint = DEFAULT_ENDPOINT;
65
104
  _contentCapture = ContentCaptureMode.EventOnly;
@@ -133,26 +172,31 @@ export class StructSDK {
133
172
  maxExportBatchSize: 100,
134
173
  scheduledDelayMillis: 1000,
135
174
  });
136
- const resource = new Resource({
175
+ const resource = resourceFromAttributes({
137
176
  "service.name": serviceName,
138
177
  "service.version": serviceVersion,
139
178
  "deployment.environment": environment,
140
179
  });
180
+ this._spanFanout = new FanoutSpanProcessor();
141
181
  this._tracerProvider = new NodeTracerProvider({
142
182
  resource,
143
- spanProcessors: [spanProcessor],
183
+ spanProcessors: [spanProcessor, this._spanFanout],
144
184
  });
145
185
  const logExporter = new OTLPLogExporter({
146
186
  url: `${this._endpoint}/v1/logs`,
147
187
  headers,
148
188
  });
149
- const logProcessor = new BatchLogRecordProcessor(logExporter, {
189
+ const logProcessor = new BatchLogRecordProcessor({
190
+ exporter: logExporter,
150
191
  maxQueueSize: 10000,
151
192
  maxExportBatchSize: 100,
152
193
  scheduledDelayMillis: 1000,
153
194
  });
154
- this._loggerProvider = new LoggerProvider({ resource });
155
- this._loggerProvider.addLogRecordProcessor(logProcessor);
195
+ this._logFanout = new FanoutLogRecordProcessor();
196
+ this._loggerProvider = new LoggerProvider({
197
+ resource,
198
+ processors: [logProcessor, this._logFanout],
199
+ });
156
200
  this._initialized = true;
157
201
  this._shutdownHook = () => {
158
202
  void this.shutdown();
@@ -172,6 +216,8 @@ export class StructSDK {
172
216
  this._initialized = false;
173
217
  this._tracerProvider = undefined;
174
218
  this._loggerProvider = undefined;
219
+ this._spanFanout = undefined;
220
+ this._logFanout = undefined;
175
221
  this._shutdownHook = undefined;
176
222
  this._readyPromise = Promise.resolve();
177
223
  return;
@@ -195,11 +241,11 @@ export class StructSDK {
195
241
  }
196
242
  /** Test-only: attach a custom span processor to the internal provider. */
197
243
  addSpanProcessor(processor) {
198
- this._tracerProvider?.addSpanProcessor(processor);
244
+ this._spanFanout?.delegates.push(processor);
199
245
  }
200
246
  /** Test-only: attach a custom log record processor. */
201
247
  addLogRecordProcessor(processor) {
202
- this._loggerProvider?.addLogRecordProcessor(processor);
248
+ this._logFanout?.delegates.push(processor);
203
249
  }
204
250
  /**
205
251
  * Shut down the SDK and flush pending telemetry.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struct-ai/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry",
5
5
  "type": "module",
6
6
  "main": "./dist/commonjs/index.js",
@@ -51,18 +51,18 @@
51
51
  "access": "public"
52
52
  },
53
53
  "engines": {
54
- "node": ">=18.0.0"
54
+ "node": "^18.19.0 || >=20.6.0"
55
55
  },
56
56
  "dependencies": {
57
57
  "@opentelemetry/api": "^1.9.0",
58
- "@opentelemetry/api-logs": "^0.52.0",
59
- "@opentelemetry/core": "^1.25.0",
60
- "@opentelemetry/exporter-logs-otlp-proto": "^0.52.0",
61
- "@opentelemetry/exporter-trace-otlp-proto": "^0.52.0",
62
- "@opentelemetry/resources": "^1.25.0",
63
- "@opentelemetry/sdk-logs": "^0.52.0",
64
- "@opentelemetry/sdk-trace-base": "^1.25.0",
65
- "@opentelemetry/sdk-trace-node": "^1.25.0"
58
+ "@opentelemetry/api-logs": "^0.220.0",
59
+ "@opentelemetry/core": "^2.9.0",
60
+ "@opentelemetry/exporter-logs-otlp-proto": "^0.220.0",
61
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0",
62
+ "@opentelemetry/resources": "^2.9.0",
63
+ "@opentelemetry/sdk-logs": "^0.220.0",
64
+ "@opentelemetry/sdk-trace-base": "^2.9.0",
65
+ "@opentelemetry/sdk-trace-node": "^2.9.0"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@anthropic-ai/sdk": ">=0.30.0",