@opentelemetry/configuration 0.300.0-rc.0 → 0.301.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 (46) hide show
  1. package/README.md +23 -136
  2. package/dist/index.cjs +5 -6
  3. package/dist/index.d.cts +2 -4
  4. package/dist/index.d.mts +2 -4
  5. package/dist/index.mjs +2 -3
  6. package/dist/{FileConfigFactory.cjs → parse.cjs} +23 -26
  7. package/dist/parse.cjs.map +1 -0
  8. package/dist/{FileConfigFactory.d.cts → parse.d.cts} +5 -4
  9. package/dist/parse.d.cts.map +1 -0
  10. package/dist/{FileConfigFactory.d.mts → parse.d.mts} +5 -4
  11. package/dist/parse.d.mts.map +1 -0
  12. package/dist/{FileConfigFactory.mjs → parse.mjs} +22 -25
  13. package/dist/parse.mjs.map +1 -0
  14. package/dist/utils.cjs +0 -60
  15. package/dist/utils.cjs.map +1 -1
  16. package/dist/utils.mjs +1 -55
  17. package/dist/utils.mjs.map +1 -1
  18. package/package.json +5 -5
  19. package/dist/ConfigFactory.cjs +0 -12
  20. package/dist/ConfigFactory.cjs.map +0 -1
  21. package/dist/ConfigFactory.d.cts +0 -6
  22. package/dist/ConfigFactory.d.cts.map +0 -1
  23. package/dist/ConfigFactory.d.mts +0 -6
  24. package/dist/ConfigFactory.d.mts.map +0 -1
  25. package/dist/ConfigFactory.mjs +0 -12
  26. package/dist/ConfigFactory.mjs.map +0 -1
  27. package/dist/EnvDefinition.cjs +0 -34
  28. package/dist/EnvDefinition.cjs.map +0 -1
  29. package/dist/EnvDefinition.mjs +0 -33
  30. package/dist/EnvDefinition.mjs.map +0 -1
  31. package/dist/EnvReader.cjs +0 -37
  32. package/dist/EnvReader.cjs.map +0 -1
  33. package/dist/EnvReader.mjs +0 -36
  34. package/dist/EnvReader.mjs.map +0 -1
  35. package/dist/EnvironmentConfigFactory.cjs +0 -354
  36. package/dist/EnvironmentConfigFactory.cjs.map +0 -1
  37. package/dist/EnvironmentConfigFactory.mjs +0 -347
  38. package/dist/EnvironmentConfigFactory.mjs.map +0 -1
  39. package/dist/FileConfigFactory.cjs.map +0 -1
  40. package/dist/FileConfigFactory.d.cts.map +0 -1
  41. package/dist/FileConfigFactory.d.mts.map +0 -1
  42. package/dist/FileConfigFactory.mjs.map +0 -1
  43. package/dist/IConfigFactory.d.cts +0 -13
  44. package/dist/IConfigFactory.d.cts.map +0 -1
  45. package/dist/IConfigFactory.d.mts +0 -13
  46. package/dist/IConfigFactory.d.mts.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,11 @@
5
5
 
6
6
  **Note: This is an experimental package under active development. New releases may include breaking changes.**
7
7
 
