@bsb/observable-opentelemetry 9.1.3 → 9.6.12

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/README.md CHANGED
@@ -5,7 +5,7 @@ OpenTelemetry observable plugin for BSB with full OTLP export support for traces
5
5
  ## Key Features
6
6
 
7
7
  - Full OpenTelemetry integration for traces, metrics, and logs
8
- - OTLP export over HTTP and gRPC protocols
8
+ - OTLP export over HTTP
9
9
  - Customizable resource attributes for service metadata
10
10
  - Configurable sampling to control trace collection rates
11
11
  - Efficient batch processing for data export
@@ -50,7 +50,7 @@ plugins:
50
50
  | `serviceName` | Name of your service | - |
51
51
  | `serviceVersion` | Version of your service | - |
52
52
  | `endpoint` | OTLP collector endpoint URL | `http://localhost:4318` |
53
- | `export.protocol` | Export protocol: `http` or `grpc` | `http` |
53
+ | `export.protocol` | Export protocol setting; current exporter implementation uses `http` | `http` |
54
54
  | `export.interval` | Export interval in milliseconds | `5000` |
55
55
  | `export.maxBatchSize` | Maximum batch size for exports | `512` |
56
56
  | `enabled` | Toggle traces, metrics, and logs individually | All enabled |
@@ -26,65 +26,65 @@
26
26
  */
27
27
  import { BSBObservable, BSBObservableConstructor, BSBError } from "@bsb/base";
28
28
  import { DTrace, LogMeta } from "@bsb/base";
29
- import * as av from "@anyvali/js";
29
+ import * as av from "anyvali";
30
30
  /**
31
31
  * Configuration schema for OpenTelemetry plugin
32
32
  */
33
33
  export declare const OpenTelemetryConfigSchema: av.ObjectSchema<{
34
- serviceName: av.OptionalSchema<av.StringSchema>;
34
+ serviceName: av.StringSchema;
35
35
  serviceVersion: av.OptionalSchema<av.StringSchema>;
36
- endpoint: av.OptionalSchema<av.StringSchema>;
36
+ endpoint: av.StringSchema;
37
37
  export: av.ObjectSchema<{
38
- protocol: av.OptionalSchema<av.EnumSchema<string[]>>;
39
- interval: av.OptionalSchema<av.Int32Schema>;
40
- maxBatchSize: av.OptionalSchema<av.Int32Schema>;
38
+ protocol: av.EnumSchema<string[]>;
39
+ interval: av.Int32Schema;
40
+ maxBatchSize: av.Int32Schema;
41
41
  }>;
42
42
  enabled: av.ObjectSchema<{
43
- traces: av.OptionalSchema<av.BoolSchema>;
44
- metrics: av.OptionalSchema<av.BoolSchema>;
45
- logs: av.OptionalSchema<av.BoolSchema>;
43
+ traces: av.BoolSchema;
44
+ metrics: av.BoolSchema;
45
+ logs: av.BoolSchema;
46
46
  }>;
47
- resourceAttributes: av.OptionalSchema<av.RecordSchema<av.StringSchema>>;
48
- samplingRate: av.OptionalSchema<av.NumberSchema>;
47
+ resourceAttributes: av.RecordSchema<av.StringSchema>;
48
+ samplingRate: av.NumberSchema;
49
49
  }>;
50
50
  export type OpenTelemetryConfig = av.Infer<typeof OpenTelemetryConfigSchema>;
51
51
  export declare const Config: import("@bsb/base").BSBPluginConfigClass<av.ObjectSchema<{
52
- serviceName: av.OptionalSchema<av.StringSchema>;
52
+ serviceName: av.StringSchema;
53
53
  serviceVersion: av.OptionalSchema<av.StringSchema>;
54
- endpoint: av.OptionalSchema<av.StringSchema>;
54
+ endpoint: av.StringSchema;
55
55
  export: av.ObjectSchema<{
56
- protocol: av.OptionalSchema<av.EnumSchema<string[]>>;
57
- interval: av.OptionalSchema<av.Int32Schema>;
58
- maxBatchSize: av.OptionalSchema<av.Int32Schema>;
56
+ protocol: av.EnumSchema<string[]>;
57
+ interval: av.Int32Schema;
58
+ maxBatchSize: av.Int32Schema;
59
59
  }>;
60
60
  enabled: av.ObjectSchema<{
61
- traces: av.OptionalSchema<av.BoolSchema>;
62
- metrics: av.OptionalSchema<av.BoolSchema>;
63
- logs: av.OptionalSchema<av.BoolSchema>;
61
+ traces: av.BoolSchema;
62
+ metrics: av.BoolSchema;
63
+ logs: av.BoolSchema;
64
64
  }>;
65
- resourceAttributes: av.OptionalSchema<av.RecordSchema<av.StringSchema>>;
66
- samplingRate: av.OptionalSchema<av.NumberSchema>;
65
+ resourceAttributes: av.RecordSchema<av.StringSchema>;
66
+ samplingRate: av.NumberSchema;
67
67
  }>>;
