@opentelemetry/sdk-node 0.219.0 → 0.221.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.
- package/README.md +31 -9
- package/build/src/create-from-config.d.ts +11 -0
- package/build/src/create-from-config.js +207 -0
- package/build/src/create-from-config.js.map +1 -0
- package/build/src/create-from-env.d.ts +11 -0
- package/build/src/create-from-env.js +80 -0
- package/build/src/create-from-env.js.map +1 -0
- package/build/src/index.d.ts +7 -1
- package/build/src/index.js +8 -2
- package/build/src/index.js.map +1 -1
- package/build/src/sdk.d.ts +0 -1
- package/build/src/sdk.js +36 -38
- package/build/src/sdk.js.map +1 -1
- package/build/src/start.js +65 -51
- package/build/src/start.js.map +1 -1
- package/build/src/types.d.ts +12 -4
- package/build/src/types.js.map +1 -1
- package/build/src/utils.d.ts +24 -11
- package/build/src/utils.js +241 -195
- package/build/src/utils.js.map +1 -1
- package/build/src/version.d.ts +1 -1
- package/build/src/version.js +1 -1
- package/build/src/version.js.map +1 -1
- package/package.json +30 -29
package/README.md
CHANGED
|
@@ -103,11 +103,6 @@ Deprecated, please use [logRecordProcessors](#logrecordprocessors) instead.
|
|
|
103
103
|
|
|
104
104
|
An array of log record processors to register to the logger provider.
|
|
105
105
|
|
|
106
|
-
### mergeResourceWithDefaults
|
|
107
|
-
|
|
108
|
-
Merge user-provided resources with the default resource. Default `true`.
|
|
109
|
-
The default will change to `false` in a future iteration of this package.
|
|
110
|
-
|
|
111
106
|
### metricReader
|
|
112
107
|
|
|
113
108
|
Add a [MetricReader](../../../packages/sdk-metrics/src/export/MetricReader.ts)
|
|
@@ -128,7 +123,34 @@ or configure each instrumentation individually.
|
|
|
128
123
|
|
|
129
124
|
### resource
|
|
130
125
|
|
|
131
|
-
|
|
126
|
+
A [Resource](https://opentelemetry.io/docs/specs/otel/resource/sdk/) to associate with generated telemetry.
|
|
127
|
+
This resource will be use as the basis for additional resource attributes determined by [resource detectors](#resourcedetectors).
|
|
128
|
+
See also the [`autoDetectResources` setting](#autodetectresources).
|
|
129
|
+
|
|
130
|
+
If not specified, the [default resource](https://opentelemetry.io/docs/specs/semconv/resource/#semantic-attributes-with-sdk-provided-default-value) will be used.
|
|
131
|
+
|
|
132
|
+
> [!WARNING]
|
|
133
|
+
> If specifying the `resource` option, it is recommended that the default resource be included.
|
|
134
|
+
> Otherwise the important `service.name` and `telemetry.sdk.*` resource attributes might not be included on telemetry,
|
|
135
|
+
> which can adversely impact downstream processing or visualization.
|
|
136
|
+
> The default resource can be include as follows:
|
|
137
|
+
>
|
|
138
|
+
> ```js
|
|
139
|
+
> import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
140
|
+
> import { resourceFromAttributes, defaultResource } from '@opentelemetry/resources';
|
|
141
|
+
> const sdk = new NodeSDK({
|
|
142
|
+
> resource: defaultResource().merge(
|
|
143
|
+
> resourceFromAttributes({
|
|
144
|
+
> 'my.custom.attr': 'some value',
|
|
145
|
+
> })
|
|
146
|
+
> ),
|
|
147
|
+
> // ...
|
|
148
|
+
> });
|
|
149
|
+
> ```
|
|
150
|
+
>
|
|
151
|
+
> Alternatively, consider setting custom resource attributes via the
|
|
152
|
+
> [`OTEL_RESOURCE_ATTRIBUTES`](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration)
|
|
153
|
+
> environment variable.
|
|
132
154
|
|
|
133
155
|
### resourceDetectors
|
|
134
156
|
|
|
@@ -174,11 +196,11 @@ An array of span processors to register to the tracer provider.
|
|
|
174
196
|
|
|
175
197
|
### traceExporter
|
|
176
198
|
|
|
177
|
-
Configure a trace exporter. If an exporter is configured, it will be used with a [BatchSpanProcessor](../../../packages/
|
|
199
|
+
Configure a trace exporter. If an exporter is configured, it will be used with a [BatchSpanProcessor](../../../packages/sdk-trace/src/platform/node/export/BatchSpanProcessor.ts). If an exporter OR span processor is not configured programmatically, this package will auto setup the default `otlp` exporter with `http/protobuf` protocol with a `BatchSpanProcessor`.
|
|
178
200
|
|
|
179
201
|
### spanLimits
|
|
180
202
|
|
|
181
|
-
Configure tracing parameters. These are the same trace parameters used to [configure a tracer](../../../packages/
|
|
203
|
+
Configure tracing parameters. These are the same trace parameters used to [configure a tracer](../../../packages/sdk-trace/src/types.ts#L20).
|
|
182
204
|
|
|
183
205
|
### serviceName
|
|
184
206
|
|
|
@@ -245,7 +267,7 @@ linkes for details:
|
|
|
245
267
|
|
|
246
268
|
- Metric reader metrics: [MetricReaderMetrics](../../../packages//sdk-metrics/src/export/MetricReaderMetrics.ts)
|
|
247
269
|
- Logger metrics: [LoggerMetrics.ts](../sdk-logs/src/LoggerMetrics.ts)
|
|
248
|
-
- Span metrics: [TracerMetrics.ts](../../../packages/
|
|
270
|
+
- Span metrics: [TracerMetrics.ts](../../../packages/sdk-trace/src/TracerMetrics.ts)
|
|
249
271
|
|
|
250
272
|
## Useful links
|
|
251
273
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SpanLimits } from '@opentelemetry/sdk-trace';
|
|
2
|
+
import type { Resource } from '@opentelemetry/resources';
|
|
3
|
+
import type { AttributeLimitsConfigModel, LoggerProviderConfigModel, LogRecordExporterConfigModel, LogRecordLimitsConfigModel, LogRecordProcessorConfigModel, SpanLimitsConfigModel } from '@opentelemetry/configuration';
|
|
4
|
+
import type { LogRecordExporter, LogRecordProcessor, LogRecordLimits } from '@opentelemetry/sdk-logs';
|
|
5
|
+
import { LoggerProvider } from '@opentelemetry/sdk-logs';
|
|
6
|
+
export declare function createLogRecordLimitsFromConfig(limits?: LogRecordLimitsConfigModel, attribute_limits?: AttributeLimitsConfigModel): LogRecordLimits | undefined;
|
|
7
|
+
export declare function createLogRecordExporterFromConfig(exporter: LogRecordExporterConfigModel): LogRecordExporter;
|
|
8
|
+
export declare function createLogRecordProcessorFromConfig(processor: LogRecordProcessorConfigModel): LogRecordProcessor;
|
|
9
|
+
export declare function createLoggerProviderFromConfig(resource: Resource, logger_provider: LoggerProviderConfigModel, attribute_limits?: AttributeLimitsConfigModel): LoggerProvider;
|
|
10
|
+
export declare function createSpanLimitsFromConfig(limits?: SpanLimitsConfigModel, attribute_limits?: AttributeLimitsConfigModel): SpanLimits | undefined;
|
|
11
|
+
//# sourceMappingURL=create-from-config.d.ts.map
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright The OpenTelemetry Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createSpanLimitsFromConfig = exports.createLoggerProviderFromConfig = exports.createLogRecordProcessorFromConfig = exports.createLogRecordExporterFromConfig = exports.createLogRecordLimitsFromConfig = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Create SDK components from parsed declarative config.
|
|
10
|
+
* https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create
|
|
11
|
+
*
|
|
12
|
+
* Dev Notes:
|
|
13
|
+
* This file exports `create<SDK Thing>FromConfig(...)` functions intended to
|
|
14
|
+
* be used by the "create" step of `startNodeSDK()`.
|
|
15
|
+
*/
|
|
16
|
+
const api_1 = require("@opentelemetry/api");
|
|
17
|
+
const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
|
|
18
|
+
const exporter_logs_otlp_grpc_1 = require("@opentelemetry/exporter-logs-otlp-grpc");
|
|
19
|
+
const exporter_logs_otlp_proto_1 = require("@opentelemetry/exporter-logs-otlp-proto");
|
|
20
|
+
const otlp_exporter_base_1 = require("@opentelemetry/otlp-exporter-base");
|
|
21
|
+
const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
22
|
+
const utils_1 = require("./utils");
|
|
23
|
+
// ---- internal utilities
|
|
24
|
+
/**
|
|
25
|
+
* Warn if some props from a declarative config object have not been handled.
|
|
26
|
+
*
|
|
27
|
+
* This is intended to be used by `create*FromConfig()` functions. It is a low
|
|
28
|
+
* tech mechanism to add awareness when a given valid config is not being
|
|
29
|
+
* completely handled. This could help when properties are added to the
|
|
30
|
+
* configuration schema. (A higher tech mechanism that wraps the parsed
|
|
31
|
+
* configuration during `create()` and watches for untouched properties
|
|
32
|
+
* might be nice.)
|
|
33
|
+
*/
|
|
34
|
+
function checkConfigUse(name, props, handledProps) {
|
|
35
|
+
if (!props)
|
|
36
|
+
return;
|
|
37
|
+
// Dev note: I'd use Set#difference, but that requires Node.js v22.
|
|
38
|
+
const unhandledProps = Object.keys(props).filter(k => !handledProps.includes(k));
|
|
39
|
+
if (unhandledProps.length > 0) {
|
|
40
|
+
api_1.diag.warn(`Config warning: some specified ${name} configuration properties were not handled by SDK setup: ${JSON.stringify(unhandledProps)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return the single non-undefined entry in the given config object, or throw.
|
|
45
|
+
*
|
|
46
|
+
* It is common for Declarative Configuration to have config objects with
|
|
47
|
+
* a single entry, e.g.
|
|
48
|
+
*
|
|
49
|
+
* "LogRecordProcessor": {
|
|
50
|
+
* "type": "object",
|
|
51
|
+
* "additionalProperties": {
|
|
52
|
+
* "type": [
|
|
53
|
+
* "object",
|
|
54
|
+
* "null"
|
|
55
|
+
* ]
|
|
56
|
+
* },
|
|
57
|
+
* "minProperties": 1,
|
|
58
|
+
* "maxProperties": 1,
|
|
59
|
+
*
|
|
60
|
+
* The TypeScript types cannot express the minProperties/maxProperties from the
|
|
61
|
+
* JSON schema. We guard against that here.
|
|
62
|
+
*/
|
|
63
|
+
function mustSingleEntry(configObj, configTypeName) {
|
|
64
|
+
const entries = Object.entries(configObj).filter(([_name, properties]) => properties !== undefined);
|
|
65
|
+
if (entries.length !== 1) {
|
|
66
|
+
const entryNames = entries.map(e => e[0]);
|
|
67
|
+
throw Error(`invalid ${configTypeName} in configuration: must have exactly one entry: entries=${JSON.stringify(entryNames)}`);
|
|
68
|
+
}
|
|
69
|
+
return entries[0];
|
|
70
|
+
}
|
|
71
|
+
// ---- create<SDKThing>FromConfig functions
|
|
72
|
+
function createLogRecordLimitsFromConfig(limits, attribute_limits) {
|
|
73
|
+
if (!limits && !attribute_limits) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
attributeValueLengthLimit: limits?.attribute_value_length_limit ??
|
|
78
|
+
attribute_limits?.attribute_value_length_limit ??
|
|
79
|
+
undefined,
|
|
80
|
+
attributeCountLimit: limits?.attribute_count_limit ??
|
|
81
|
+
attribute_limits?.attribute_count_limit ??
|
|
82
|
+
undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
exports.createLogRecordLimitsFromConfig = createLogRecordLimitsFromConfig;
|
|
86
|
+
function createLogRecordExporterFromConfig(exporter) {
|
|
87
|
+
const [name, properties] = mustSingleEntry(exporter, 'LogRecordExporter');
|
|
88
|
+
switch (name) {
|
|
89
|
+
case 'otlp_http': {
|
|
90
|
+
checkConfigUse('LogRecordExporter', properties, [
|
|
91
|
+
'compression',
|
|
92
|
+
'endpoint',
|
|
93
|
+
'headers',
|
|
94
|
+
'timeout',
|
|
95
|
+
'tls',
|
|
96
|
+
'encoding',
|
|
97
|
+
]);
|
|
98
|
+
const props = properties;
|
|
99
|
+
const commonOpts = {
|
|
100
|
+
compression: props?.compression === 'gzip'
|
|
101
|
+
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
|
|
102
|
+
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
|
|
103
|
+
url: props?.endpoint ?? undefined,
|
|
104
|
+
headers: (0, utils_1.getHeadersFromConfiguration)(props?.headers),
|
|
105
|
+
timeoutMillis: (0, utils_1.validateExporterTimeout)(props?.timeout),
|
|
106
|
+
httpAgentOptions: (0, utils_1.getHttpAgentOptionsFromTls)(props?.tls),
|
|
107
|
+
};
|
|
108
|
+
const encoding = props?.encoding ?? 'protobuf';
|
|
109
|
+
switch (encoding) {
|
|
110
|
+
case 'json':
|
|
111
|
+
return new exporter_logs_otlp_http_1.OTLPLogExporter(commonOpts);
|
|
112
|
+
case 'protobuf':
|
|
113
|
+
return new exporter_logs_otlp_proto_1.OTLPLogExporter(commonOpts);
|
|
114
|
+
default:
|
|
115
|
+
throw new Error(`unknown OtlpHttpExporter encoding in configuration: "${encoding}"`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
case 'otlp_grpc': {
|
|
119
|
+
checkConfigUse('LogRecordExporter', properties, [
|
|
120
|
+
'compression',
|
|
121
|
+
'endpoint',
|
|
122
|
+
'timeout',
|
|
123
|
+
'tls',
|
|
124
|
+
'headers',
|
|
125
|
+
]);
|
|
126
|
+
const props = properties;
|
|
127
|
+
return new exporter_logs_otlp_grpc_1.OTLPLogExporter({
|
|
128
|
+
compression: props?.compression === 'gzip'
|
|
129
|
+
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
|
|
130
|
+
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
|
|
131
|
+
url: props?.endpoint ?? undefined,
|
|
132
|
+
timeoutMillis: (0, utils_1.validateExporterTimeout)(props?.timeout),
|
|
133
|
+
credentials: (0, utils_1.getGrpcCredentialsFromTls)(props?.tls),
|
|
134
|
+
metadata: (0, utils_1.getGrpcMetadataFromHeaders)(props?.headers),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
case 'console':
|
|
138
|
+
return new sdk_logs_1.ConsoleLogRecordExporter();
|
|
139
|
+
default:
|
|
140
|
+
throw new Error(`unknown LogRecordExporter name in configuration: "${name}"`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.createLogRecordExporterFromConfig = createLogRecordExporterFromConfig;
|
|
144
|
+
function createLogRecordProcessorFromConfig(processor) {
|
|
145
|
+
const [name, properties] = mustSingleEntry(processor, 'LogRecordProcessor');
|
|
146
|
+
switch (name) {
|
|
147
|
+
case 'batch': {
|
|
148
|
+
checkConfigUse('BatchLogRecordProcessor', properties, [
|
|
149
|
+
'exporter',
|
|
150
|
+
'max_queue_size',
|
|
151
|
+
'max_export_batch_size',
|
|
152
|
+
'schedule_delay',
|
|
153
|
+
'export_timeout',
|
|
154
|
+
]);
|
|
155
|
+
const props = properties;
|
|
156
|
+
const exporter = createLogRecordExporterFromConfig(props.exporter);
|
|
157
|
+
return new sdk_logs_1.BatchLogRecordProcessor({
|
|
158
|
+
exporter,
|
|
159
|
+
maxQueueSize: props.max_queue_size ?? undefined,
|
|
160
|
+
maxExportBatchSize: props.max_export_batch_size ?? undefined,
|
|
161
|
+
scheduledDelayMillis: props.schedule_delay ?? undefined,
|
|
162
|
+
exportTimeoutMillis: props.export_timeout ?? undefined,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
case 'simple': {
|
|
166
|
+
const props = properties;
|
|
167
|
+
const exporter = createLogRecordExporterFromConfig(props.exporter);
|
|
168
|
+
return new sdk_logs_1.SimpleLogRecordProcessor({ exporter });
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
throw new Error(`unknown LogRecordProcessor name: "${name}"`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.createLogRecordProcessorFromConfig = createLogRecordProcessorFromConfig;
|
|
175
|
+
function createLoggerProviderFromConfig(resource, logger_provider, attribute_limits) {
|
|
176
|
+
const processors = logger_provider.processors.map(p => createLogRecordProcessorFromConfig(p));
|
|
177
|
+
const logRecordLimits = createLogRecordLimitsFromConfig(logger_provider.limits, attribute_limits);
|
|
178
|
+
checkConfigUse('LoggerProvider', logger_provider, ['processors', 'limits']);
|
|
179
|
+
return new sdk_logs_1.LoggerProvider({
|
|
180
|
+
resource,
|
|
181
|
+
processors,
|
|
182
|
+
logRecordLimits,
|
|
183
|
+
// TODO: loggerConfigurator
|
|
184
|
+
// TODO: meterProvider
|
|
185
|
+
// Note: forceFlushTimeoutMillis not configurable via decl conf.
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
exports.createLoggerProviderFromConfig = createLoggerProviderFromConfig;
|
|
189
|
+
function createSpanLimitsFromConfig(limits, attribute_limits) {
|
|
190
|
+
if (!limits && !attribute_limits) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
attributeValueLengthLimit: limits?.attribute_value_length_limit ??
|
|
195
|
+
attribute_limits?.attribute_value_length_limit ??
|
|
196
|
+
undefined,
|
|
197
|
+
attributeCountLimit: limits?.attribute_count_limit ??
|
|
198
|
+
attribute_limits?.attribute_count_limit ??
|
|
199
|
+
undefined,
|
|
200
|
+
eventCountLimit: limits?.event_count_limit ?? undefined,
|
|
201
|
+
linkCountLimit: limits?.link_count_limit ?? undefined,
|
|
202
|
+
attributePerEventCountLimit: limits?.event_attribute_count_limit ?? undefined,
|
|
203
|
+
attributePerLinkCountLimit: limits?.link_attribute_count_limit ?? undefined,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
exports.createSpanLimitsFromConfig = createSpanLimitsFromConfig;
|
|
207
|
+
//# sourceMappingURL=create-from-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-from-config.js","sourceRoot":"","sources":["../../src/create-from-config.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Create SDK components from parsed declarative config.\n * https://opentelemetry.io/docs/specs/otel/configuration/sdk/#create\n *\n * Dev Notes:\n * This file exports `create<SDK Thing>FromConfig(...)` functions intended to\n * be used by the \"create\" step of `startNodeSDK()`.\n */\n\nimport { diag } from '@opentelemetry/api';\nimport type { SpanLimits } from '@opentelemetry/sdk-trace';\nimport type { Resource } from '@opentelemetry/resources';\nimport { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';\nimport { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';\nimport { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base';\nimport type {\n AttributeLimitsConfigModel,\n BatchLogRecordProcessorConfigModel,\n LoggerProviderConfigModel,\n LogRecordExporterConfigModel,\n LogRecordLimitsConfigModel,\n LogRecordProcessorConfigModel,\n OtlpGrpcExporterConfigModel,\n OtlpHttpExporterConfigModel,\n SimpleLogRecordProcessorConfigModel,\n SpanLimitsConfigModel,\n} from '@opentelemetry/configuration';\nimport type {\n LogRecordExporter,\n LogRecordProcessor,\n LogRecordLimits,\n} from '@opentelemetry/sdk-logs';\nimport {\n BatchLogRecordProcessor,\n ConsoleLogRecordExporter,\n SimpleLogRecordProcessor,\n LoggerProvider,\n} from '@opentelemetry/sdk-logs';\n\nimport {\n getGrpcCredentialsFromTls,\n getGrpcMetadataFromHeaders,\n getHeadersFromConfiguration,\n getHttpAgentOptionsFromTls,\n validateExporterTimeout,\n} from './utils';\n\n// ---- internal utilities\n\n/**\n * Warn if some props from a declarative config object have not been handled.\n *\n * This is intended to be used by `create*FromConfig()` functions. It is a low\n * tech mechanism to add awareness when a given valid config is not being\n * completely handled. This could help when properties are added to the\n * configuration schema. (A higher tech mechanism that wraps the parsed\n * configuration during `create()` and watches for untouched properties\n * might be nice.)\n */\nfunction checkConfigUse(\n name: string,\n props: object | undefined,\n handledProps: string[]\n) {\n if (!props) return;\n // Dev note: I'd use Set#difference, but that requires Node.js v22.\n const unhandledProps = Object.keys(props).filter(\n k => !handledProps.includes(k)\n );\n\n if (unhandledProps.length > 0) {\n diag.warn(\n `Config warning: some specified ${name} configuration properties were not handled by SDK setup: ${JSON.stringify(unhandledProps)}`\n );\n }\n}\n\n/**\n * Return the single non-undefined entry in the given config object, or throw.\n *\n * It is common for Declarative Configuration to have config objects with\n * a single entry, e.g.\n *\n * \"LogRecordProcessor\": {\n * \"type\": \"object\",\n * \"additionalProperties\": {\n * \"type\": [\n * \"object\",\n * \"null\"\n * ]\n * },\n * \"minProperties\": 1,\n * \"maxProperties\": 1,\n *\n * The TypeScript types cannot express the minProperties/maxProperties from the\n * JSON schema. We guard against that here.\n */\nfunction mustSingleEntry(\n configObj: Record<string, unknown>,\n configTypeName: string\n): [string, unknown] {\n const entries = Object.entries(configObj).filter(\n ([_name, properties]) => properties !== undefined\n );\n\n if (entries.length !== 1) {\n const entryNames = entries.map(e => e[0]);\n throw Error(\n `invalid ${configTypeName} in configuration: must have exactly one entry: entries=${JSON.stringify(entryNames)}`\n );\n }\n\n return entries[0];\n}\n\n// ---- create<SDKThing>FromConfig functions\n\nexport function createLogRecordLimitsFromConfig(\n limits?: LogRecordLimitsConfigModel,\n attribute_limits?: AttributeLimitsConfigModel\n): LogRecordLimits | undefined {\n if (!limits && !attribute_limits) {\n return undefined;\n }\n return {\n attributeValueLengthLimit:\n limits?.attribute_value_length_limit ??\n attribute_limits?.attribute_value_length_limit ??\n undefined,\n attributeCountLimit:\n limits?.attribute_count_limit ??\n attribute_limits?.attribute_count_limit ??\n undefined,\n };\n}\n\nexport function createLogRecordExporterFromConfig(\n exporter: LogRecordExporterConfigModel\n): LogRecordExporter {\n const [name, properties] = mustSingleEntry(exporter, 'LogRecordExporter');\n\n switch (name) {\n case 'otlp_http': {\n checkConfigUse('LogRecordExporter', properties!, [\n 'compression',\n 'endpoint',\n 'headers',\n 'timeout',\n 'tls',\n 'encoding',\n ]);\n const props = properties as OtlpHttpExporterConfigModel;\n const commonOpts = {\n compression:\n props?.compression === 'gzip'\n ? CompressionAlgorithm.GZIP\n : CompressionAlgorithm.NONE,\n url: props?.endpoint ?? undefined,\n headers: getHeadersFromConfiguration(props?.headers),\n timeoutMillis: validateExporterTimeout(props?.timeout),\n httpAgentOptions: getHttpAgentOptionsFromTls(props?.tls),\n };\n const encoding = props?.encoding ?? 'protobuf';\n switch (encoding) {\n case 'json':\n return new OTLPHttpLogExporter(commonOpts);\n case 'protobuf':\n return new OTLPProtoLogExporter(commonOpts);\n default:\n throw new Error(\n `unknown OtlpHttpExporter encoding in configuration: \"${encoding}\"`\n );\n }\n }\n\n case 'otlp_grpc': {\n checkConfigUse('LogRecordExporter', properties!, [\n 'compression',\n 'endpoint',\n 'timeout',\n 'tls',\n 'headers',\n ]);\n const props = properties as OtlpGrpcExporterConfigModel;\n return new OTLPGrpcLogExporter({\n compression:\n props?.compression === 'gzip'\n ? CompressionAlgorithm.GZIP\n : CompressionAlgorithm.NONE,\n url: props?.endpoint ?? undefined,\n timeoutMillis: validateExporterTimeout(props?.timeout),\n credentials: getGrpcCredentialsFromTls(props?.tls),\n metadata: getGrpcMetadataFromHeaders(props?.headers),\n });\n }\n\n case 'console':\n return new ConsoleLogRecordExporter();\n\n default:\n throw new Error(\n `unknown LogRecordExporter name in configuration: \"${name}\"`\n );\n }\n}\n\nexport function createLogRecordProcessorFromConfig(\n processor: LogRecordProcessorConfigModel\n): LogRecordProcessor {\n const [name, properties] = mustSingleEntry(processor, 'LogRecordProcessor');\n\n switch (name) {\n case 'batch': {\n checkConfigUse('BatchLogRecordProcessor', properties!, [\n 'exporter',\n 'max_queue_size',\n 'max_export_batch_size',\n 'schedule_delay',\n 'export_timeout',\n ]);\n const props = properties as BatchLogRecordProcessorConfigModel;\n const exporter = createLogRecordExporterFromConfig(props.exporter);\n return new BatchLogRecordProcessor({\n exporter,\n maxQueueSize: props.max_queue_size ?? undefined,\n maxExportBatchSize: props.max_export_batch_size ?? undefined,\n scheduledDelayMillis: props.schedule_delay ?? undefined,\n exportTimeoutMillis: props.export_timeout ?? undefined,\n });\n }\n\n case 'simple': {\n const props = properties as SimpleLogRecordProcessorConfigModel;\n const exporter = createLogRecordExporterFromConfig(props.exporter);\n return new SimpleLogRecordProcessor({ exporter });\n }\n\n default:\n throw new Error(`unknown LogRecordProcessor name: \"${name}\"`);\n }\n}\n\nexport function createLoggerProviderFromConfig(\n resource: Resource,\n logger_provider: LoggerProviderConfigModel,\n attribute_limits?: AttributeLimitsConfigModel\n): LoggerProvider {\n const processors = logger_provider.processors.map(p =>\n createLogRecordProcessorFromConfig(p)\n );\n const logRecordLimits = createLogRecordLimitsFromConfig(\n logger_provider.limits,\n attribute_limits\n );\n checkConfigUse('LoggerProvider', logger_provider, ['processors', 'limits']);\n\n return new LoggerProvider({\n resource,\n processors,\n logRecordLimits,\n // TODO: loggerConfigurator\n // TODO: meterProvider\n // Note: forceFlushTimeoutMillis not configurable via decl conf.\n });\n}\n\nexport function createSpanLimitsFromConfig(\n limits?: SpanLimitsConfigModel,\n attribute_limits?: AttributeLimitsConfigModel\n): SpanLimits | undefined {\n if (!limits && !attribute_limits) {\n return undefined;\n }\n return {\n attributeValueLengthLimit:\n limits?.attribute_value_length_limit ??\n attribute_limits?.attribute_value_length_limit ??\n undefined,\n attributeCountLimit:\n limits?.attribute_count_limit ??\n attribute_limits?.attribute_count_limit ??\n undefined,\n eventCountLimit: limits?.event_count_limit ?? undefined,\n linkCountLimit: limits?.link_count_limit ?? undefined,\n attributePerEventCountLimit:\n limits?.event_attribute_count_limit ?? undefined,\n attributePerLinkCountLimit: limits?.link_attribute_count_limit ?? undefined,\n };\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create SDK components from environment variable settings.
|
|
3
|
+
* https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/
|
|
4
|
+
*/
|
|
5
|
+
import type { MeterProvider } from '@opentelemetry/api';
|
|
6
|
+
import type { Sampler, SpanExporter, SpanLimits } from '@opentelemetry/sdk-trace';
|
|
7
|
+
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace';
|
|
8
|
+
export declare function createSamplerFromEnv(): Sampler | undefined;
|
|
9
|
+
export declare function createSpanLimitsFromEnv(): SpanLimits | undefined;
|
|
10
|
+
export declare function createBatchSpanProcessorFromEnv(exporter: SpanExporter, selfObsMeterProvider?: MeterProvider): BatchSpanProcessor;
|
|
11
|
+
//# sourceMappingURL=create-from-env.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright The OpenTelemetry Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createBatchSpanProcessorFromEnv = exports.createSpanLimitsFromEnv = exports.createSamplerFromEnv = void 0;
|
|
8
|
+
const api_1 = require("@opentelemetry/api");
|
|
9
|
+
const core_1 = require("@opentelemetry/core");
|
|
10
|
+
const sdk_trace_1 = require("@opentelemetry/sdk-trace");
|
|
11
|
+
const sdk_trace_2 = require("@opentelemetry/sdk-trace");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
13
|
+
const DEFAULT_RATIO = 1;
|
|
14
|
+
function createSamplerFromEnv() {
|
|
15
|
+
const samplerName = (0, core_1.getStringFromEnv)('OTEL_TRACES_SAMPLER');
|
|
16
|
+
if (samplerName === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
switch (samplerName) {
|
|
20
|
+
case 'always_on':
|
|
21
|
+
return new sdk_trace_2.AlwaysOnSampler();
|
|
22
|
+
case 'always_off':
|
|
23
|
+
return new sdk_trace_2.AlwaysOffSampler();
|
|
24
|
+
case 'parentbased_always_on':
|
|
25
|
+
return new sdk_trace_2.ParentBasedSampler({
|
|
26
|
+
root: new sdk_trace_2.AlwaysOnSampler(),
|
|
27
|
+
});
|
|
28
|
+
case 'parentbased_always_off':
|
|
29
|
+
return new sdk_trace_2.ParentBasedSampler({
|
|
30
|
+
root: new sdk_trace_2.AlwaysOffSampler(),
|
|
31
|
+
});
|
|
32
|
+
case 'traceidratio':
|
|
33
|
+
return new sdk_trace_2.TraceIdRatioBasedSampler(getSamplerRatioFromEnv());
|
|
34
|
+
case 'parentbased_traceidratio':
|
|
35
|
+
return new sdk_trace_2.ParentBasedSampler({
|
|
36
|
+
root: new sdk_trace_2.TraceIdRatioBasedSampler(getSamplerRatioFromEnv()),
|
|
37
|
+
});
|
|
38
|
+
default:
|
|
39
|
+
api_1.diag.error(`unknown OTEL_TRACES_SAMPLER value "${samplerName}", using default`);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.createSamplerFromEnv = createSamplerFromEnv;
|
|
44
|
+
function getSamplerRatioFromEnv() {
|
|
45
|
+
const ratio = (0, core_1.getNumberFromEnv)('OTEL_TRACES_SAMPLER_ARG');
|
|
46
|
+
if (ratio == null) {
|
|
47
|
+
api_1.diag.error(`OTEL_TRACES_SAMPLER_ARG is blank, defaulting to ${DEFAULT_RATIO}.`);
|
|
48
|
+
return DEFAULT_RATIO;
|
|
49
|
+
}
|
|
50
|
+
if (ratio < 0 || ratio > 1) {
|
|
51
|
+
api_1.diag.error(`OTEL_TRACES_SAMPLER_ARG=${ratio} was given, but it is out of range ([0..1]), defaulting to ${DEFAULT_RATIO}.`);
|
|
52
|
+
return DEFAULT_RATIO;
|
|
53
|
+
}
|
|
54
|
+
return ratio;
|
|
55
|
+
}
|
|
56
|
+
function createSpanLimitsFromEnv() {
|
|
57
|
+
return {
|
|
58
|
+
attributeCountLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT') ??
|
|
59
|
+
(0, core_1.getNumberFromEnv)('OTEL_ATTRIBUTE_COUNT_LIMIT'),
|
|
60
|
+
attributeValueLengthLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT') ??
|
|
61
|
+
(0, core_1.getNumberFromEnv)('OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'),
|
|
62
|
+
eventCountLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_EVENT_COUNT_LIMIT'),
|
|
63
|
+
linkCountLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_LINK_COUNT_LIMIT'),
|
|
64
|
+
attributePerEventCountLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT'),
|
|
65
|
+
attributePerLinkCountLimit: (0, core_1.getNumberFromEnv)('OTEL_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
exports.createSpanLimitsFromEnv = createSpanLimitsFromEnv;
|
|
69
|
+
function createBatchSpanProcessorFromEnv(exporter, selfObsMeterProvider) {
|
|
70
|
+
return new sdk_trace_1.BatchSpanProcessor({
|
|
71
|
+
exporter,
|
|
72
|
+
selfObsMeterProvider,
|
|
73
|
+
maxQueueSize: (0, utils_1.getNonNegativeNumberFromEnv)('OTEL_BSP_MAX_QUEUE_SIZE'),
|
|
74
|
+
scheduledDelayMillis: (0, utils_1.getNonNegativeNumberFromEnv)('OTEL_BSP_SCHEDULE_DELAY'),
|
|
75
|
+
exportTimeoutMillis: (0, utils_1.getNonNegativeNumberFromEnv)('OTEL_BSP_EXPORT_TIMEOUT'),
|
|
76
|
+
maxExportBatchSize: (0, utils_1.getNonNegativeNumberFromEnv)('OTEL_BSP_MAX_EXPORT_BATCH_SIZE'),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
exports.createBatchSpanProcessorFromEnv = createBatchSpanProcessorFromEnv;
|
|
80
|
+
//# sourceMappingURL=create-from-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-from-env.js","sourceRoot":"","sources":["../../src/create-from-env.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,4CAA0C;AAC1C,8CAAyE;AAMzE,wDAA8D;AAC9D,wDAKkC;AAClC,mCAAsD;AAEtD,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,SAAgB,oBAAoB;IAClC,MAAM,WAAW,GAAG,IAAA,uBAAgB,EAAC,qBAAqB,CAAC,CAAC;IAC5D,IAAI,WAAW,KAAK,SAAS,EAAE;QAC7B,OAAO,SAAS,CAAC;KAClB;IACD,QAAQ,WAAW,EAAE;QACnB,KAAK,WAAW;YACd,OAAO,IAAI,2BAAe,EAAE,CAAC;QAC/B,KAAK,YAAY;YACf,OAAO,IAAI,4BAAgB,EAAE,CAAC;QAChC,KAAK,uBAAuB;YAC1B,OAAO,IAAI,8BAAkB,CAAC;gBAC5B,IAAI,EAAE,IAAI,2BAAe,EAAE;aAC5B,CAAC,CAAC;QACL,KAAK,wBAAwB;YAC3B,OAAO,IAAI,8BAAkB,CAAC;gBAC5B,IAAI,EAAE,IAAI,4BAAgB,EAAE;aAC7B,CAAC,CAAC;QACL,KAAK,cAAc;YACjB,OAAO,IAAI,oCAAwB,CAAC,sBAAsB,EAAE,CAAC,CAAC;QAChE,KAAK,0BAA0B;YAC7B,OAAO,IAAI,8BAAkB,CAAC;gBAC5B,IAAI,EAAE,IAAI,oCAAwB,CAAC,sBAAsB,EAAE,CAAC;aAC7D,CAAC,CAAC;QACL;YACE,UAAI,CAAC,KAAK,CACR,sCAAsC,WAAW,kBAAkB,CACpE,CAAC;YACF,OAAO,SAAS,CAAC;KACpB;AACH,CAAC;AA9BD,oDA8BC;AAED,SAAS,sBAAsB;IAC7B,MAAM,KAAK,GAAG,IAAA,uBAAgB,EAAC,yBAAyB,CAAC,CAAC;IAC1D,IAAI,KAAK,IAAI,IAAI,EAAE;QACjB,UAAI,CAAC,KAAK,CACR,mDAAmD,aAAa,GAAG,CACpE,CAAC;QACF,OAAO,aAAa,CAAC;KACtB;IAED,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE;QAC1B,UAAI,CAAC,KAAK,CACR,2BAA2B,KAAK,8DAA8D,aAAa,GAAG,CAC/G,CAAC;QACF,OAAO,aAAa,CAAC;KACtB;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,uBAAuB;IACrC,OAAO;QACL,mBAAmB,EACjB,IAAA,uBAAgB,EAAC,iCAAiC,CAAC;YACnD,IAAA,uBAAgB,EAAC,4BAA4B,CAAC;QAChD,yBAAyB,EACvB,IAAA,uBAAgB,EAAC,wCAAwC,CAAC;YAC1D,IAAA,uBAAgB,EAAC,mCAAmC,CAAC;QACvD,eAAe,EAAE,IAAA,uBAAgB,EAAC,6BAA6B,CAAC;QAChE,cAAc,EAAE,IAAA,uBAAgB,EAAC,4BAA4B,CAAC;QAC9D,2BAA2B,EAAE,IAAA,uBAAgB,EAC3C,2CAA2C,CAC5C;QACD,0BAA0B,EAAE,IAAA,uBAAgB,EAC1C,0CAA0C,CAC3C;KACF,CAAC;AACJ,CAAC;AAjBD,0DAiBC;AAED,SAAgB,+BAA+B,CAC7C,QAAsB,EACtB,oBAAoC;IAEpC,OAAO,IAAI,8BAAkB,CAAC;QAC5B,QAAQ;QACR,oBAAoB;QACpB,YAAY,EAAE,IAAA,mCAA2B,EAAC,yBAAyB,CAAC;QACpE,oBAAoB,EAAE,IAAA,mCAA2B,EAC/C,yBAAyB,CAC1B;QACD,mBAAmB,EAAE,IAAA,mCAA2B,EAAC,yBAAyB,CAAC;QAC3E,kBAAkB,EAAE,IAAA,mCAA2B,EAC7C,gCAAgC,CACjC;KACF,CAAC,CAAC;AACL,CAAC;AAhBD,0EAgBC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Create SDK components from environment variable settings.\n * https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/\n */\n\nimport type { MeterProvider } from '@opentelemetry/api';\nimport { diag } from '@opentelemetry/api';\nimport { getNumberFromEnv, getStringFromEnv } from '@opentelemetry/core';\nimport type {\n Sampler,\n SpanExporter,\n SpanLimits,\n} from '@opentelemetry/sdk-trace';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace';\nimport {\n AlwaysOffSampler,\n AlwaysOnSampler,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n} from '@opentelemetry/sdk-trace';\nimport { getNonNegativeNumberFromEnv } from './utils';\n\nconst DEFAULT_RATIO = 1;\n\nexport function createSamplerFromEnv(): Sampler | undefined {\n const samplerName = getStringFromEnv('OTEL_TRACES_SAMPLER');\n if (samplerName === undefined) {\n return undefined;\n }\n switch (samplerName) {\n case 'always_on':\n return new AlwaysOnSampler();\n case 'always_off':\n return new AlwaysOffSampler();\n case 'parentbased_always_on':\n return new ParentBasedSampler({\n root: new AlwaysOnSampler(),\n });\n case 'parentbased_always_off':\n return new ParentBasedSampler({\n root: new AlwaysOffSampler(),\n });\n case 'traceidratio':\n return new TraceIdRatioBasedSampler(getSamplerRatioFromEnv());\n case 'parentbased_traceidratio':\n return new ParentBasedSampler({\n root: new TraceIdRatioBasedSampler(getSamplerRatioFromEnv()),\n });\n default:\n diag.error(\n `unknown OTEL_TRACES_SAMPLER value \"${samplerName}\", using default`\n );\n return undefined;\n }\n}\n\nfunction getSamplerRatioFromEnv(): number | undefined {\n const ratio = getNumberFromEnv('OTEL_TRACES_SAMPLER_ARG');\n if (ratio == null) {\n diag.error(\n `OTEL_TRACES_SAMPLER_ARG is blank, defaulting to ${DEFAULT_RATIO}.`\n );\n return DEFAULT_RATIO;\n }\n\n if (ratio < 0 || ratio > 1) {\n diag.error(\n `OTEL_TRACES_SAMPLER_ARG=${ratio} was given, but it is out of range ([0..1]), defaulting to ${DEFAULT_RATIO}.`\n );\n return DEFAULT_RATIO;\n }\n\n return ratio;\n}\n\nexport function createSpanLimitsFromEnv(): SpanLimits | undefined {\n return {\n attributeCountLimit:\n getNumberFromEnv('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT') ??\n getNumberFromEnv('OTEL_ATTRIBUTE_COUNT_LIMIT'),\n attributeValueLengthLimit:\n getNumberFromEnv('OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT') ??\n getNumberFromEnv('OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'),\n eventCountLimit: getNumberFromEnv('OTEL_SPAN_EVENT_COUNT_LIMIT'),\n linkCountLimit: getNumberFromEnv('OTEL_SPAN_LINK_COUNT_LIMIT'),\n attributePerEventCountLimit: getNumberFromEnv(\n 'OTEL_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT'\n ),\n attributePerLinkCountLimit: getNumberFromEnv(\n 'OTEL_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT'\n ),\n };\n}\n\nexport function createBatchSpanProcessorFromEnv(\n exporter: SpanExporter,\n selfObsMeterProvider?: MeterProvider\n): BatchSpanProcessor {\n return new BatchSpanProcessor({\n exporter,\n selfObsMeterProvider,\n maxQueueSize: getNonNegativeNumberFromEnv('OTEL_BSP_MAX_QUEUE_SIZE'),\n scheduledDelayMillis: getNonNegativeNumberFromEnv(\n 'OTEL_BSP_SCHEDULE_DELAY'\n ),\n exportTimeoutMillis: getNonNegativeNumberFromEnv('OTEL_BSP_EXPORT_TIMEOUT'),\n maxExportBatchSize: getNonNegativeNumberFromEnv(\n 'OTEL_BSP_MAX_EXPORT_BATCH_SIZE'\n ),\n });\n}\n"]}
|
package/build/src/index.d.ts
CHANGED
|
@@ -3,8 +3,14 @@ export * as contextBase from '@opentelemetry/api';
|
|
|
3
3
|
export * as core from '@opentelemetry/core';
|
|
4
4
|
export * as logs from '@opentelemetry/sdk-logs';
|
|
5
5
|
export * as metrics from '@opentelemetry/sdk-metrics';
|
|
6
|
-
export * as node from '@opentelemetry/sdk-trace-node';
|
|
7
6
|
export * as resources from '@opentelemetry/resources';
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Import directly from `@opentelemetry/sdk-trace` instead.
|
|
9
|
+
*/
|
|
10
|
+
export * as node from '@opentelemetry/sdk-trace-node';
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Import directly from `@opentelemetry/sdk-trace` instead.
|
|
13
|
+
*/
|
|
8
14
|
export * as tracing from '@opentelemetry/sdk-trace-base';
|
|
9
15
|
export { NodeSDK } from './sdk';
|
|
10
16
|
export type { LoggerProviderConfig, MeterProviderConfig } from './sdk';
|
package/build/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.startNodeSDK = exports.NodeSDK = exports.tracing = exports.
|
|
7
|
+
exports.startNodeSDK = exports.NodeSDK = exports.tracing = exports.node = exports.resources = exports.metrics = exports.logs = exports.core = exports.contextBase = exports.api = void 0;
|
|
8
8
|
// This is a meta-package, and these exist in to re-export *all* items from
|
|
9
9
|
// the individual packages as individual _namespaces_, so wildcard exports are
|
|
10
10
|
// appropriate here. Otherwise, it'd be a pain to enumerate and keep things
|
|
@@ -15,8 +15,14 @@ exports.contextBase = require("@opentelemetry/api");
|
|
|
15
15
|
exports.core = require("@opentelemetry/core");
|
|
16
16
|
exports.logs = require("@opentelemetry/sdk-logs");
|
|
17
17
|
exports.metrics = require("@opentelemetry/sdk-metrics");
|
|
18
|
-
exports.node = require("@opentelemetry/sdk-trace-node");
|
|
19
18
|
exports.resources = require("@opentelemetry/resources");
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated Import directly from `@opentelemetry/sdk-trace` instead.
|
|
21
|
+
*/
|
|
22
|
+
exports.node = require("@opentelemetry/sdk-trace-node");
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Import directly from `@opentelemetry/sdk-trace` instead.
|
|
25
|
+
*/
|
|
20
26
|
exports.tracing = require("@opentelemetry/sdk-trace-base");
|
|
21
27
|
/* eslint-enable no-restricted-syntax */
|
|
22
28
|
var sdk_1 = require("./sdk");
|
package/build/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,2EAA2E;AAC3E,8EAA8E;AAC9E,2EAA2E;AAC3E,0CAA0C;AAE1C,yCAAyC;AACzC,4CAA0C;AAC1C,oDAAkD;AAClD,8CAA4C;AAC5C,kDAAgD;AAChD,wDAAsD;AACtD,wDAAsD;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,2EAA2E;AAC3E,8EAA8E;AAC9E,2EAA2E;AAC3E,0CAA0C;AAE1C,yCAAyC;AACzC,4CAA0C;AAC1C,oDAAkD;AAClD,8CAA4C;AAC5C,kDAAgD;AAChD,wDAAsD;AACtD,wDAAsD;AAEtD;;GAEG;AACH,wDAAsD;AACtD;;GAEG;AACH,2DAAyD;AACzD,wCAAwC;AAExC,6BAAgC;AAAvB,8FAAA,OAAO,OAAA;AAGhB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// This is a meta-package, and these exist in to re-export *all* items from\n// the individual packages as individual _namespaces_, so wildcard exports are\n// appropriate here. Otherwise, it'd be a pain to enumerate and keep things\n// in-sync with all the upstream packages.\n\n/* eslint-disable no-restricted-syntax */\nexport * as api from '@opentelemetry/api';\nexport * as contextBase from '@opentelemetry/api';\nexport * as core from '@opentelemetry/core';\nexport * as logs from '@opentelemetry/sdk-logs';\nexport * as metrics from '@opentelemetry/sdk-metrics';\nexport * as resources from '@opentelemetry/resources';\n\n/**\n * @deprecated Import directly from `@opentelemetry/sdk-trace` instead.\n */\nexport * as node from '@opentelemetry/sdk-trace-node';\n/**\n * @deprecated Import directly from `@opentelemetry/sdk-trace` instead.\n */\nexport * as tracing from '@opentelemetry/sdk-trace-base';\n/* eslint-enable no-restricted-syntax */\n\nexport { NodeSDK } from './sdk';\nexport type { LoggerProviderConfig, MeterProviderConfig } from './sdk';\nexport type { NodeSDKConfiguration } from './types';\nexport { startNodeSDK } from './start';\n"]}
|
package/build/src/sdk.d.ts
CHANGED
|
@@ -36,7 +36,6 @@ export type LoggerProviderConfig = {
|
|
|
36
36
|
* nodeSdk.start(); // registers all configured SDK components
|
|
37
37
|
*/
|
|
38
38
|
export declare class NodeSDK {
|
|
39
|
-
private _tracerProviderConfig?;
|
|
40
39
|
private _loggerProviderConfig?;
|
|
41
40
|
private _meterProviderConfig?;
|
|
42
41
|
private _instrumentations;
|
package/build/src/sdk.js
CHANGED
|
@@ -15,11 +15,11 @@ const exporter_logs_otlp_grpc_1 = require("@opentelemetry/exporter-logs-otlp-grp
|
|
|
15
15
|
const exporter_logs_otlp_proto_1 = require("@opentelemetry/exporter-logs-otlp-proto");
|
|
16
16
|
const exporter_prometheus_1 = require("@opentelemetry/exporter-prometheus");
|
|
17
17
|
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
18
|
-
const
|
|
19
|
-
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
18
|
+
const sdk_trace_1 = require("@opentelemetry/sdk-trace");
|
|
20
19
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
21
20
|
const core_1 = require("@opentelemetry/core");
|
|
22
21
|
const utils_1 = require("./utils");
|
|
22
|
+
const create_from_env_1 = require("./create-from-env");
|
|
23
23
|
/**
|
|
24
24
|
*
|
|
25
25
|
* @returns MetricReader[] if appropriate environment variables are configured
|
|
@@ -72,7 +72,6 @@ function getMetricReadersFromEnv() {
|
|
|
72
72
|
* nodeSdk.start(); // registers all configured SDK components
|
|
73
73
|
*/
|
|
74
74
|
class NodeSDK {
|
|
75
|
-
_tracerProviderConfig;
|
|
76
75
|
_loggerProviderConfig;
|
|
77
76
|
_meterProviderConfig;
|
|
78
77
|
_instrumentations;
|
|
@@ -116,30 +115,8 @@ class NodeSDK {
|
|
|
116
115
|
this._resourceDetectors = [resources_1.envDetector, resources_1.processDetector, resources_1.hostDetector];
|
|
117
116
|
}
|
|
118
117
|
this._serviceName = configuration.serviceName;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
configuration.spanProcessor ||
|
|
122
|
-
configuration.spanProcessors) {
|
|
123
|
-
const tracerProviderConfig = {};
|
|
124
|
-
if (configuration.sampler) {
|
|
125
|
-
tracerProviderConfig.sampler = configuration.sampler;
|
|
126
|
-
}
|
|
127
|
-
if (configuration.spanLimits) {
|
|
128
|
-
tracerProviderConfig.spanLimits = configuration.spanLimits;
|
|
129
|
-
}
|
|
130
|
-
if (configuration.idGenerator) {
|
|
131
|
-
tracerProviderConfig.idGenerator = configuration.idGenerator;
|
|
132
|
-
}
|
|
133
|
-
if (configuration.spanProcessor) {
|
|
134
|
-
api_1.diag.warn("The 'spanProcessor' option is deprecated. Please use 'spanProcessors' instead.");
|
|
135
|
-
}
|
|
136
|
-
const spanProcessor = configuration.spanProcessor ??
|
|
137
|
-
new sdk_trace_base_1.BatchSpanProcessor(configuration.traceExporter);
|
|
138
|
-
const spanProcessors = configuration.spanProcessors ?? [spanProcessor];
|
|
139
|
-
this._tracerProviderConfig = {
|
|
140
|
-
tracerConfig: tracerProviderConfig,
|
|
141
|
-
spanProcessors,
|
|
142
|
-
};
|
|
118
|
+
if (configuration.spanProcessor) {
|
|
119
|
+
api_1.diag.warn("The 'spanProcessor' option is deprecated. Please use 'spanProcessors' instead.");
|
|
143
120
|
}
|
|
144
121
|
if (configuration.logRecordProcessors) {
|
|
145
122
|
this._loggerProviderConfig = {
|
|
@@ -152,9 +129,6 @@ class NodeSDK {
|
|
|
152
129
|
};
|
|
153
130
|
api_1.diag.warn("The 'logRecordProcessor' option is deprecated. Please use 'logRecordProcessors' instead.");
|
|
154
131
|
}
|
|
155
|
-
else {
|
|
156
|
-
this.configureLoggerProviderFromEnv();
|
|
157
|
-
}
|
|
158
132
|
if (configuration.metricReaders) {
|
|
159
133
|
this._meterProviderConfig = {
|
|
160
134
|
readers: configuration.metricReaders,
|
|
@@ -223,19 +197,40 @@ class NodeSDK {
|
|
|
223
197
|
instrumentation.setMeterProvider(api_1.metrics.getMeterProvider());
|
|
224
198
|
}
|
|
225
199
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
200
|
+
// Determine `spanProcessors` from multiple possible options.
|
|
201
|
+
let spanProcessors;
|
|
202
|
+
if (this._configuration?.spanProcessors) {
|
|
203
|
+
spanProcessors = this._configuration.spanProcessors;
|
|
204
|
+
}
|
|
205
|
+
else if (this._configuration?.spanProcessor) {
|
|
206
|
+
spanProcessors = [this._configuration.spanProcessor];
|
|
207
|
+
}
|
|
208
|
+
else if (this._configuration?.traceExporter) {
|
|
209
|
+
spanProcessors = [
|
|
210
|
+
(0, create_from_env_1.createBatchSpanProcessorFromEnv)(this._configuration.traceExporter, sdkMetricsEnabled ? this._meterProvider : undefined),
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
spanProcessors = (0, utils_1.getSpanProcessorsFromEnv)(sdkMetricsEnabled ? this._meterProvider : undefined);
|
|
215
|
+
}
|
|
229
216
|
// Only register if there is a span processor
|
|
230
217
|
if (spanProcessors.length > 0) {
|
|
231
|
-
this._tracerProvider = new
|
|
232
|
-
|
|
218
|
+
this._tracerProvider = new sdk_trace_1.TracerProvider({
|
|
219
|
+
sampler: this._configuration?.sampler ?? (0, create_from_env_1.createSamplerFromEnv)(),
|
|
220
|
+
spanLimits: {
|
|
221
|
+
...(0, create_from_env_1.createSpanLimitsFromEnv)(),
|
|
222
|
+
...this._configuration?.spanLimits,
|
|
223
|
+
},
|
|
233
224
|
resource: this._resource,
|
|
234
225
|
meterProvider: sdkMetricsEnabled ? this._meterProvider : undefined,
|
|
226
|
+
idGenerator: this._configuration?.idGenerator,
|
|
235
227
|
spanProcessors,
|
|
236
228
|
});
|
|
237
229
|
api_1.trace.setGlobalTracerProvider(this._tracerProvider);
|
|
238
230
|
}
|
|
231
|
+
if (!this._loggerProviderConfig) {
|
|
232
|
+
this.configureLoggerProviderFromEnv(sdkMetricsEnabled ? this._meterProvider : undefined);
|
|
233
|
+
}
|
|
239
234
|
if (this._loggerProviderConfig) {
|
|
240
235
|
const loggerProvider = new sdk_logs_1.LoggerProvider({
|
|
241
236
|
...(0, utils_1.getLoggerProviderConfigFromEnv)(),
|
|
@@ -262,7 +257,7 @@ class NodeSDK {
|
|
|
262
257
|
// return void instead of the array from Promise.all
|
|
263
258
|
.then(() => { }));
|
|
264
259
|
}
|
|
265
|
-
configureLoggerProviderFromEnv() {
|
|
260
|
+
configureLoggerProviderFromEnv(meterProvider) {
|
|
266
261
|
const enabledExporters = Array.from(new Set((0, core_1.getStringListFromEnv)('OTEL_LOGS_EXPORTER') ?? []));
|
|
267
262
|
if (enabledExporters.length === 0) {
|
|
268
263
|
api_1.diag.debug('OTEL_LOGS_EXPORTER is empty. Using default otlp exporter.');
|
|
@@ -303,10 +298,13 @@ class NodeSDK {
|
|
|
303
298
|
this._loggerProviderConfig = {
|
|
304
299
|
logRecordProcessors: exporters.map(exporter => {
|
|
305
300
|
if (exporter instanceof sdk_logs_1.ConsoleLogRecordExporter) {
|
|
306
|
-
return new sdk_logs_1.SimpleLogRecordProcessor(
|
|
301
|
+
return new sdk_logs_1.SimpleLogRecordProcessor({
|
|
302
|
+
exporter,
|
|
303
|
+
selfObsMeterProvider: meterProvider,
|
|
304
|
+
});
|
|
307
305
|
}
|
|
308
306
|
else {
|
|
309
|
-
return (0, utils_1.getBatchLogRecordProcessorFromEnv)(exporter);
|
|
307
|
+
return (0, utils_1.getBatchLogRecordProcessorFromEnv)(exporter, meterProvider);
|
|
310
308
|
}
|
|
311
309
|
}),
|
|
312
310
|
};
|