8
- This package implements the [OpenTelemetry declarative configuration](https://github.com/open-telemetry/opentelemetry-configuration) specification for Node.js. It parses configuration from a YAML file or environment variables and produces a `ConfigurationModel` that the OpenTelemetry SDK uses to initialize providers.
8
+ This package implements a part of the [OpenTelemetry declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) specification for Node.js. It exports:
9
+
10
+ - a suite of TypeScript types representing [the configuration types](https://opentelemetry.io/docs/specs/otel-config/types/) defined by [the declarative config schema](https://github.com/open-telemetry/opentelemetry-configuration#readme);
11
+ - [`parseConfigFile()` to parse and validate](https://opentelemetry.io/docs/specs/otel/configuration/sdk/#parse) a YAML configuration, which can then be used (e.g. by `@opentelemetry/sdk-node`) to setup an OpenTelemetry SDK; and
12
+ - some utilities for working with parsed configuration data.
9
13
 
10
14
  ## Installation
11
15
 
@@ -15,129 +19,38 @@ npm install @opentelemetry/configuration
15
19
 
16
20
  ## Usage
17
21
 
18
- `createConfigFactory()` selects the configuration source automatically:
19
-
20
- - If `OTEL_CONFIG_FILE` points to a valid `.yaml`/`.yml` file, configuration is read from that file.
21
- - Otherwise, configuration is assembled from standard OpenTelemetry environment variables.
22
-
23
- ```typescript
24
- import { createConfigFactory } from '@opentelemetry/configuration';
25
-
26
- const factory = createConfigFactory();
27
- const config = factory.getConfigModel();
28
- ```
29
-
30
- ### YAML file configuration
31
-
32
- Set `OTEL_CONFIG_FILE` to the path of your configuration file:
33
-
34
- ```sh
35
- OTEL_CONFIG_FILE=./otel-config.yaml node app.js
22
+ ```js
23
+ import { parseConfigFile } from '@opentelemetry/configuration';
24
+ const config = parseConfigFile('./otel-sdk-config.yaml');
36
25
  ```
37
26
 
38
- Example:
27
+ An extremely limit example configuration file:
39
28
 
40
29
  ```yaml
41
- file_format: "1.0"
42
- resource:
43
- attributes:
44
- - name: service.name
45
- value: my-service
30
+ file_format: "1.1"
46
31
  tracer_provider:
47
32
  processors:
48
33
  - batch:
49
34
  exporter:
50
35
  otlp_http:
51
- endpoint: http://localhost:4318/v1/traces
36
+ endpoint: ${OTEL_EXPORTER_ENDPOINT:-http://localhost:4318}/v1/traces
52
37
  ```
53
38
 
54
39
  Environment variable substitution is supported using `${VAR_NAME}`, `${VAR_NAME:-default}`, `${env:VAR_NAME}`, and `${env:VAR_NAME:-default}` syntax. Use `$$` for a literal `$`.
55
40
 
56
- ```yaml
57
- tracer_provider:
58
- processors:
59
- - batch:
60
- exporter:
61
- otlp_http:
62
- endpoint: ${OTEL_EXPORTER_ENDPOINT:-http://localhost:4318}/v1/traces
63
- ```
41
+ See <https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration> and <https://github.com/open-telemetry/opentelemetry-configuration> for documentation, examples, and a JSON schema for declarative configuration.
42
+
43
+ ## Supported schema versions
44
+
45
+ - `1.0`
46
+ - `1.1`
64
47
 
65
- ### Environment variable configuration
66
-
67
- When no config file is set, the factory reads from the standard OpenTelemetry SDK environment variables. The full set of variables this package consumes:
68
-
69
- | Variable | Description |
70
- | --- | --- |
71
- | `OTEL_SDK_DISABLED` | Disable the SDK entirely |
72
- | `OTEL_LOG_LEVEL` | Internal SDK log level |
73
- | `OTEL_SERVICE_NAME` | Service name resource attribute |
74
- | `OTEL_RESOURCE_ATTRIBUTES` | Comma-separated resource attributes |
75
- | `OTEL_NODE_RESOURCE_DETECTORS` | Resource detectors to enable (`env`, `host`, `os`, `process`, `serviceinstance`, `all`, `none`) |
76
- | `OTEL_PROPAGATORS` | Propagators: `tracecontext`, `baggage`, `b3`, `b3multi` |
77
- | `OTEL_TRACES_EXPORTER` | Traces exporter(s): `otlp`, `console`, `none` |
78
- | `OTEL_METRICS_EXPORTER` | Metrics exporter(s): `otlp`, `prometheus`, `console`, `none` |
79
- | `OTEL_LOGS_EXPORTER` | Logs exporter(s): `otlp`, `console`, `none` |
80
- | `OTEL_TRACES_SAMPLER` | Sampler name (e.g. `parentbased_always_on`, `traceidratio`) |
81
- | `OTEL_TRACES_SAMPLER_ARG` | Sampler argument (e.g. ratio value) |
82
- | `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP endpoint (all signals) |
83
- | `OTEL_EXPORTER_OTLP_HEADERS` | OTLP headers (all signals) |
84
- | `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP protocol: `grpc`, `http/protobuf`, `http/json` |
85
- | `OTEL_EXPORTER_OTLP_TIMEOUT` | OTLP request timeout (all signals) |
86
- | `OTEL_EXPORTER_OTLP_COMPRESSION` | OTLP compression (all signals): `gzip`, `none` |
87
- | `OTEL_EXPORTER_OTLP_CERTIFICATE` | OTLP server CA certificate file (all signals) |
88
- | `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE` | OTLP client certificate file for mTLS (all signals) |
89
- | `OTEL_EXPORTER_OTLP_CLIENT_KEY` | OTLP client private key file for mTLS (all signals) |
90
- | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Per-signal override (traces) |
91
- | `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | Per-signal override (traces) |
92
- | `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | Per-signal override (traces) |
93
- | `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | Per-signal override (traces) |
94
- | `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION` | Per-signal override (traces) |
95
- | `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE` | Per-signal override (traces) |
96
- | `OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE` | Per-signal override (traces) |
97
- | `OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY` | Per-signal override (traces) |
98
- | `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Per-signal override (metrics) |
99
- | `OTEL_EXPORTER_OTLP_METRICS_HEADERS` | Per-signal override (metrics) |
100
- | `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL` | Per-signal override (metrics) |
101
- | `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` | Per-signal override (metrics) |
102
- | `OTEL_EXPORTER_OTLP_METRICS_COMPRESSION` | Per-signal override (metrics) |
103
- | `OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE` | Per-signal override (metrics) |
104
- | `OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE` | Per-signal override (metrics) |
105
- | `OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY` | Per-signal override (metrics) |
106
- | `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE` | Metric temporality preference: `cumulative`, `delta`, `lowmemory` |
107
- | `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION` | Default histogram aggregation: `explicit_bucket_histogram`, `base2_exponential_bucket_histogram` |
108
- | `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Per-signal override (logs) |
109
- | `OTEL_EXPORTER_OTLP_LOGS_HEADERS` | Per-signal override (logs) |
110
- | `OTEL_EXPORTER_OTLP_LOGS_PROTOCOL` | Per-signal override (logs) |
111
- | `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` | Per-signal override (logs) |
112
- | `OTEL_EXPORTER_OTLP_LOGS_COMPRESSION` | Per-signal override (logs) |
113
- | `OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE` | Per-signal override (logs) |
114
- | `OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE` | Per-signal override (logs) |
115
- | `OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY` | Per-signal override (logs) |
116
- | `OTEL_EXPORTER_PROMETHEUS_HOST` | Prometheus exporter bind host |
117
- | `OTEL_EXPORTER_PROMETHEUS_PORT` | Prometheus exporter bind port |
118
- | `OTEL_METRIC_EXPORT_INTERVAL` | Periodic metric reader export interval (ms) |
119
- | `OTEL_METRIC_EXPORT_TIMEOUT` | Periodic metric reader export timeout (ms) |
120
- | `OTEL_METRICS_EXEMPLAR_FILTER` | Exemplar filter: `always_on`, `always_off`, `trace_based` |
121
- | `OTEL_BSP_SCHEDULE_DELAY` | Batch span processor: schedule delay (ms) |
122
- | `OTEL_BSP_EXPORT_TIMEOUT` | Batch span processor: export timeout (ms) |
123
- | `OTEL_BSP_MAX_QUEUE_SIZE` | Batch span processor: max queue size |
124
- | `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | Batch span processor: max export batch size |
125
- | `OTEL_BLRP_SCHEDULE_DELAY` | Batch log record processor: schedule delay (ms) |
126
- | `OTEL_BLRP_EXPORT_TIMEOUT` | Batch log record processor: export timeout (ms) |
127
- | `OTEL_BLRP_MAX_QUEUE_SIZE` | Batch log record processor: max queue size |
128
- | `OTEL_BLRP_MAX_EXPORT_BATCH_SIZE` | Batch log record processor: max export batch size |
129
- | `OTEL_ATTRIBUTE_COUNT_LIMIT` | Default max attributes per span/log/event/link |
130
- | `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` | Default max attribute value length |
131
- | `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT` | Max attributes per span |
132
- | `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` | Max span attribute value length |
133
- | `OTEL_SPAN_EVENT_COUNT_LIMIT` | Max events per span |
134
- | `OTEL_SPAN_LINK_COUNT_LIMIT` | Max links per span |
135
- | `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT` | Max attributes per span event |
136
- | `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT` | Max attributes per span link |
137
- | `OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT` | Max attributes per log record |
138
- | `OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT` | Max log record attribute value length |
139
-
140
- See [`src/EnvironmentConfigFactory.ts`](src/EnvironmentConfigFactory.ts) for the exact parsing logic.
48
+ For a per-field view of which schema fields the SDK currently applies, see
49
+ the JS row in the cross-SDK [language support status][lss] doc maintained in
50
+ the `opentelemetry-configuration` repo. That doc is the source of truth for
51
+ declarative-config conformance across all SDKs.
52
+
53
+ [lss]: https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md#js-
141
54
 
142
55
  ## Exported types
143
56
 
@@ -175,32 +88,6 @@ The generation script (`scripts/generate-config.js`) handles several post-proces
175
88
  - Removes the duplicate type declarations that `json-schema-to-typescript` emits for structurally-identical sub-schemas (e.g. the second `GrpcTls`/`HttpTls`)
176
89
  - Produces a pre-compiled ajv validator (`validator.js` + `validator.d.ts`) for use at runtime
177
90
 
178
- ### Defaults
179
-
180
- Both config paths apply the same spec-defined defaults so consumers see consistent behaviour regardless of config source:
181
-
182
- | Field | Default |
183
- | --- | --- |
184
- | `disabled` | `false` |
185
- | `log_level` | `info` |
186
- | `attribute_limits.attribute_count_limit` | `128` |
187
-
188
- `FileConfigFactory` applies these via `applyConfigDefaults()` after schema validation. `EnvironmentConfigFactory` applies them via `initializeDefaultConfiguration()` in the constructor, then overlays env var values on top.
189
-
190
- One intentional exception in both paths: `AttributeNameValue.type` is **not** defaulted even though the spec says "if omitted, string is used". This is a semantic default for SDK code interpreting resource attributes, not a config-parser concern. SDK code reading `resource.attributes` should apply `attr.type ?? 'string'` at the point of use.
191
-
192
- ## Supported schema versions
193
-
194
- - `1.0`
195
- - `1.1`
196
-
197
- For a per-field view of which schema fields the SDK currently applies, see
198
- the JS row in the cross-SDK [language support status][lss] doc maintained in
199
- the `opentelemetry-configuration` repo. That doc is the source of truth for
200
- declarative-config conformance across all SDKs.
201
-
202
- [lss]: https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md#js-
203
-
204
91
  ## Useful links
205
92
 
206
93
  - [OpenTelemetry Declarative Configuration Specification](https://github.com/open-telemetry/opentelemetry-configuration)
package/dist/index.cjs CHANGED
@@ -1,7 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_FileConfigFactory = require("./FileConfigFactory.cjs");
3
- const require_ConfigFactory = require("./ConfigFactory.cjs");
4
- exports.createConfigFactory = require_ConfigFactory.createConfigFactory;
5
- exports.mergeHeadersConfig = require_FileConfigFactory.mergeHeadersConfig;
6
- exports.mergePropagatorCompositeConfig = require_FileConfigFactory.mergePropagatorCompositeConfig;
7
- exports.mergeResourceAttributesConfig = require_FileConfigFactory.mergeResourceAttributesConfig;
2
+ const require_parse = require("./parse.cjs");
3
+ exports.mergeHeadersConfig = require_parse.mergeHeadersConfig;
4
+ exports.mergePropagatorCompositeConfig = require_parse.mergePropagatorCompositeConfig;
5
+ exports.mergeResourceAttributesConfig = require_parse.mergeResourceAttributesConfig;
6
+ exports.parseConfigFile = require_parse.parseConfigFile;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,3 @@
1
1
  import { Aggregation, AttributeLimits, Base2ExponentialBucketHistogramAggregation, BatchLogRecordProcessor, BatchSpanProcessor, ConfigurationModel, ConsoleMetricExporter, ExperimentalPrometheusMetricExporter, ExplicitBucketHistogramAggregation, ExporterDefaultHistogramAggregation, ExporterTemporalityPreference, GrpcTls, HttpTls, IdGenerator, InstrumentType, LogRecordExporter, LogRecordLimits, LogRecordProcessor, LoggerProvider, MeterProvider, MetricProducer, MetricReader, NameStringValuePair, OtlpGrpcExporter, OtlpGrpcMetricExporter, OtlpHttpExporter, OtlpHttpMetricExporter, ParentBasedSampler, PeriodicMetricReader, Propagator, PullMetricExporter, PullMetricReader, PushMetricExporter, Resource, Sampler, SeverityNumber, SimpleLogRecordProcessor, SimpleSpanProcessor, SpanExporter, SpanLimits, SpanProcessor, TextMapPropagator, TraceIdRatioBasedSampler, TracerProvider, View } from "./generated/types.cjs";
2
- import { ConfigFactory } from "./IConfigFactory.cjs";
3
- import { createConfigFactory } from "./ConfigFactory.cjs";
4
- import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig } from "./FileConfigFactory.cjs";
5
- export { type Aggregation as AggregationConfigModel, type AttributeLimits as AttributeLimitsConfigModel, type Base2ExponentialBucketHistogramAggregation as Base2ExponentialBucketHistogramAggregationConfigModel, type BatchLogRecordProcessor as BatchLogRecordProcessorConfigModel, type BatchSpanProcessor as BatchSpanProcessorConfigModel, type ConfigFactory, type ConfigurationModel, type ConsoleMetricExporter as ConsoleMetricExporterConfigModel, type ExperimentalPrometheusMetricExporter as ExperimentalPrometheusMetricExporterConfigModel, type ExplicitBucketHistogramAggregation as ExplicitBucketHistogramAggregationConfigModel, type ExporterDefaultHistogramAggregation as ExporterDefaultHistogramAggregationConfigModel, type ExporterTemporalityPreference as ExporterTemporalityPreferenceConfigModel, type GrpcTls as GrpcTlsConfigModel, type HttpTls as HttpTlsConfigModel, type IdGenerator as IdGeneratorConfigModel, type InstrumentType as InstrumentTypeConfigModel, type LogRecordExporter as LogRecordExporterConfigModel, type LogRecordLimits as LogRecordLimitsConfigModel, type LogRecordProcessor as LogRecordProcessorConfigModel, type LoggerProvider as LoggerProviderConfigModel, type MeterProvider as MeterProviderConfigModel, type MetricProducer as MetricProducerConfigModel, type MetricReader as MetricReaderConfigModel, type NameStringValuePair as NameStringValuePairConfigModel, type OtlpGrpcExporter as OtlpGrpcExporterConfigModel, type OtlpGrpcMetricExporter as OtlpGrpcMetricExporterConfigModel, type OtlpHttpExporter as OtlpHttpExporterConfigModel, type OtlpHttpMetricExporter as OtlpHttpMetricExporterConfigModel, type ParentBasedSampler as ParentBasedSamplerConfigModel, type PeriodicMetricReader as PeriodicMetricReaderConfigModel, type Propagator as PropagatorConfigModel, type PullMetricExporter as PullMetricExporterConfigModel, type PullMetricReader as PullMetricReaderConfigModel, type PushMetricExporter as PushMetricExporterConfigModel, type Resource as ResourceConfigModel, type Sampler as SamplerConfigModel, type SeverityNumber as SeverityNumberConfigModel, type SimpleLogRecordProcessor as SimpleLogRecordProcessorConfigModel, type SimpleSpanProcessor as SimpleSpanProcessorConfigModel, type SpanExporter as SpanExporterConfigModel, type SpanLimits as SpanLimitsConfigModel, type SpanProcessor as SpanProcessorConfigModel, type TextMapPropagator as TextMapPropagatorConfigModel, type TraceIdRatioBasedSampler as TraceIdRatioBasedSamplerConfigModel, type TracerProvider as TracerProviderConfigModel, type View as ViewConfigModel, createConfigFactory, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig };
2
+ import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile } from "./parse.cjs";
3
+ export { type Aggregation as AggregationConfigModel, type AttributeLimits as AttributeLimitsConfigModel, type Base2ExponentialBucketHistogramAggregation as Base2ExponentialBucketHistogramAggregationConfigModel, type BatchLogRecordProcessor as BatchLogRecordProcessorConfigModel, type BatchSpanProcessor as BatchSpanProcessorConfigModel, type ConfigurationModel, type ConsoleMetricExporter as ConsoleMetricExporterConfigModel, type ExperimentalPrometheusMetricExporter as ExperimentalPrometheusMetricExporterConfigModel, type ExplicitBucketHistogramAggregation as ExplicitBucketHistogramAggregationConfigModel, type ExporterDefaultHistogramAggregation as ExporterDefaultHistogramAggregationConfigModel, type ExporterTemporalityPreference as ExporterTemporalityPreferenceConfigModel, type GrpcTls as GrpcTlsConfigModel, type HttpTls as HttpTlsConfigModel, type IdGenerator as IdGeneratorConfigModel, type InstrumentType as InstrumentTypeConfigModel, type LogRecordExporter as LogRecordExporterConfigModel, type LogRecordLimits as LogRecordLimitsConfigModel, type LogRecordProcessor as LogRecordProcessorConfigModel, type LoggerProvider as LoggerProviderConfigModel, type MeterProvider as MeterProviderConfigModel, type MetricProducer as MetricProducerConfigModel, type MetricReader as MetricReaderConfigModel, type NameStringValuePair as NameStringValuePairConfigModel, type OtlpGrpcExporter as OtlpGrpcExporterConfigModel, type OtlpGrpcMetricExporter as OtlpGrpcMetricExporterConfigModel, type OtlpHttpExporter as OtlpHttpExporterConfigModel, type OtlpHttpMetricExporter as OtlpHttpMetricExporterConfigModel, type ParentBasedSampler as ParentBasedSamplerConfigModel, type PeriodicMetricReader as PeriodicMetricReaderConfigModel, type Propagator as PropagatorConfigModel, type PullMetricExporter as PullMetricExporterConfigModel, type PullMetricReader as PullMetricReaderConfigModel, type PushMetricExporter as PushMetricExporterConfigModel, type Resource as ResourceConfigModel, type Sampler as SamplerConfigModel, type SeverityNumber as SeverityNumberConfigModel, type SimpleLogRecordProcessor as SimpleLogRecordProcessorConfigModel, type SimpleSpanProcessor as SimpleSpanProcessorConfigModel, type SpanExporter as SpanExporterConfigModel, type SpanLimits as SpanLimitsConfigModel, type SpanProcessor as SpanProcessorConfigModel, type TextMapPropagator as TextMapPropagatorConfigModel, type TraceIdRatioBasedSampler as TraceIdRatioBasedSamplerConfigModel, type TracerProvider as TracerProviderConfigModel, type View as ViewConfigModel, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,3 @@
1
1
  import { Aggregation, AttributeLimits, Base2ExponentialBucketHistogramAggregation, BatchLogRecordProcessor, BatchSpanProcessor, ConfigurationModel, ConsoleMetricExporter, ExperimentalPrometheusMetricExporter, ExplicitBucketHistogramAggregation, ExporterDefaultHistogramAggregation, ExporterTemporalityPreference, GrpcTls, HttpTls, IdGenerator, InstrumentType, LogRecordExporter, LogRecordLimits, LogRecordProcessor, LoggerProvider, MeterProvider, MetricProducer, MetricReader, NameStringValuePair, OtlpGrpcExporter, OtlpGrpcMetricExporter, OtlpHttpExporter, OtlpHttpMetricExporter, ParentBasedSampler, PeriodicMetricReader, Propagator, PullMetricExporter, PullMetricReader, PushMetricExporter, Resource, Sampler, SeverityNumber, SimpleLogRecordProcessor, SimpleSpanProcessor, SpanExporter, SpanLimits, SpanProcessor, TextMapPropagator, TraceIdRatioBasedSampler, TracerProvider, View } from "./generated/types.mjs";
2
- import { ConfigFactory } from "./IConfigFactory.mjs";
3
- import { createConfigFactory } from "./ConfigFactory.mjs";
4
- import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig } from "./FileConfigFactory.mjs";
5
- export { type Aggregation as AggregationConfigModel, type AttributeLimits as AttributeLimitsConfigModel, type Base2ExponentialBucketHistogramAggregation as Base2ExponentialBucketHistogramAggregationConfigModel, type BatchLogRecordProcessor as BatchLogRecordProcessorConfigModel, type BatchSpanProcessor as BatchSpanProcessorConfigModel, type ConfigFactory, type ConfigurationModel, type ConsoleMetricExporter as ConsoleMetricExporterConfigModel, type ExperimentalPrometheusMetricExporter as ExperimentalPrometheusMetricExporterConfigModel, type ExplicitBucketHistogramAggregation as ExplicitBucketHistogramAggregationConfigModel, type ExporterDefaultHistogramAggregation as ExporterDefaultHistogramAggregationConfigModel, type ExporterTemporalityPreference as ExporterTemporalityPreferenceConfigModel, type GrpcTls as GrpcTlsConfigModel, type HttpTls as HttpTlsConfigModel, type IdGenerator as IdGeneratorConfigModel, type InstrumentType as InstrumentTypeConfigModel, type LogRecordExporter as LogRecordExporterConfigModel, type LogRecordLimits as LogRecordLimitsConfigModel, type LogRecordProcessor as LogRecordProcessorConfigModel, type LoggerProvider as LoggerProviderConfigModel, type MeterProvider as MeterProviderConfigModel, type MetricProducer as MetricProducerConfigModel, type MetricReader as MetricReaderConfigModel, type NameStringValuePair as NameStringValuePairConfigModel, type OtlpGrpcExporter as OtlpGrpcExporterConfigModel, type OtlpGrpcMetricExporter as OtlpGrpcMetricExporterConfigModel, type OtlpHttpExporter as OtlpHttpExporterConfigModel, type OtlpHttpMetricExporter as OtlpHttpMetricExporterConfigModel, type ParentBasedSampler as ParentBasedSamplerConfigModel, type PeriodicMetricReader as PeriodicMetricReaderConfigModel, type Propagator as PropagatorConfigModel, type PullMetricExporter as PullMetricExporterConfigModel, type PullMetricReader as PullMetricReaderConfigModel, type PushMetricExporter as PushMetricExporterConfigModel, type Resource as ResourceConfigModel, type Sampler as SamplerConfigModel, type SeverityNumber as SeverityNumberConfigModel, type SimpleLogRecordProcessor as SimpleLogRecordProcessorConfigModel, type SimpleSpanProcessor as SimpleSpanProcessorConfigModel, type SpanExporter as SpanExporterConfigModel, type SpanLimits as SpanLimitsConfigModel, type SpanProcessor as SpanProcessorConfigModel, type TextMapPropagator as TextMapPropagatorConfigModel, type TraceIdRatioBasedSampler as TraceIdRatioBasedSamplerConfigModel, type TracerProvider as TracerProviderConfigModel, type View as ViewConfigModel, createConfigFactory, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig };
2
+ import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile } from "./parse.mjs";
3
+ export { type Aggregation as AggregationConfigModel, type AttributeLimits as AttributeLimitsConfigModel, type Base2ExponentialBucketHistogramAggregation as Base2ExponentialBucketHistogramAggregationConfigModel, type BatchLogRecordProcessor as BatchLogRecordProcessorConfigModel, type BatchSpanProcessor as BatchSpanProcessorConfigModel, type ConfigurationModel, type ConsoleMetricExporter as ConsoleMetricExporterConfigModel, type ExperimentalPrometheusMetricExporter as ExperimentalPrometheusMetricExporterConfigModel, type ExplicitBucketHistogramAggregation as ExplicitBucketHistogramAggregationConfigModel, type ExporterDefaultHistogramAggregation as ExporterDefaultHistogramAggregationConfigModel, type ExporterTemporalityPreference as ExporterTemporalityPreferenceConfigModel, type GrpcTls as GrpcTlsConfigModel, type HttpTls as HttpTlsConfigModel, type IdGenerator as IdGeneratorConfigModel, type InstrumentType as InstrumentTypeConfigModel, type LogRecordExporter as LogRecordExporterConfigModel, type LogRecordLimits as LogRecordLimitsConfigModel, type LogRecordProcessor as LogRecordProcessorConfigModel, type LoggerProvider as LoggerProviderConfigModel, type MeterProvider as MeterProviderConfigModel, type MetricProducer as MetricProducerConfigModel, type MetricReader as MetricReaderConfigModel, type NameStringValuePair as NameStringValuePairConfigModel, type OtlpGrpcExporter as OtlpGrpcExporterConfigModel, type OtlpGrpcMetricExporter as OtlpGrpcMetricExporterConfigModel, type OtlpHttpExporter as OtlpHttpExporterConfigModel, type OtlpHttpMetricExporter as OtlpHttpMetricExporterConfigModel, type ParentBasedSampler as ParentBasedSamplerConfigModel, type PeriodicMetricReader as PeriodicMetricReaderConfigModel, type Propagator as PropagatorConfigModel, type PullMetricExporter as PullMetricExporterConfigModel, type PullMetricReader as PullMetricReaderConfigModel, type PushMetricExporter as PushMetricExporterConfigModel, type Resource as ResourceConfigModel, type Sampler as SamplerConfigModel, type SeverityNumber as SeverityNumberConfigModel, type SimpleLogRecordProcessor as SimpleLogRecordProcessorConfigModel, type SimpleSpanProcessor as SimpleSpanProcessorConfigModel, type SpanExporter as SpanExporterConfigModel, type SpanLimits as SpanLimitsConfigModel, type SpanProcessor as SpanProcessorConfigModel, type TextMapPropagator as TextMapPropagatorConfigModel, type TraceIdRatioBasedSampler as TraceIdRatioBasedSamplerConfigModel, type TracerProvider as TracerProviderConfigModel, type View as ViewConfigModel, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
package/dist/index.mjs CHANGED
@@ -1,3 +1,2 @@
1
- import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig } from "./FileConfigFactory.mjs";
2
- import { createConfigFactory } from "./ConfigFactory.mjs";
3
- export { createConfigFactory, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig };
1
+ import { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile } from "./parse.mjs";
2
+ export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
@@ -1,41 +1,37 @@
1
1
  const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
2
2
  const require_utils = require("./utils.cjs");
3
3
  const require_validator$1 = require("./generated/validator.cjs");
4
- let _opentelemetry_core = require("@opentelemetry/core");
5
4
  let _opentelemetry_api = require("@opentelemetry/api");
6
- let yaml = require("yaml");
7
- yaml = require_runtime.__toESM(yaml);
5
+ let _opentelemetry_core = require("@opentelemetry/core");
8
6
  let fs = require("fs");
9
7
  fs = require_runtime.__toESM(fs);
10
- //#region src/FileConfigFactory.ts
8
+ let yaml = require("yaml");
9
+ yaml = require_runtime.__toESM(yaml);
10
+ //#region src/parse.ts
11
11
  const validateConfig = require_validator$1.default;
12
- var FileConfigFactory = class {
13
- _config;
14
- constructor() {
15
- this._config = parseConfigFile();
16
- }
17
- getConfigModel() {
18
- return this._config;
19
- }
20
- };
21
12
  const SUPPORTED_FILE_FORMAT_MAJOR = 1;
22
13
  const SUPPORTED_FILE_FORMAT_MINOR = 1;
23
- function validateFileFormat(configFile, fileFormat) {
24
- if (typeof fileFormat !== "string" || fileFormat.length === 0) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". Expected a "MAJOR.MINOR" version string.`);
14
+ function validateFileFormat(fileFormat, source) {
15
+ const errPrefix = source ? `${source}: ` : "";
16
+ if (typeof fileFormat !== "string" || fileFormat.length === 0) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". Expected a "MAJOR.MINOR" version string.`);
25
17
  const parts = fileFormat.split("-", 1)[0].split(".");
26
18
  const major = Number(parts[0]);
27
19
  const minor = parts.length > 1 ? Number(parts[1]) : 0;
28
- if (!Number.isInteger(major) || !Number.isInteger(minor)) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". Expected "MAJOR.MINOR" version numbers.`);
29
- if (major !== SUPPORTED_FILE_FORMAT_MAJOR) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`);
30
- if (minor > SUPPORTED_FILE_FORMAT_MINOR) _opentelemetry_api.diag.warn(`${configFile}: Configuration file_format "${fileFormat}" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`);
20
+ if (!Number.isInteger(major) || !Number.isInteger(minor)) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". Expected "MAJOR.MINOR" version numbers.`);
21
+ if (major !== SUPPORTED_FILE_FORMAT_MAJOR) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`);
22
+ if (minor > SUPPORTED_FILE_FORMAT_MINOR) _opentelemetry_api.diag.warn(`${errPrefix}Configuration file_format "${fileFormat}" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`);
23
+ }
24
+ function parseConfigFile(configFile) {
25
+ return parseConfig({
26
+ configYaml: fs.readFileSync(configFile, "utf8"),
27
+ source: configFile
28
+ });
31
29
  }
32
- function parseConfigFile() {
33
- const configFile = (0, _opentelemetry_core.getStringFromEnv)("OTEL_CONFIG_FILE") || "";
34
- const file = fs.readFileSync(configFile, "utf8");
35
- const doc = yaml.parseDocument(file, { version: "1.2" });
30
+ function parseConfig(opts) {
31
+ const doc = yaml.parseDocument(opts.configYaml, { version: "1.2" });
36
32
  require_utils.substituteEnvVars(doc);
37
33
  const processed = doc.toJS();
38
- validateFileFormat(configFile, processed?.file_format);
34
+ validateFileFormat(processed?.file_format, opts.source);
39
35
  if (!validateConfig(processed)) {
40
36
  let detail;
41
37
  if (!validateConfig.errors) detail = "unknown error";
@@ -46,7 +42,8 @@ function parseConfigFile() {
46
42
  const sep = "\n ";
47
43
  detail = sep + validateConfig.errors.map((e) => `${e.instancePath} ${e.message}`).join(sep);
48
44
  }
49
- throw new Error(`Invalid OpenTelemetry config file: ${configFile}: ${detail}`);
45
+ const errPrefix = opts.source ? `${opts.source}: ` : "";
46
+ throw new Error(`Invalid OpenTelemetry config file: ${errPrefix}${detail}`);
50
47
  }
51
48
  const data = processed;
52
49
  delete data["file_format"];
@@ -132,10 +129,10 @@ function mergePropagatorCompositeConfig(composite, composite_list) {
132
129
  return mergedComposite;
133
130
  }
134
131
  //#endregion
135
- exports.FileConfigFactory = FileConfigFactory;
136
132
  exports.mergeHeadersConfig = mergeHeadersConfig;
137
133
  exports.mergePropagatorCompositeConfig = mergePropagatorCompositeConfig;
138
134
  exports.mergeResourceAttributesConfig = mergeResourceAttributesConfig;
135
+ exports.parseConfig = parseConfig;
139
136
  exports.parseConfigFile = parseConfigFile;
140
137
 
141
- //# sourceMappingURL=FileConfigFactory.cjs.map
138
+ //# sourceMappingURL=parse.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.cjs","names":["parseKeyPairsIntoRecord"],"sources":["../src/parse.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { diag } from '@opentelemetry/api';\nimport { parseKeyPairsIntoRecord } from '@opentelemetry/core';\nimport * as fs from 'fs';\nimport * as yaml from 'yaml';\nimport { substituteEnvVars } from './utils';\nimport type {\n AttributeNameValue,\n ConfigurationModel,\n NameStringValuePair,\n TextMapPropagator,\n} from './generated/types';\n// Pre-compiled ajv validator — eliminates runtime schema compilation on cold start.\n// Generated by `npm run generate:config`; do not import ajv directly here.\n// The generated module uses CJS `module.exports = fn`. `import = require` is the\n// only TypeScript form that works equivalently under both CJS and ESM consumers.\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nimport validateConfig = require('./generated/validator');\n\n// The schema version this SDK targets. Per the configuration versioning spec,\n// an implementation MUST reject a config file whose MAJOR version differs (a\n// breaking-change boundary), accepts any MINOR version within that major, and\n// SHOULD warn when the MINOR version is newer than it targets since unknown\n// settings may be ignored. See\n// https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md\nconst SUPPORTED_FILE_FORMAT_MAJOR = 1;\nconst SUPPORTED_FILE_FORMAT_MINOR = 1;\n\nfunction validateFileFormat(fileFormat: unknown, source?: string): void {\n const errPrefix = source ? `${source}: ` : '';\n\n if (typeof fileFormat !== 'string' || fileFormat.length === 0) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". Expected a \"MAJOR.MINOR\" version string.`\n );\n }\n\n // Drop any pre-release / meta tag, e.g. \"1.0-rc.2\" -> \"1.0\".\n const parts = fileFormat.split('-', 1)[0].split('.');\n const major = Number(parts[0]);\n const minor = parts.length > 1 ? Number(parts[1]) : 0;\n if (!Number.isInteger(major) || !Number.isInteger(minor)) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". Expected \"MAJOR.MINOR\" version numbers.`\n );\n }\n\n if (major !== SUPPORTED_FILE_FORMAT_MAJOR) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`\n );\n }\n\n if (minor > SUPPORTED_FILE_FORMAT_MINOR) {\n diag.warn(\n `${errPrefix}Configuration file_format \"${fileFormat}\" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`\n );\n }\n}\n\nexport function parseConfigFile(configFile: string): ConfigurationModel {\n const configYaml = fs.readFileSync(configFile, 'utf8');\n return parseConfig({ configYaml, source: configFile });\n}\n\nexport function parseConfig(opts: {\n configYaml: string;\n source?: string;\n}): ConfigurationModel {\n const doc = yaml.parseDocument(opts.configYaml, { version: '1.2' });\n substituteEnvVars(doc);\n const processed = doc.toJS() as Record<string, unknown>;\n\n validateFileFormat(processed?.file_format, opts.source);\n\n const valid = validateConfig(processed);\n if (!valid) {\n let detail: string;\n if (!validateConfig.errors) {\n detail = 'unknown error';\n } else if (validateConfig.errors.length === 1) {\n const err = validateConfig.errors[0];\n detail = `${err.instancePath} ${err.message}`;\n } else {\n const sep = '\\n ';\n detail =\n sep +\n validateConfig.errors\n .map(e => `${e.instancePath} ${e.message}`)\n .join(sep);\n }\n const errPrefix = opts.source ? `${opts.source}: ` : '';\n throw new Error(`Invalid OpenTelemetry config file: ${errPrefix}${detail}`);\n }\n\n const data = processed as unknown as ConfigurationModel;\n\n // Strip file_format from output — it's a meta-field, not a config value\n delete (data as Record<string, unknown>)['file_format'];\n\n return data;\n}\n\n/**\n * Merge attributes from `resource.attributes` and `resource.attributes_list`\n * (comma-separated key=value pairs) into an `AttributeNameValue[]` array.\n * Entries already in `resource.attributes` taking precedence.\n *\n * Note: The returned array might not be a copy, so it should not be mutated.\n */\nexport function mergeResourceAttributesConfig(\n attributes?: AttributeNameValue[],\n attributes_list?: string | null\n): AttributeNameValue[] | undefined {\n if (!attributes_list) {\n return attributes;\n }\n\n const mergedAttrs = attributes ? attributes.slice() : [];\n const existingNames = new Set(mergedAttrs.map(a => a.name));\n\n let discard = false;\n const listAttrs: Record<string, string> = {};\n for (const pair of attributes_list.split(',')) {\n if (pair.trim() === '') continue;\n\n const parts = pair.split('=');\n if (parts.length !== 2) {\n diag.warn(\n `Invalid format for resource.attributes_list entry \"${pair}\": expected key=value with '=' percent-encoded in keys/values. Discarding all entries.`\n );\n discard = true;\n break;\n }\n\n const rawName = parts[0].trim();\n const rawValue = parts[1].trim();\n if (rawName === '') {\n diag.warn(\n `Empty attribute name in resource.attributes_list entry \"${pair}\". Discarding all entries.`\n );\n discard = true;\n break;\n }\n\n try {\n listAttrs[decodeURIComponent(rawName)] = decodeURIComponent(rawValue);\n } catch (e) {\n diag.warn(\n `Failed to percent-decode resource.attributes_list entry \"${pair}\", discarding all entries: ${e}`\n );\n discard = true;\n break;\n }\n }\n\n if (!discard) {\n for (const [name, value] of Object.entries(listAttrs)) {\n if (!existingNames.has(name)) {\n mergedAttrs.push({ name, value, type: 'string' });\n }\n }\n }\n\n return mergedAttrs;\n}\n\n/**\n * Merge headers from `headers` and `headers_list` (comma-separated key=value\n * pairs) into a record. Entries in `headers` take precedence.\n */\nexport function mergeHeadersConfig(\n headers?: NameStringValuePair[],\n headers_list?: string | null\n): Record<string, string> | undefined {\n if (!headers && !headers_list) {\n return undefined;\n }\n\n const mergedHeaders = parseKeyPairsIntoRecord(headers_list ?? undefined);\n headers?.forEach(header => {\n if (header.value !== null) {\n mergedHeaders[header.name] = header.value;\n }\n });\n return mergedHeaders;\n}\n\n/**\n * Merge propagator.composite_list (comma-separated propagator names) into\n * propagator.composite, with entries already in composite taking precedence.\n * Merge TextMapPropagator configs from `propagator.composite` and `propagator.composite_list`\n * (comma-separated names) into a `TextMapPropagator[]` array.\n * Entries already in `propagator.composite` taking precedence.\n *\n * Note: The returned array might not be a copy, so it should not be mutated.\n */\nexport function mergePropagatorCompositeConfig(\n composite?: TextMapPropagator[],\n composite_list?: string | null\n): TextMapPropagator[] | undefined {\n if (!composite_list) {\n return composite;\n }\n\n const mergedComposite = composite ? composite.slice() : [];\n const existingNames = new Set(mergedComposite.map(c => Object.keys(c)[0]));\n\n for (const name of composite_list.split(',')) {\n const trimmed = name.trim();\n if (trimmed && !existingNames.has(trimmed)) {\n mergedComposite.push({ [trimmed]: null });\n existingNames.add(trimmed);\n }\n }\n\n return mergedComposite;\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { AttributeNameValue, NameStringValuePair, TextMapPropagator } from "./generated/types.cjs";
2
- //#region src/FileConfigFactory.d.ts
1
+ import { AttributeNameValue, ConfigurationModel, NameStringValuePair, TextMapPropagator } from "./generated/types.cjs";
2
+ //#region src/parse.d.ts
3
+ declare function parseConfigFile(configFile: string): ConfigurationModel;
3
4
  /**
4
5
  * Merge attributes from `resource.attributes` and `resource.attributes_list`
5
6
  * (comma-separated key=value pairs) into an `AttributeNameValue[]` array.
@@ -24,5 +25,5 @@ declare function mergeHeadersConfig(headers?: NameStringValuePair[], headers_lis
24
25
  */
25
26
  declare function mergePropagatorCompositeConfig(composite?: TextMapPropagator[], composite_list?: string | null): TextMapPropagator[] | undefined;
26
27
  //#endregion
27
- export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig };
28
- //# sourceMappingURL=FileConfigFactory.d.cts.map
28
+ export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
29
+ //# sourceMappingURL=parse.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.cts","names":[],"sources":["../src/parse.d.ts"],"mappings":";;iBACwB,gBAAgB,qBAAqB;;;;;;;;iBAYrC,8BAA8B,aAAa,sBAAsB,kCAAkC;;;;;iBAKnG,mBAAmB,UAAU,uBAAuB,+BAA+B;;;;;;;;;;iBAUnF,+BAA+B,YAAY,qBAAqB,iCAAiC"}
@@ -1,5 +1,6 @@
1
- import { AttributeNameValue, NameStringValuePair, TextMapPropagator } from "./generated/types.mjs";
2
- //#region src/FileConfigFactory.d.ts
1
+ import { AttributeNameValue, ConfigurationModel, NameStringValuePair, TextMapPropagator } from "./generated/types.mjs";
2
+ //#region src/parse.d.ts
3
+ declare function parseConfigFile(configFile: string): ConfigurationModel;
3
4
  /**
4
5
  * Merge attributes from `resource.attributes` and `resource.attributes_list`
5
6
  * (comma-separated key=value pairs) into an `AttributeNameValue[]` array.
@@ -24,5 +25,5 @@ declare function mergeHeadersConfig(headers?: NameStringValuePair[], headers_lis
24
25
  */
25
26
  declare function mergePropagatorCompositeConfig(composite?: TextMapPropagator[], composite_list?: string | null): TextMapPropagator[] | undefined;
26
27
  //#endregion
27
- export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig };
28
- //# sourceMappingURL=FileConfigFactory.d.mts.map
28
+ export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
29
+ //# sourceMappingURL=parse.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.mts","names":[],"sources":["../src/parse.d.ts"],"mappings":";;iBACwB,gBAAgB,qBAAqB;;;;;;;;iBAYrC,8BAA8B,aAAa,sBAAsB,kCAAkC;;;;;iBAKnG,mBAAmB,UAAU,uBAAuB,+BAA+B;;;;;;;;;;iBAUnF,+BAA+B,YAAY,qBAAqB,iCAAiC"}
@@ -1,38 +1,34 @@
1
1
  import { substituteEnvVars } from "./utils.mjs";