68
68
  /**
69
69
  * OpenTelemetry observable plugin with OTLP export
70
70
  */
71
71
  export declare class Plugin extends BSBObservable<InstanceType<typeof Config>> {
72
72
  static Config: import("@bsb/base").BSBPluginConfigClass<av.ObjectSchema<{
73
- serviceName: av.OptionalSchema<av.StringSchema>;
73
+ serviceName: av.StringSchema;
74
74
  serviceVersion: av.OptionalSchema<av.StringSchema>;
75
- endpoint: av.OptionalSchema<av.StringSchema>;
75
+ endpoint: av.StringSchema;
76
76
  export: av.ObjectSchema<{
77
- protocol: av.OptionalSchema<av.EnumSchema<string[]>>;
78
- interval: av.OptionalSchema<av.Int32Schema>;
79
- maxBatchSize: av.OptionalSchema<av.Int32Schema>;
77
+ protocol: av.EnumSchema<string[]>;
78
+ interval: av.Int32Schema;
79
+ maxBatchSize: av.Int32Schema;
80
80
  }>;
81
81
  enabled: av.ObjectSchema<{
82
- traces: av.OptionalSchema<av.BoolSchema>;
83
- metrics: av.OptionalSchema<av.BoolSchema>;
84
- logs: av.OptionalSchema<av.BoolSchema>;
82
+ traces: av.BoolSchema;
83
+ metrics: av.BoolSchema;
84
+ logs: av.BoolSchema;
85
85
  }>;
86
- resourceAttributes: av.OptionalSchema<av.RecordSchema<av.StringSchema>>;
87
- samplingRate: av.OptionalSchema<av.NumberSchema>;
86
+ resourceAttributes: av.RecordSchema<av.StringSchema>;
87
+ samplingRate: av.NumberSchema;
88
88
  }>>;
89
89
  private logFormatter;
90
90
  private sdk;
@@ -118,8 +118,8 @@ export declare class Plugin extends BSBObservable<InstanceType<typeof Config>> {
118
118
  setGauge(timestamp: number, pluginName: string, name: string, value: number, labels?: Record<string, string>): void;
119
119
  createHistogram(timestamp: number, pluginName: string, name: string, description: string, help: string, boundaries?: number[], labels?: string[]): void;
120
120
  observeHistogram(timestamp: number, pluginName: string, name: string, value: number, labels?: Record<string, string>): void;
121
- spanStart(trace: DTrace, pluginName: string, spanName: string, parentSpanId: string | null, attributes?: Record<string, string | number | boolean>): void;
122
- spanEnd(trace: DTrace, pluginName: string, attributes?: Record<string, string | number | boolean>): void;
123
- spanError(trace: DTrace, pluginName: string, error: Error, attributes?: Record<string, string | number | boolean>): void;
121
+ spanStart(timestamp: number, trace: DTrace, pluginName: string, spanName: string, parentSpanId: string | null, attributes?: Record<string, string | number | boolean>): void;
122
+ spanEnd(timestamp: number, trace: DTrace, pluginName: string, attributes?: Record<string, string | number | boolean>): void;
123
+ spanError(timestamp: number, trace: DTrace, pluginName: string, error: Error, attributes?: Record<string, string | number | boolean>): void;
124
124
  dispose(): Promise<void>;
125
125
  }
@@ -25,9 +25,9 @@
25
25
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
26
26
  */
27
27
  import { BSBObservable, createConfigSchema, LogFormatter, BSBError } from "@bsb/base";
28
- import * as av from "@anyvali/js";
28
+ import * as av from "anyvali";
29
29
  import * as api from "@opentelemetry/api";
30
- import { Resource } from "@opentelemetry/resources";
30
+ import { resourceFromAttributes } from "@opentelemetry/resources";
31
31
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
32
32
  import { NodeSDK } from "@opentelemetry/sdk-node";
33
33
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
@@ -39,22 +39,22 @@ import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs
39
39
  * Configuration schema for OpenTelemetry plugin
40
40
  */
41
41
  export const OpenTelemetryConfigSchema = av.object({
42
- serviceName: av.optional(av.string()).default("bsb-service"),
43
- serviceVersion: av.optional(av.string()),
44
- endpoint: av.optional(av.string().format("url")).default("http://localhost:4318"),
42
+ serviceName: av.string().default("bsb-service").describe("Service name reported through OpenTelemetry resource attributes"),
43
+ serviceVersion: av.optional(av.string()).describe("Optional service version reported through OpenTelemetry resource attributes"),
44
+ endpoint: av.string().format("url").default("http://localhost:4318").describe("OTLP collector endpoint base URL"),
45
45
  export: av.object({
46
- protocol: av.optional(av.enum_(["http", "grpc"])).default("http"),
47
- interval: av.optional(av.int32().min(100)).default(5000),
48
- maxBatchSize: av.optional(av.int32().min(1)).default(512),
49
- }, { unknownKeys: "strip" }),
46
+ protocol: av.enum_(["http"]).default("http").describe("OTLP HTTP transport protocol setting"),
47
+ interval: av.int32().min(100).default(5000).describe("Metric export interval in milliseconds"),
48
+ maxBatchSize: av.int32().min(1).default(512).describe("Maximum number of telemetry items sent in one export batch"),
49
+ }).describe("OpenTelemetry export settings"),
50
50
  enabled: av.object({
51
- traces: av.optional(av.bool()).default(true),
52
- metrics: av.optional(av.bool()).default(true),
53
- logs: av.optional(av.bool()).default(true),
54
- }, { unknownKeys: "strip" }),
55
- resourceAttributes: av.optional(av.record(av.string())).default({}),
56
- samplingRate: av.optional(av.number().min(0).max(1)).default(1.0),
57
- }, { unknownKeys: "strip" });
51
+ traces: av.bool().default(true).describe("Whether trace export is enabled"),
52
+ metrics: av.bool().default(true).describe("Whether metric export is enabled"),
53
+ logs: av.bool().default(true).describe("Whether log export is enabled"),
54
+ }).describe("Telemetry signal enablement"),
55
+ resourceAttributes: av.record(av.string()).default({}).describe("Additional OpenTelemetry resource attributes attached to exported telemetry"),
56
+ samplingRate: av.number().min(0).max(1).default(1.0).describe("Trace sampling rate from 0.0 to 1.0"),
57
+ }).describe("OpenTelemetry observable plugin configuration");
58
58
  export const Config = createConfigSchema({
59
59
  name: 'observable-opentelemetry',
60
60
  description: 'OpenTelemetry integration for logs, metrics, and traces via OTLP',
@@ -123,7 +123,7 @@ export class Plugin extends BSBObservable {
123
123
  }
124
124
  async init() {
125
125
  // Create resource with service information
126
- const resource = new Resource({
126
+ const resource = resourceFromAttributes({
127
127
  [ATTR_SERVICE_NAME]: this.config.serviceName,
128
128
  ...(this.config.serviceVersion && { [ATTR_SERVICE_VERSION]: this.config.serviceVersion }),
129
129
  ...this.config.resourceAttributes,
@@ -150,17 +150,23 @@ export class Plugin extends BSBObservable {
150
150
  }
151
151
  // Setup metrics separately
152
152
  if (this.config.enabled.metrics) {
153
- const meterProvider = new MeterProvider({ resource });
154
- meterProvider.addMetricReader(new PeriodicExportingMetricReader({
155
- exporter: metricExporter,
156
- exportIntervalMillis: this.config.export.interval,
157
- }));
153
+ const meterProvider = new MeterProvider({
154
+ resource,
155
+ readers: [
156
+ new PeriodicExportingMetricReader({
157
+ exporter: metricExporter,
158
+ exportIntervalMillis: this.config.export.interval,
159
+ }),
160
+ ],
161
+ });
158
162
  this.meter = meterProvider.getMeter(this.config.serviceName, this.config.serviceVersion);
159
163
  }
160
164
  // Setup logs separately
161
165
  if (this.config.enabled.logs) {
162
- this.loggerProvider = new LoggerProvider({ resource });
163
- this.loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
166
+ this.loggerProvider = new LoggerProvider({
167
+ resource,
168
+ processors: [new BatchLogRecordProcessor(logExporter)],
169
+ });
164
170
  this.logger = this.loggerProvider.getLogger(this.config.serviceName, this.config.serviceVersion);
165
171
  }
166
172
  }
@@ -298,12 +304,13 @@ export class Plugin extends BSBObservable {
298
304
  }
299
305
  }
300
306
  // Tracing methods
301
- spanStart(trace, pluginName, spanName, parentSpanId, attributes) {
307
+ spanStart(timestamp, trace, pluginName, spanName, parentSpanId, attributes) {
302
308
  if (!this.tracer || this.isDisposed) {
303
309
  return;
304
310
  }
305
311
  const context = this.getTraceContext(trace);
306
312
  const span = this.tracer.startSpan(spanName, {
313
+ startTime: timestamp,
307
314
  attributes: {
308
315
  "bsb.plugin": pluginName,
309
316
  ...(parentSpanId ? { "bsb.parent_span_id": parentSpanId } : {}),
@@ -313,7 +320,7 @@ export class Plugin extends BSBObservable {
313
320
  const spanKey = `${trace.t}:${trace.s}`;
314
321
  this.spans.set(spanKey, span);
315
322
  }
316
- spanEnd(trace, pluginName, attributes) {
323
+ spanEnd(timestamp, trace, pluginName, attributes) {
317
324
  if (this.isDisposed) {
318
325
  return;
319
326
  }
@@ -323,18 +330,18 @@ export class Plugin extends BSBObservable {
323
330
  if (attributes) {
324
331
  span.setAttributes(attributes);
325
332
  }
326
- span.end();
333
+ span.end(timestamp);
327
334
  this.spans.delete(spanKey);
328
335
  }
329
336
  }
330
- spanError(trace, pluginName, error, attributes) {
337
+ spanError(timestamp, trace, pluginName, error, attributes) {
331
338
  if (this.isDisposed) {
332
339
  return;
333
340
  }
334
341
  const spanKey = `${trace.t}:${trace.s}`;
335
342
  const span = this.spans.get(spanKey);
336
343
  if (span) {
337
- span.recordException(error);
344
+ span.recordException(error, timestamp);
338
345
  span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message });
339
346
  if (attributes) {
340
347
  span.setAttributes(attributes);
@@ -1,121 +1,144 @@
1
1
  {
2
2
  "pluginName": "observable-opentelemetry",
3
3
  "events": {},
4
- "version": "9.1.3",
4
+ "version": "9.6.12",
5
5
  "configSchema": {
6
6
  "anyvaliVersion": "1.0",
7
- "schemaVersion": "1",
7
+ "schemaVersion": "1.1",
8
8
  "root": {
9
9
  "kind": "object",
10
10
  "properties": {
11
11
  "serviceName": {
12
- "kind": "optional",
13
- "inner": {
14
- "kind": "string"
15
- },
16
- "default": "bsb-service"
12
+ "kind": "string",
13
+ "default": "bsb-service",
14
+ "metadata": {
15
+ "description": "Service name reported through OpenTelemetry resource attributes"
16
+ }
17
17
  },
18
18
  "serviceVersion": {
19
19
  "kind": "optional",
20
20
  "inner": {
21
21
  "kind": "string"
22
+ },
23
+ "metadata": {
24
+ "description": "Optional service version reported through OpenTelemetry resource attributes"
22
25
  }
23
26
  },
24
27
  "endpoint": {
25
- "kind": "optional",
26
- "inner": {
27
- "kind": "string",
28
- "format": "url"
29
- },
30
- "default": "http://localhost:4318"
28
+ "kind": "string",
29
+ "format": "url",
30
+ "default": "http://localhost:4318",
31
+ "metadata": {
32
+ "description": "OTLP collector endpoint base URL"
33
+ }
31
34
  },
32
35
  "export": {
33
36
  "kind": "object",
34
37
  "properties": {
35
38
  "protocol": {
36
- "kind": "optional",
37
- "inner": {
38
- "kind": "enum",
39
- "values": [
40
- "http",
41
- "grpc"
42
- ]
43
- },
44
- "default": "http"
39
+ "kind": "enum",
40
+ "values": [
41
+ "http"
42
+ ],
43
+ "default": "http",
44
+ "metadata": {
45
+ "description": "OTLP HTTP transport protocol setting"
46
+ }
45
47
  },
46
48
  "interval": {
47
- "kind": "optional",
48
- "inner": {
49
- "kind": "int32",
50
- "min": 100
51
- },
52
- "default": 5000
49
+ "kind": "int32",
50
+ "min": 100,
51
+ "default": 5000,
52
+ "metadata": {
53
+ "description": "Metric export interval in milliseconds"
54
+ }
53
55
  },
54
56
  "maxBatchSize": {
55
- "kind": "optional",
56
- "inner": {
57
- "kind": "int32",
58
- "min": 1
59
- },
60
- "default": 512
57
+ "kind": "int32",
58
+ "min": 1,
59
+ "default": 512,
60
+ "metadata": {
61
+ "description": "Maximum number of telemetry items sent in one export batch"
62
+ }
61
63
  }
62
64
  },
63
- "required": [],
64
- "unknownKeys": "strip"
65
+ "required": [
66
+ "protocol",
67
+ "interval",
68
+ "maxBatchSize"
69
+ ],
70
+ "unknownKeys": "strip",
71
+ "metadata": {
72
+ "description": "OpenTelemetry export settings"
73
+ }
65
74
  },
66
75
  "enabled": {
67
76
  "kind": "object",
68
77
  "properties": {
69
78
  "traces": {
70
- "kind": "optional",
71
- "inner": {
72
- "kind": "bool"
73
- },
74
- "default": true
79
+ "kind": "bool",
80
+ "default": true,
81
+ "metadata": {
82
+ "description": "Whether trace export is enabled"
83
+ }
75
84
  },
76
85
  "metrics": {
77
- "kind": "optional",
78
- "inner": {
79
- "kind": "bool"
80
- },
81
- "default": true
86
+ "kind": "bool",
87
+ "default": true,
88
+ "metadata": {
89
+ "description": "Whether metric export is enabled"
90
+ }
82
91
  },
83
92
  "logs": {
84
- "kind": "optional",
85
- "inner": {
86
- "kind": "bool"
87
- },
88
- "default": true
93
+ "kind": "bool",
94
+ "default": true,
95
+ "metadata": {
96
+ "description": "Whether log export is enabled"
97
+ }
89
98
  }
90
99
  },
91
- "required": [],
92
- "unknownKeys": "strip"
100
+ "required": [
101
+ "traces",
102
+ "metrics",
103
+ "logs"
104
+ ],
105
+ "unknownKeys": "strip",
106
+ "metadata": {
107
+ "description": "Telemetry signal enablement"
108
+ }
93
109
  },
94
110
  "resourceAttributes": {
95
- "kind": "optional",
96
- "inner": {
97
- "kind": "record",
98
- "valueSchema": {
99
- "kind": "string"
100
- }
111
+ "kind": "record",
112
+ "valueSchema": {
113
+ "kind": "string"
101
114
  },
102
- "default": {}
115
+ "default": {},
116
+ "metadata": {
117
+ "description": "Additional OpenTelemetry resource attributes attached to exported telemetry"
118
+ }
103
119
  },
104
120
  "samplingRate": {
105
- "kind": "optional",
106
- "inner": {
107
- "kind": "number",
108
- "min": 0,
109
- "max": 1
110
- },
111
- "default": 1
121
+ "kind": "number",
122
+ "min": 0,
123
+ "max": 1,
124
+ "default": 1,
125
+ "metadata": {
126
+ "description": "Trace sampling rate from 0.0 to 1.0"
127
+ }
112
128
  }
113
129
  },
114
130
  "required": [
131
+ "serviceName",
132
+ "endpoint",
115
133
  "export",
116
- "enabled"
134
+ "enabled",
135
+ "resourceAttributes",
136
+ "samplingRate"
117
137
  ],
118
- "unknownKeys": "strip"
138
+ "unknownKeys": "strip",
139
+ "metadata": {
140
+ "description": "OpenTelemetry observable plugin configuration"
141
+ }
119
142
  },
120
143
  "definitions": {},
121
144
  "extensions": {}