2
2
  import { require_validator } from "./generated/validator.mjs";
3
- import { getStringFromEnv, parseKeyPairsIntoRecord } from "@opentelemetry/core";
4
3
  import { diag } from "@opentelemetry/api";
5
- import * as yaml from "yaml";
4
+ import { parseKeyPairsIntoRecord } from "@opentelemetry/core";
6
5
  import * as fs from "fs";
7
- //#region src/FileConfigFactory.ts
6
+ import * as yaml from "yaml";
7
+ //#region src/parse.ts
8
8
  const validateConfig = require_validator();
9
- var FileConfigFactory = class {
10
- _config;
11
- constructor() {
12
- this._config = parseConfigFile();
13
- }
14
- getConfigModel() {
15
- return this._config;
16
- }
17
- };
18
9
  const SUPPORTED_FILE_FORMAT_MAJOR = 1;
19
10
  const SUPPORTED_FILE_FORMAT_MINOR = 1;
20
- function validateFileFormat(configFile, fileFormat) {
21
- if (typeof fileFormat !== "string" || fileFormat.length === 0) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". Expected a "MAJOR.MINOR" version string.`);
11
+ function validateFileFormat(fileFormat, source) {
12
+ const errPrefix = source ? `${source}: ` : "";
13
+ if (typeof fileFormat !== "string" || fileFormat.length === 0) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". Expected a "MAJOR.MINOR" version string.`);
22
14
  const parts = fileFormat.split("-", 1)[0].split(".");
23
15
  const major = Number(parts[0]);
24
16
  const minor = parts.length > 1 ? Number(parts[1]) : 0;
25
- if (!Number.isInteger(major) || !Number.isInteger(minor)) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". Expected "MAJOR.MINOR" version numbers.`);
26
- if (major !== SUPPORTED_FILE_FORMAT_MAJOR) throw new Error(`${configFile}: Unsupported file_format: "${fileFormat}". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`);
27
- if (minor > SUPPORTED_FILE_FORMAT_MINOR) diag.warn(`${configFile}: Configuration file_format "${fileFormat}" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`);
17
+ if (!Number.isInteger(major) || !Number.isInteger(minor)) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". Expected "MAJOR.MINOR" version numbers.`);
18
+ if (major !== SUPPORTED_FILE_FORMAT_MAJOR) throw new Error(`${errPrefix}Unsupported file_format: "${fileFormat}". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`);
19
+ if (minor > SUPPORTED_FILE_FORMAT_MINOR) diag.warn(`${errPrefix}Configuration file_format "${fileFormat}" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`);
20
+ }
21
+ function parseConfigFile(configFile) {
22
+ return parseConfig({
23
+ configYaml: fs.readFileSync(configFile, "utf8"),
24
+ source: configFile
25
+ });
28
26
  }
29
- function parseConfigFile() {
30
- const configFile = getStringFromEnv("OTEL_CONFIG_FILE") || "";
31
- const file = fs.readFileSync(configFile, "utf8");
32
- const doc = yaml.parseDocument(file, { version: "1.2" });
27
+ function parseConfig(opts) {
28
+ const doc = yaml.parseDocument(opts.configYaml, { version: "1.2" });
33
29
  substituteEnvVars(doc);
34
30
  const processed = doc.toJS();
35
- validateFileFormat(configFile, processed?.file_format);
31
+ validateFileFormat(processed?.file_format, opts.source);
36
32
  if (!validateConfig(processed)) {
37
33
  let detail;
38
34
  if (!validateConfig.errors) detail = "unknown error";
@@ -43,7 +39,8 @@ function parseConfigFile() {
43
39
  const sep = "\n ";
44
40
  detail = sep + validateConfig.errors.map((e) => `${e.instancePath} ${e.message}`).join(sep);
45
41
  }
46
- throw new Error(`Invalid OpenTelemetry config file: ${configFile}: ${detail}`);
42
+ const errPrefix = opts.source ? `${opts.source}: ` : "";
43
+ throw new Error(`Invalid OpenTelemetry config file: ${errPrefix}${detail}`);
47
44
  }
48
45
  const data = processed;
49
46
  delete data["file_format"];
@@ -129,6 +126,6 @@ function mergePropagatorCompositeConfig(composite, composite_list) {
129
126
  return mergedComposite;
130
127
  }
131
128
  //#endregion
132
- export { FileConfigFactory, mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfigFile };
129
+ export { mergeHeadersConfig, mergePropagatorCompositeConfig, mergeResourceAttributesConfig, parseConfig, parseConfigFile };
133
130
 
134
- //# sourceMappingURL=FileConfigFactory.mjs.map
131
+ //# sourceMappingURL=parse.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.mjs","names":[],"sources":["../src/parse.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { diag } from '@opentelemetry/api';\nimport { parseKeyPairsIntoRecord } from '@opentelemetry/core';\nimport * as fs from 'fs';\nimport * as yaml from 'yaml';\nimport { substituteEnvVars } from './utils';\nimport type {\n AttributeNameValue,\n ConfigurationModel,\n NameStringValuePair,\n TextMapPropagator,\n} from './generated/types';\n// Pre-compiled ajv validator — eliminates runtime schema compilation on cold start.\n// Generated by `npm run generate:config`; do not import ajv directly here.\n// The generated module uses CJS `module.exports = fn`. `import = require` is the\n// only TypeScript form that works equivalently under both CJS and ESM consumers.\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nimport validateConfig = require('./generated/validator');\n\n// The schema version this SDK targets. Per the configuration versioning spec,\n// an implementation MUST reject a config file whose MAJOR version differs (a\n// breaking-change boundary), accepts any MINOR version within that major, and\n// SHOULD warn when the MINOR version is newer than it targets since unknown\n// settings may be ignored. See\n// https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md\nconst SUPPORTED_FILE_FORMAT_MAJOR = 1;\nconst SUPPORTED_FILE_FORMAT_MINOR = 1;\n\nfunction validateFileFormat(fileFormat: unknown, source?: string): void {\n const errPrefix = source ? `${source}: ` : '';\n\n if (typeof fileFormat !== 'string' || fileFormat.length === 0) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". Expected a \"MAJOR.MINOR\" version string.`\n );\n }\n\n // Drop any pre-release / meta tag, e.g. \"1.0-rc.2\" -> \"1.0\".\n const parts = fileFormat.split('-', 1)[0].split('.');\n const major = Number(parts[0]);\n const minor = parts.length > 1 ? Number(parts[1]) : 0;\n if (!Number.isInteger(major) || !Number.isInteger(minor)) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". Expected \"MAJOR.MINOR\" version numbers.`\n );\n }\n\n if (major !== SUPPORTED_FILE_FORMAT_MAJOR) {\n throw new Error(\n `${errPrefix}Unsupported file_format: \"${fileFormat}\". This SDK supports schema version ${SUPPORTED_FILE_FORMAT_MAJOR}.x.`\n );\n }\n\n if (minor > SUPPORTED_FILE_FORMAT_MINOR) {\n diag.warn(\n `${errPrefix}Configuration file_format \"${fileFormat}\" has a newer minor version than this SDK supports (${SUPPORTED_FILE_FORMAT_MAJOR}.${SUPPORTED_FILE_FORMAT_MINOR}); some settings may be ignored.`\n );\n }\n}\n\nexport function parseConfigFile(configFile: string): ConfigurationModel {\n const configYaml = fs.readFileSync(configFile, 'utf8');\n return parseConfig({ configYaml, source: configFile });\n}\n\nexport function parseConfig(opts: {\n configYaml: string;\n source?: string;\n}): ConfigurationModel {\n const doc = yaml.parseDocument(opts.configYaml, { version: '1.2' });\n substituteEnvVars(doc);\n const processed = doc.toJS() as Record<string, unknown>;\n\n validateFileFormat(processed?.file_format, opts.source);\n\n const valid = validateConfig(processed);\n if (!valid) {\n let detail: string;\n if (!validateConfig.errors) {\n detail = 'unknown error';\n } else if (validateConfig.errors.length === 1) {\n const err = validateConfig.errors[0];\n detail = `${err.instancePath} ${err.message}`;\n } else {\n const sep = '\\n ';\n detail =\n sep +\n validateConfig.errors\n .map(e => `${e.instancePath} ${e.message}`)\n .join(sep);\n }\n const errPrefix = opts.source ? `${opts.source}: ` : '';\n throw new Error(`Invalid OpenTelemetry config file: ${errPrefix}${detail}`);\n }\n\n const data = processed as unknown as ConfigurationModel;\n\n // Strip file_format from output — it's a meta-field, not a config value\n delete (data as Record<string, unknown>)['file_format'];\n\n return data;\n}\n\n/**\n * Merge attributes from `resource.attributes` and `resource.attributes_list`\n * (comma-separated key=value pairs) into an `AttributeNameValue[]` array.\n * Entries already in `resource.attributes` taking precedence.\n *\n * Note: The returned array might not be a copy, so it should not be mutated.\n */\nexport function mergeResourceAttributesConfig(\n attributes?: AttributeNameValue[],\n attributes_list?: string | null\n): AttributeNameValue[] | undefined {\n if (!attributes_list) {\n return attributes;\n }\n\n const mergedAttrs = attributes ? attributes.slice() : [];\n const existingNames = new Set(mergedAttrs.map(a => a.name));\n\n let discard = false;\n const listAttrs: Record<string, string> = {};\n for (const pair of attributes_list.split(',')) {\n if (pair.trim() === '') continue;\n\n const parts = pair.split('=');\n if (parts.length !== 2) {\n diag.warn(\n `Invalid format for resource.attributes_list entry \"${pair}\": expected key=value with '=' percent-encoded in keys/values. Discarding all entries.`\n );\n discard = true;\n break;\n }\n\n const rawName = parts[0].trim();\n const rawValue = parts[1].trim();\n if (rawName === '') {\n diag.warn(\n `Empty attribute name in resource.attributes_list entry \"${pair}\". Discarding all entries.`\n );\n discard = true;\n break;\n }\n\n try {\n listAttrs[decodeURIComponent(rawName)] = decodeURIComponent(rawValue);\n } catch (e) {\n diag.warn(\n `Failed to percent-decode resource.attributes_list entry \"${pair}\", discarding all entries: ${e}`\n );\n discard = true;\n break;\n }\n }\n\n if (!discard) {\n for (const [name, value] of Object.entries(listAttrs)) {\n if (!existingNames.has(name)) {\n mergedAttrs.push({ name, value, type: 'string' });\n }\n }\n }\n\n return mergedAttrs;\n}\n\n/**\n * Merge headers from `headers` and `headers_list` (comma-separated key=value\n * pairs) into a record. Entries in `headers` take precedence.\n */\nexport function mergeHeadersConfig(\n headers?: NameStringValuePair[],\n headers_list?: string | null\n): Record<string, string> | undefined {\n if (!headers && !headers_list) {\n return undefined;\n }\n\n const mergedHeaders = parseKeyPairsIntoRecord(headers_list ?? undefined);\n headers?.forEach(header => {\n if (header.value !== null) {\n mergedHeaders[header.name] = header.value;\n }\n });\n return mergedHeaders;\n}\n\n/**\n * Merge propagator.composite_list (comma-separated propagator names) into\n * propagator.composite, with entries already in composite taking precedence.\n * Merge TextMapPropagator configs from `propagator.composite` and `propagator.composite_list`\n * (comma-separated names) into a `TextMapPropagator[]` array.\n * Entries already in `propagator.composite` taking precedence.\n *\n * Note: The returned array might not be a copy, so it should not be mutated.\n */\nexport function mergePropagatorCompositeConfig(\n composite?: TextMapPropagator[],\n composite_list?: string | null\n): TextMapPropagator[] | undefined {\n if (!composite_list) {\n return composite;\n }\n\n const mergedComposite = composite ? composite.slice() : [];\n const existingNames = new Set(mergedComposite.map(c => Object.keys(c)[0]));\n\n for (const name of composite_list.split(',')) {\n const trimmed = name.trim();\n if (trimmed && !existingNames.has(trimmed)) {\n mergedComposite.push({ [trimmed]: null });\n existingNames.add(trimmed);\n }\n }\n\n return mergedComposite;\n}\n"],"mappings":"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"}
package/dist/utils.cjs CHANGED
@@ -71,67 +71,7 @@ function yamlScalarCoerce(value) {
71
71
  if (coerced === null || type === "number" || type === "boolean") return coerced;
72
72
  else return value;
73
73
  }
74
- function getGrpcTlsConfig(certificateFile, clientKeyFile, clientCertificateFile, insecure) {
75
- if (certificateFile || clientKeyFile || clientCertificateFile) {
76
- const tls = {};
77
- if (certificateFile) tls.ca_file = certificateFile;
78
- if (clientKeyFile) tls.key_file = clientKeyFile;
79
- if (clientCertificateFile) tls.cert_file = clientCertificateFile;
80
- if (insecure !== void 0) tls.insecure = insecure;
81
- return tls;
82
- }
83
- }
84
- function initializeDefaultConfiguration() {
85
- return {
86
- disabled: false,
87
- log_level: "info",
88
- resource: {},
89
- attribute_limits: { attribute_count_limit: 128 }
90
- };
91
- }
92
- function initializeDefaultTracerProviderConfiguration() {
93
- return {
94
- processors: [],
95
- limits: {
96
- attribute_count_limit: 128,
97
- event_count_limit: 128,
98
- link_count_limit: 128,
99
- event_attribute_count_limit: 128,
100
- link_attribute_count_limit: 128
101
- },
102
- sampler: { parent_based: { root: { always_on: null } } }
103
- };
104
- }
105
- function initializeDefaultMeterProviderConfiguration() {
106
- return {
107
- readers: [],
108
- views: [],
109
- exemplar_filter: "trace_based"
110
- };
111
- }
112
- function initializeDefaultLoggerProviderConfiguration() {
113
- return {
114
- processors: [],
115
- limits: { attribute_count_limit: 128 },
116
- "logger_configurator/development": {}
117
- };
118
- }
119
- function getHttpTlsConfig(certificateFile, clientKeyFile, clientCertificateFile) {
120
- if (certificateFile || clientKeyFile || clientCertificateFile) {
121
- const tls = {};
122
- if (certificateFile) tls.ca_file = certificateFile;
123
- if (clientKeyFile) tls.key_file = clientKeyFile;
124
- if (clientCertificateFile) tls.cert_file = clientCertificateFile;
125
- return tls;
126
- }
127
- }
128
74
  //#endregion
129
- exports.getGrpcTlsConfig = getGrpcTlsConfig;
130
- exports.getHttpTlsConfig = getHttpTlsConfig;
131
- exports.initializeDefaultConfiguration = initializeDefaultConfiguration;
132
- exports.initializeDefaultLoggerProviderConfiguration = initializeDefaultLoggerProviderConfiguration;
133
- exports.initializeDefaultMeterProviderConfiguration = initializeDefaultMeterProviderConfiguration;
134
- exports.initializeDefaultTracerProviderConfiguration = initializeDefaultTracerProviderConfiguration;
135
75
  exports.substituteEnvVars = substituteEnvVars;
136
76
 
137
77
  //# sourceMappingURL=utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","names":["getStringFromEnv"],"sources":["../src/utils.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport * as yaml from 'yaml';\nimport { getStringFromEnv } from '@opentelemetry/core';\nimport type { ConfigurationModel, GrpcTls, HttpTls } from './generated/types';\n\n/**\n * Handle (Environment) variable substitution per\n * https://opentelemetry.io/docs/specs/otel/configuration/data-model/#environment-variable-substitution\n *\n * This changes the yaml.Document in-place.\n * This must work with a yaml.Document, rather than a raw JS object from\n * `yaml.parse()`, to distinguish between `foo: ${BAR}` and `foo: \"${BAR}\"`.\n *\n * Exported for testing.\n */\nexport function substituteEnvVars(doc: yaml.Document) {\n // Visit each scalar string value in the document. These are\n // the candidates for env var substitution.\n yaml.visit(doc, {\n Scalar: (key, node, _path) => {\n if (key === 'key') return; // skip mapping keys\n if (typeof node.value !== 'string') return;\n let subbed: string | null | number | boolean = envVarSubst(node.value);\n if (subbed !== node.value && node.type === yaml.Scalar.PLAIN) {\n // \"PLAIN\" here is a simple YAML value (e.g. 42 in `foo: 42`).\n // I.e., not quoted (`foo: \"42\"`) or in a block.\n subbed = yamlScalarCoerce(subbed);\n }\n node.value = subbed;\n },\n });\n}\n\n// ENV_SUBSTITUTION_RE *mostly* matches the `ENV-SUBSTITUTION` ABNF from the\n// spec with the exception of the DEFAULT-VALUE: we are using `[^\\n}]*`\n// (copying the OTel Java regex) rather than a regex closer to ABNF\n// `*(VCHAR-WSP-NO-RBRACE)` (which is slightly ambiguous on what whitespace is\n// allowed in WSP).\nconst ENV_SUBSTITUTION_RE = /^([a-zA-Z_][a-zA-Z0-9_]*)(?::-([^\\n}]*))?$/;\n\n/**\n * Do environment variable substitution for the given string value.\n */\nfunction envVarSubst(s: string): string {\n const ESCAPE_RE = /(\\$\\$)/;\n const chunks = s.split(ESCAPE_RE);\n for (let i = 0; i < chunks.length; ++i) {\n if (i % 2 === 1) {\n // Odd chunks are matched escape sequences, i.e. '$$'.\n chunks[i] = '$';\n continue;\n }\n\n // Even chunks are processed for possible substition matches.\n const SUBSTITUTION_REF_RE = /\\$\\{(?:env:)?([^}]+)\\}/g;\n let chunk = '';\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = SUBSTITUTION_REF_RE.exec(chunks[i])) !== null) {\n chunk += chunks[i].slice(lastIndex, match.index);\n const envMatch = ENV_SUBSTITUTION_RE.exec(match[1]);\n if (!envMatch) {\n // E.g.: `key: ${STRING_VALUE:?error}` test case\n throw new Error(\n `parse error: invalid env var substitution: ${match[0]}`\n );\n }\n const envName = envMatch[1];\n const defaultValue = envMatch[2] ?? '';\n chunk += getStringFromEnv(envName) || defaultValue;\n lastIndex = SUBSTITUTION_REF_RE.lastIndex;\n }\n chunk += chunks[i].slice(lastIndex);\n chunks[i] = chunk;\n }\n\n const result = chunks.join('');\n return result;\n}\n\n/**\n * Re-interpret a string value from env var substitution as a possible\n * YAML number, boolean, or null value.\n *\n * If the interpretted value is any other type, we return the original\n * string:\n * - sequences and mappings may not result from env var substitution, per the spec\n * - a re-parsed YAML string normalizes whitespace, which we do not want\n */\nfunction yamlScalarCoerce(value: string): string | null | number | boolean {\n let coerced;\n try {\n coerced = yaml.parse(value, { version: '1.2' });\n } catch {\n return value;\n }\n const type = typeof coerced;\n if (coerced === null || type === 'number' || type === 'boolean') {\n return coerced;\n } else {\n return value;\n }\n}\n\nexport function getGrpcTlsConfig(\n certificateFile?: string,\n clientKeyFile?: string,\n clientCertificateFile?: string,\n insecure?: boolean\n): GrpcTls | undefined {\n if (certificateFile || clientKeyFile || clientCertificateFile) {\n const tls: GrpcTls = {};\n if (certificateFile) {\n tls.ca_file = certificateFile;\n }\n if (clientKeyFile) {\n tls.key_file = clientKeyFile;\n }\n if (clientCertificateFile) {\n tls.cert_file = clientCertificateFile;\n }\n if (insecure !== undefined) {\n tls.insecure = insecure;\n }\n return tls;\n }\n return undefined;\n}\n\nexport function initializeDefaultConfiguration(): ConfigurationModel {\n return {\n disabled: false,\n log_level: 'info',\n resource: {},\n attribute_limits: {\n attribute_count_limit: 128,\n },\n };\n}\n\nexport function initializeDefaultTracerProviderConfiguration(): NonNullable<\n ConfigurationModel['tracer_provider']\n> {\n return {\n processors: [],\n limits: {\n attribute_count_limit: 128,\n event_count_limit: 128,\n link_count_limit: 128,\n event_attribute_count_limit: 128,\n link_attribute_count_limit: 128,\n },\n sampler: {\n parent_based: {\n root: { always_on: null },\n },\n },\n };\n}\n\nexport function initializeDefaultMeterProviderConfiguration(): NonNullable<\n ConfigurationModel['meter_provider']\n> {\n return {\n readers: [],\n views: [],\n exemplar_filter: 'trace_based',\n };\n}\n\nexport function initializeDefaultLoggerProviderConfiguration(): NonNullable<\n ConfigurationModel['logger_provider']\n> {\n return {\n processors: [],\n limits: { attribute_count_limit: 128 },\n 'logger_configurator/development': {},\n };\n}\n\nexport function getHttpTlsConfig(\n certificateFile?: string,\n clientKeyFile?: string,\n clientCertificateFile?: string\n): HttpTls | undefined {\n if (certificateFile || clientKeyFile || clientCertificateFile) {\n const tls: HttpTls = {};\n if (certificateFile) {\n tls.ca_file = certificateFile;\n }\n if (clientKeyFile) {\n tls.key_file = clientKeyFile;\n }\n if (clientCertificateFile) {\n tls.cert_file = clientCertificateFile;\n }\n return tls;\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,SAAgB,kBAAkB,KAAoB;CAGpD,KAAK,MAAM,KAAK,EACd,SAAS,KAAK,MAAM,UAAU;EAC5B,IAAI,QAAQ,OAAO;EACnB,IAAI,OAAO,KAAK,UAAU,UAAU;EACpC,IAAI,SAA2C,YAAY,KAAK,KAAK;EACrE,IAAI,WAAW,KAAK,SAAS,KAAK,SAAS,KAAK,OAAO,OAGrD,SAAS,iBAAiB,MAAM;EAElC,KAAK,QAAQ;CACf,EACF,CAAC;AACH;AAOA,MAAM,sBAAsB;;;;AAK5B,SAAS,YAAY,GAAmB;CAEtC,MAAM,SAAS,EAAE,MAAM,QAAS;CAChC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,EAAE,GAAG;EACtC,IAAI,IAAI,MAAM,GAAG;GAEf,OAAO,KAAK;GACZ;EACF;EAGA,MAAM,sBAAsB;EAC5B,IAAI,QAAQ;EACZ,IAAI,YAAY;EAChB,IAAI;EACJ,QAAQ,QAAQ,oBAAoB,KAAK,OAAO,EAAE,OAAO,MAAM;GAC7D,SAAS,OAAO,EAAE,CAAC,MAAM,WAAW,MAAM,KAAK;GAC/C,MAAM,WAAW,oBAAoB,KAAK,MAAM,EAAE;GAClD,IAAI,CAAC,UAEH,MAAM,IAAI,MACR,8CAA8C,MAAM,IACtD;GAEF,MAAM,UAAU,SAAS;GACzB,MAAM,eAAe,SAAS,MAAM;GACpC,UAAA,GAASA,oBAAAA,iBAAAA,CAAiB,OAAO,KAAK;GACtC,YAAY,oBAAoB;EAClC;EACA,SAAS,OAAO,EAAE,CAAC,MAAM,SAAS;EAClC,OAAO,KAAK;CACd;CAGA,OADe,OAAO,KAAK,EACf;AACd;;;;;;;;;;AAWA,SAAS,iBAAiB,OAAiD;CACzE,IAAI;CACJ,IAAI;EACF,UAAU,KAAK,MAAM,OAAO,EAAE,SAAS,MAAM,CAAC;CAChD,QAAQ;EACN,OAAO;CACT;CACA,MAAM,OAAO,OAAO;CACpB,IAAI,YAAY,QAAQ,SAAS,YAAY,SAAS,WACpD,OAAO;MAEP,OAAO;AAEX;AAEA,SAAgB,iBACd,iBACA,eACA,uBACA,UACqB;CACrB,IAAI,mBAAmB,iBAAiB,uBAAuB;EAC7D,MAAM,MAAe,CAAC;EACtB,IAAI,iBACF,IAAI,UAAU;EAEhB,IAAI,eACF,IAAI,WAAW;EAEjB,IAAI,uBACF,IAAI,YAAY;EAElB,IAAI,aAAa,KAAA,GACf,IAAI,WAAW;EAEjB,OAAO;CACT;AAEF;AAEA,SAAgB,iCAAqD;CACnE,OAAO;EACL,UAAU;EACV,WAAW;EACX,UAAU,CAAC;EACX,kBAAkB,EAChB,uBAAuB,IACzB;CACF;AACF;AAEA,SAAgB,+CAEd;CACA,OAAO;EACL,YAAY,CAAC;EACb,QAAQ;GACN,uBAAuB;GACvB,mBAAmB;GACnB,kBAAkB;GAClB,6BAA6B;GAC7B,4BAA4B;EAC9B;EACA,SAAS,EACP,cAAc,EACZ,MAAM,EAAE,WAAW,KAAK,EAC1B,EACF;CACF;AACF;AAEA,SAAgB,8CAEd;CACA,OAAO;EACL,SAAS,CAAC;EACV,OAAO,CAAC;EACR,iBAAiB;CACnB;AACF;AAEA,SAAgB,+CAEd;CACA,OAAO;EACL,YAAY,CAAC;EACb,QAAQ,EAAE,uBAAuB,IAAI;EACrC,mCAAmC,CAAC;CACtC;AACF;AAEA,SAAgB,iBACd,iBACA,eACA,uBACqB;CACrB,IAAI,mBAAmB,iBAAiB,uBAAuB;EAC7D,MAAM,MAAe,CAAC;EACtB,IAAI,iBACF,IAAI,UAAU;EAEhB,IAAI,eACF,IAAI,WAAW;EAEjB,IAAI,uBACF,IAAI,YAAY;EAElB,OAAO;CACT;AAEF"}
1
+ {"version":3,"file":"utils.cjs","names":["getStringFromEnv"],"sources":["../src/utils.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport * as yaml from 'yaml';\nimport { getStringFromEnv } from '@opentelemetry/core';\n\n/**\n * Handle (Environment) variable substitution per\n * https://opentelemetry.io/docs/specs/otel/configuration/data-model/#environment-variable-substitution\n *\n * This changes the yaml.Document in-place.\n * This must work with a yaml.Document, rather than a raw JS object from\n * `yaml.parse()`, to distinguish between `foo: ${BAR}` and `foo: \"${BAR}\"`.\n *\n * Exported for testing.\n */\nexport function substituteEnvVars(doc: yaml.Document) {\n // Visit each scalar string value in the document. These are\n // the candidates for env var substitution.\n yaml.visit(doc, {\n Scalar: (key, node, _path) => {\n if (key === 'key') return; // skip mapping keys\n if (typeof node.value !== 'string') return;\n let subbed: string | null | number | boolean = envVarSubst(node.value);\n if (subbed !== node.value && node.type === yaml.Scalar.PLAIN) {\n // \"PLAIN\" here is a simple YAML value (e.g. 42 in `foo: 42`).\n // I.e., not quoted (`foo: \"42\"`) or in a block.\n subbed = yamlScalarCoerce(subbed);\n }\n node.value = subbed;\n },\n });\n}\n\n// ENV_SUBSTITUTION_RE *mostly* matches the `ENV-SUBSTITUTION` ABNF from the\n// spec with the exception of the DEFAULT-VALUE: we are using `[^\\n}]*`\n// (copying the OTel Java regex) rather than a regex closer to ABNF\n// `*(VCHAR-WSP-NO-RBRACE)` (which is slightly ambiguous on what whitespace is\n// allowed in WSP).\nconst ENV_SUBSTITUTION_RE = /^([a-zA-Z_][a-zA-Z0-9_]*)(?::-([^\\n}]*))?$/;\n\n/**\n * Do environment variable substitution for the given string value.\n */\nfunction envVarSubst(s: string): string {\n const ESCAPE_RE = /(\\$\\$)/;\n const chunks = s.split(ESCAPE_RE);\n for (let i = 0; i < chunks.length; ++i) {\n if (i % 2 === 1) {\n // Odd chunks are matched escape sequences, i.e. '$$'.\n chunks[i] = '$';\n continue;\n }\n\n // Even chunks are processed for possible substition matches.\n const SUBSTITUTION_REF_RE = /\\$\\{(?:env:)?([^}]+)\\}/g;\n let chunk = '';\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = SUBSTITUTION_REF_RE.exec(chunks[i])) !== null) {\n chunk += chunks[i].slice(lastIndex, match.index);\n const envMatch = ENV_SUBSTITUTION_RE.exec(match[1]);\n if (!envMatch) {\n // E.g.: `key: ${STRING_VALUE:?error}` test case\n throw new Error(\n `parse error: invalid env var substitution: ${match[0]}`\n );\n }\n const envName = envMatch[1];\n const defaultValue = envMatch[2] ?? '';\n chunk += getStringFromEnv(envName) || defaultValue;\n lastIndex = SUBSTITUTION_REF_RE.lastIndex;\n }\n chunk += chunks[i].slice(lastIndex);\n chunks[i] = chunk;\n }\n\n const result = chunks.join('');\n return result;\n}\n\n/**\n * Re-interpret a string value from env var substitution as a possible\n * YAML number, boolean, or null value.\n *\n * If the interpretted value is any other type, we return the original\n * string:\n * - sequences and mappings may not result from env var substitution, per the spec\n * - a re-parsed YAML string normalizes whitespace, which we do not want\n */\nfunction yamlScalarCoerce(value: string): string | null | number | boolean {\n let coerced;\n try {\n coerced = yaml.parse(value, { version: '1.2' });\n } catch {\n return value;\n }\n const type = typeof coerced;\n if (coerced === null || type === 'number' || type === 'boolean') {\n return coerced;\n } else {\n return value;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,SAAgB,kBAAkB,KAAoB;CAGpD,KAAK,MAAM,KAAK,EACd,SAAS,KAAK,MAAM,UAAU;EAC5B,IAAI,QAAQ,OAAO;EACnB,IAAI,OAAO,KAAK,UAAU,UAAU;EACpC,IAAI,SAA2C,YAAY,KAAK,KAAK;EACrE,IAAI,WAAW,KAAK,SAAS,KAAK,SAAS,KAAK,OAAO,OAGrD,SAAS,iBAAiB,MAAM;EAElC,KAAK,QAAQ;CACf,EACF,CAAC;AACH;AAOA,MAAM,sBAAsB;;;;AAK5B,SAAS,YAAY,GAAmB;CAEtC,MAAM,SAAS,EAAE,MAAM,QAAS;CAChC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,EAAE,GAAG;EACtC,IAAI,IAAI,MAAM,GAAG;GAEf,OAAO,KAAK;GACZ;EACF;EAGA,MAAM,sBAAsB;EAC5B,IAAI,QAAQ;EACZ,IAAI,YAAY;EAChB,IAAI;EACJ,QAAQ,QAAQ,oBAAoB,KAAK,OAAO,EAAE,OAAO,MAAM;GAC7D,SAAS,OAAO,EAAE,CAAC,MAAM,WAAW,MAAM,KAAK;GAC/C,MAAM,WAAW,oBAAoB,KAAK,MAAM,EAAE;GAClD,IAAI,CAAC,UAEH,MAAM,IAAI,MACR,8CAA8C,MAAM,IACtD;GAEF,MAAM,UAAU,SAAS;GACzB,MAAM,eAAe,SAAS,MAAM;GACpC,UAAA,GAASA,oBAAAA,iBAAAA,CAAiB,OAAO,KAAK;GACtC,YAAY,oBAAoB;EAClC;EACA,SAAS,OAAO,EAAE,CAAC,MAAM,SAAS;EAClC,OAAO,KAAK;CACd;CAGA,OADe,OAAO,KAAK,EACf;AACd;;;;;;;;;;AAWA,SAAS,iBAAiB,OAAiD;CACzE,IAAI;CACJ,IAAI;EACF,UAAU,KAAK,MAAM,OAAO,EAAE,SAAS,MAAM,CAAC;CAChD,QAAQ;EACN,OAAO;CACT;CACA,MAAM,OAAO,OAAO;CACpB,IAAI,YAAY,QAAQ,SAAS,YAAY,SAAS,WACpD,OAAO;MAEP,OAAO;AAEX"}