From a6d0fca347d7a1cf84ba6f6eaa7f8bd7827247cc Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 22 Aug 2025 11:45:25 -0400 Subject: [PATCH 01/15] parse config file --- experimental/CHANGELOG.md | 1 + .../opentelemetry-configuration/package.json | 3 +- .../src/EnvironmentConfigProvider.ts | 2 +- .../src/FileConfigProvider.ts | 91 ++++++++++++++++++- .../src/configModel.ts | 6 +- .../test/ConfigProvider.test.ts | 63 ++++++++++++- .../test/fixtures/kitchen-sink.yaml | 2 +- package-lock.json | 10 +- 8 files changed, 162 insertions(+), 16 deletions(-) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 2480cecab9f..7ddc0e586a2 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -14,6 +14,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 *feat(opentelemetry-configuration): creation of basic ConfigProvider [#5809](https://github.com/open-telemetry/opentelemetry-js/pull/5809) @maryliag *feat(opentelemetry-configuration): creation of basic FileConfigProvider [#5863](https://github.com/open-telemetry/opentelemetry-js/pull/5863) @maryliag +*feat(opentelemetry-configuration): Parse of Configuration File [#](https://github.com/open-telemetry/opentelemetry-js/pull/) @maryliag ### :bug: Bug Fixes diff --git a/experimental/packages/opentelemetry-configuration/package.json b/experimental/packages/opentelemetry-configuration/package.json index 17f304f8aff..721b27375d8 100644 --- a/experimental/packages/opentelemetry-configuration/package.json +++ b/experimental/packages/opentelemetry-configuration/package.json @@ -41,7 +41,8 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^2.0.1" + "@opentelemetry/core": "^2.0.1", + "yaml": "^1.10.2" }, "devDependencies": { "@opentelemetry/api": "^1.9.0", diff --git a/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts index 718979c7119..0470ec3b17a 100644 --- a/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts @@ -35,7 +35,7 @@ export class EnvironmentConfigProvider implements ConfigProvider { constructor() { this._config = initializeDefaultConfiguration(); - this._config.disable = getBooleanFromEnv('OTEL_SDK_DISABLED'); + this._config.disabled = getBooleanFromEnv('OTEL_SDK_DISABLED'); const logLevel = getStringFromEnv('OTEL_LOG_LEVEL'); if (logLevel) { diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index 58b3af0093e..a56b530127b 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -14,19 +14,26 @@ * limitations under the License. */ -import { getStringFromEnv } from '@opentelemetry/core'; +import { + diagLogLevelFromString, + getStringFromEnv, + getStringListFromEnv, +} from '@opentelemetry/core'; import { ConfigurationModel, initializeDefaultConfiguration, } from './configModel'; import { ConfigProvider } from './IConfigProvider'; import * as fs from 'fs'; +import * as yaml from 'yaml'; +import { DiagLogLevel } from '@opentelemetry/api'; export class FileConfigProvider implements ConfigProvider { private _config: ConfigurationModel; constructor() { this._config = initializeDefaultConfiguration(); + ParseConfigFile(this._config); } getInstrumentationConfig(): ConfigurationModel { @@ -37,7 +44,10 @@ export class FileConfigProvider implements ConfigProvider { export function hasValidConfigFile(): boolean { const configFile = getStringFromEnv('OTEL_EXPERIMENTAL_CONFIG_FILE'); if (configFile) { - if (!configFile.endsWith('.yaml') || !fs.existsSync(configFile)) { + if ( + !(configFile.endsWith('.yaml') || configFile.endsWith('.yml')) || + !fs.existsSync(configFile) + ) { throw new Error( `Config file ${configFile} set on OTEL_EXPERIMENTAL_CONFIG_FILE is not valid` ); @@ -46,3 +56,80 @@ export function hasValidConfigFile(): boolean { } return false; } + +function ParseConfigFile(config: ConfigurationModel) { + const supportedFileVersions = ['1.0-rc.1']; + const configFile = getStringFromEnv('OTEL_EXPERIMENTAL_CONFIG_FILE') || ''; + const file = fs.readFileSync(configFile, 'utf8'); + const parsedContent = yaml.parse(file); + + if ( + parsedContent['file_format'] && + supportedFileVersions.includes(parsedContent['file_format']) + ) { + config.disabled = setValue(config.disabled, parsedContent['disabled']); + config.log_level = setValue( + config.log_level, + diagLogLevelFromString(parsedContent['log_level']) ?? DiagLogLevel.INFO + ); + config.resource.attributes_list = setValue( + config.resource.attributes_list, + parsedContent['resource']?.['attributes_list'] + ); + config.resource.schema_url = setValue( + config.resource.schema_url, + parsedContent['resource']?.['schema_url'] + ); + setResourceAttributes(config, parsedContent['resource']?.['attributes']); + + setValuesFromEnvVariables(config); + } else { + console.log(`Unsupported File Format: ${parsedContent['file_format']}. It must be one of the following: ${supportedFileVersions}`); + throw new Error( + `Unsupported File Format: ${parsedContent['file_format']}. It must be one of the following: ${supportedFileVersions}` + ); + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function setValue(obj: unknown, value: unknown): any { + if (value) { + return value; + } + if (typeof obj === 'boolean') { + const raw = String(value)?.trim().toLowerCase(); + if (raw === 'false') { + return false; + } + } + return obj; +} + +/** + * Some values can only be set by Environment Variables and + * not declarative configuration. This function set those values. + * @param config + */ +function setValuesFromEnvVariables(config: ConfigurationModel) { + const nodeResourceDetectors = getStringListFromEnv( + 'OTEL_NODE_RESOURCE_DETECTORS' + ); + if (nodeResourceDetectors) { + config.node_resource_detectors = nodeResourceDetectors; + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function setResourceAttributes(config: ConfigurationModel, attributes: any[]) { + if (attributes) { + config.resource.attributes = []; + for (let i = 0; i < attributes.length; i++) { + const att = attributes[i]; + config.resource.attributes.push({ + name: att['name'], + value: att['value'], + type: att['type'] ?? 'string', + }); + } + } +} diff --git a/experimental/packages/opentelemetry-configuration/src/configModel.ts b/experimental/packages/opentelemetry-configuration/src/configModel.ts index 3791b554ce4..83eaf6e6473 100644 --- a/experimental/packages/opentelemetry-configuration/src/configModel.ts +++ b/experimental/packages/opentelemetry-configuration/src/configModel.ts @@ -21,7 +21,7 @@ export interface ConfigurationModel { * Configure if the SDK is disabled or not. * If omitted or null, false is used. */ - disable: boolean; + disabled: boolean; /** * Configure the log level of the internal logger used by the SDK. @@ -44,7 +44,7 @@ export interface ConfigurationModel { export function initializeDefaultConfiguration(): ConfigurationModel { const config: ConfigurationModel = { - disable: false, + disabled: true, log_level: DiagLogLevel.INFO, node_resource_detectors: ['all'], resource: {}, @@ -56,7 +56,7 @@ export function initializeDefaultConfiguration(): ConfigurationModel { export interface ConfigAttributes { name: string; value: string | boolean | number | string[] | boolean[] | number[]; - type?: + type: | 'string' | 'bool' | 'int' diff --git a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts index 8594f2f6198..d7e125cf43c 100644 --- a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts +++ b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts @@ -20,12 +20,69 @@ import { DiagLogLevel } from '@opentelemetry/api'; import { createConfigProvider } from '../src/ConfigProvider'; const defaultConfig: Configuration = { - disable: false, + disabled: false, log_level: DiagLogLevel.INFO, node_resource_detectors: ['all'], resource: {}, }; +const configFromFile: Configuration = { + disabled: false, + log_level: DiagLogLevel.DEBUG, + node_resource_detectors: ['all'], + resource: { + schema_url: 'https://opentelemetry.io/schemas/1.16.0', + attributes_list: 'service.namespace=my-namespace,service.version=1.0.0', + attributes: [ + { + name: 'service.name', + value: 'unknown_service', + type: 'string', + }, + { + name: 'string_key', + value: 'value', + type: 'string', + }, + { + name: 'bool_key', + value: true, + type: 'bool', + }, + { + name: 'int_key', + value: 1, + type: 'int', + }, + { + name: 'double_key', + value: 1.1, + type: 'double', + }, + { + name: 'string_array_key', + value: ['value1', 'value2'], + type: 'string_array', + }, + { + name: 'bool_array_key', + value: [true, false], + type: 'bool_array', + }, + { + name: 'int_array_key', + value: [1, 2], + type: 'int_array', + }, + { + name: 'double_array_key', + value: [1.1, 2.2], + type: 'double_array', + }, + ], + }, +}; + describe('ConfigProvider', function () { describe('get values from environment variables', function () { afterEach(function () { @@ -47,7 +104,7 @@ describe('ConfigProvider', function () { process.env.OTEL_SDK_DISABLED = 'true'; const expectedConfig: Configuration = { ...defaultConfig, - disable: true, + disabled: true, }; const configProvider = createConfigProvider(); assert.deepStrictEqual( @@ -111,7 +168,7 @@ describe('ConfigProvider', function () { const configProvider = createConfigProvider(); assert.deepStrictEqual( configProvider.getInstrumentationConfig(), - defaultConfig + configFromFile ); }); diff --git a/experimental/packages/opentelemetry-configuration/test/fixtures/kitchen-sink.yaml b/experimental/packages/opentelemetry-configuration/test/fixtures/kitchen-sink.yaml index a861d98b4a7..85c40c0526e 100644 --- a/experimental/packages/opentelemetry-configuration/test/fixtures/kitchen-sink.yaml +++ b/experimental/packages/opentelemetry-configuration/test/fixtures/kitchen-sink.yaml @@ -14,7 +14,7 @@ file_format: "1.0-rc.1" disabled: false # Configure the log level of the internal logger used by the SDK. # If omitted, info is used. -log_level: info +log_level: debug # Configure general attribute limits. See also tracer_provider.limits, logger_provider.limits. attribute_limits: # Configure max attribute value size. diff --git a/package-lock.json b/package-lock.json index 26e129d6384..fe0109b5a06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2458,7 +2458,8 @@ "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^2.0.1" + "@opentelemetry/core": "^2.0.1", + "yaml": "^1.10.2" }, "devDependencies": { "@opentelemetry/api": "^1.9.0", @@ -33367,7 +33368,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "license": "ISC", "engines": { "node": ">= 6" @@ -39386,7 +39386,8 @@ "nyc": "17.1.0", "sinon": "18.0.1", "ts-loader": "9.5.2", - "typescript": "5.0.4" + "typescript": "5.0.4", + "yaml": "^1.10.2" }, "dependencies": { "@types/node": { @@ -61462,8 +61463,7 @@ "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { "version": "17.7.2", From fcef5690f4fcc9483beba5c12158edb3f37838f8 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 22 Aug 2025 11:48:52 -0400 Subject: [PATCH 02/15] update changelog --- experimental/CHANGELOG.md | 2 +- .../opentelemetry-configuration/src/FileConfigProvider.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 082c8f64824..a53c0f85bb3 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -18,7 +18,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 *feat(opentelemetry-configuration): creation of basic ConfigProvider [#5809](https://github.com/open-telemetry/opentelemetry-js/pull/5809) @maryliag *feat(opentelemetry-configuration): creation of basic FileConfigProvider [#5863](https://github.com/open-telemetry/opentelemetry-js/pull/5863) @maryliag -*feat(opentelemetry-configuration): Parse of Configuration File [#](https://github.com/open-telemetry/opentelemetry-js/pull/) @maryliag +*feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag ### :bug: Bug Fixes diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index a56b530127b..d3a08fdb245 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -84,7 +84,6 @@ function ParseConfigFile(config: ConfigurationModel) { setValuesFromEnvVariables(config); } else { - console.log(`Unsupported File Format: ${parsedContent['file_format']}. It must be one of the following: ${supportedFileVersions}`); throw new Error( `Unsupported File Format: ${parsedContent['file_format']}. It must be one of the following: ${supportedFileVersions}` ); From 0f6a05a84a926aa40e58a5f5f876f79f7a22c35f Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 22 Aug 2025 13:48:18 -0400 Subject: [PATCH 03/15] add more tests --- .../src/EnvironmentConfigProvider.ts | 6 ++-- .../src/FileConfigProvider.ts | 34 +++++++++++++------ .../test/ConfigProvider.test.ts | 33 ++++++++++++++++++ .../test/fixtures/invalid.yaml | 1 + .../test/fixtures/short-config.yml | 2 ++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 experimental/packages/opentelemetry-configuration/test/fixtures/invalid.yaml create mode 100644 experimental/packages/opentelemetry-configuration/test/fixtures/short-config.yml diff --git a/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts index 0470ec3b17a..49c205cc138 100644 --- a/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { DiagLogLevel } from '@opentelemetry/api'; import { ConfigurationModel, initializeDefaultConfiguration, @@ -37,10 +36,9 @@ export class EnvironmentConfigProvider implements ConfigProvider { this._config = initializeDefaultConfiguration(); this._config.disabled = getBooleanFromEnv('OTEL_SDK_DISABLED'); - const logLevel = getStringFromEnv('OTEL_LOG_LEVEL'); + const logLevel = diagLogLevelFromString(getStringFromEnv('OTEL_LOG_LEVEL')); if (logLevel) { - this._config.log_level = - diagLogLevelFromString(logLevel) ?? DiagLogLevel.INFO; + this._config.log_level = logLevel; } const nodeResourceDetectors = getStringListFromEnv( diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index d3a08fdb245..ef3e57f220e 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -26,7 +26,6 @@ import { import { ConfigProvider } from './IConfigProvider'; import * as fs from 'fs'; import * as yaml from 'yaml'; -import { DiagLogLevel } from '@opentelemetry/api'; export class FileConfigProvider implements ConfigProvider { private _config: ConfigurationModel; @@ -67,19 +66,35 @@ function ParseConfigFile(config: ConfigurationModel) { parsedContent['file_format'] && supportedFileVersions.includes(parsedContent['file_format']) ) { - config.disabled = setValue(config.disabled, parsedContent['disabled']); - config.log_level = setValue( + const disabled = getValue(config.disabled, parsedContent['disabled']); + if (disabled || disabled === false) { + config.disabled = disabled; + } + + const logLevel = getValue( config.log_level, - diagLogLevelFromString(parsedContent['log_level']) ?? DiagLogLevel.INFO + diagLogLevelFromString(parsedContent['log_level']) ); - config.resource.attributes_list = setValue( + if (logLevel) { + config.log_level = logLevel; + } + + const attrList = getValue( config.resource.attributes_list, parsedContent['resource']?.['attributes_list'] ); - config.resource.schema_url = setValue( + if (attrList) { + config.resource.attributes_list = attrList; + } + + const schemaUrl = getValue( config.resource.schema_url, parsedContent['resource']?.['schema_url'] ); + if (schemaUrl) { + config.resource.schema_url = schemaUrl; + } + setResourceAttributes(config, parsedContent['resource']?.['attributes']); setValuesFromEnvVariables(config); @@ -91,17 +106,14 @@ function ParseConfigFile(config: ConfigurationModel) { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -function setValue(obj: unknown, value: unknown): any { - if (value) { - return value; - } +function getValue(obj: unknown, value: unknown): any { if (typeof obj === 'boolean') { const raw = String(value)?.trim().toLowerCase(); if (raw === 'false') { return false; } } - return obj; + return value; } /** diff --git a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts index d7e125cf43c..2add1de6ddc 100644 --- a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts +++ b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts @@ -160,6 +160,7 @@ describe('ConfigProvider', function () { describe('get values from config file', function () { afterEach(function () { delete process.env.OTEL_EXPERIMENTAL_CONFIG_FILE; + delete process.env.OTEL_NODE_RESOURCE_DETECTORS; }); it('should initialize config with default values from valid config file', function () { @@ -179,6 +180,13 @@ describe('ConfigProvider', function () { }); }); + it('should return error from invalid config file format', function () { + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = 'test/fixtures/invalid.yaml'; + assert.throws(() => { + createConfigProvider(); + }); + }); + it('should initialize config with default values with empty string for config file', function () { process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = ''; const configProvider = createConfigProvider(); @@ -196,5 +204,30 @@ describe('ConfigProvider', function () { defaultConfig ); }); + + it('should initialize config with default values from valid short config file', function () { + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = + 'test/fixtures/short-config.yml'; + const configProvider = createConfigProvider(); + assert.deepStrictEqual( + configProvider.getInstrumentationConfig(), + defaultConfig + ); + }); + + it('should initialize config with default values from valid config file and node resources', function () { + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = + 'test/fixtures/short-config.yml'; + process.env.OTEL_NODE_RESOURCE_DETECTORS = 'env,host, serviceinstance'; + const expectedConfig = { + ...defaultConfig, + node_resource_detectors: ['env', 'host', 'serviceinstance'], + }; + const configProvider = createConfigProvider(); + assert.deepStrictEqual( + configProvider.getInstrumentationConfig(), + expectedConfig + ); + }); }); }); diff --git a/experimental/packages/opentelemetry-configuration/test/fixtures/invalid.yaml b/experimental/packages/opentelemetry-configuration/test/fixtures/invalid.yaml new file mode 100644 index 00000000000..3d0a379779d --- /dev/null +++ b/experimental/packages/opentelemetry-configuration/test/fixtures/invalid.yaml @@ -0,0 +1 @@ +file_format: "invalid" \ No newline at end of file diff --git a/experimental/packages/opentelemetry-configuration/test/fixtures/short-config.yml b/experimental/packages/opentelemetry-configuration/test/fixtures/short-config.yml new file mode 100644 index 00000000000..984c87c34a8 --- /dev/null +++ b/experimental/packages/opentelemetry-configuration/test/fixtures/short-config.yml @@ -0,0 +1,2 @@ +file_format: "1.0-rc.1" +disabled: false \ No newline at end of file From eeb69f57f911c3050a0a504fad7f621c7943aaf9 Mon Sep 17 00:00:00 2001 From: Marylia Gutierrez Date: Tue, 16 Sep 2025 11:29:39 -0400 Subject: [PATCH 04/15] Update experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts Co-authored-by: Marc Pichler --- .../opentelemetry-configuration/src/FileConfigProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index ef3e57f220e..b7daf55d79d 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -56,7 +56,7 @@ export function hasValidConfigFile(): boolean { return false; } -function ParseConfigFile(config: ConfigurationModel) { +function parseConfigFile(config: ConfigurationModel) { const supportedFileVersions = ['1.0-rc.1']; const configFile = getStringFromEnv('OTEL_EXPERIMENTAL_CONFIG_FILE') || ''; const file = fs.readFileSync(configFile, 'utf8'); From 73fe9afe7e965efb9288f391377cc0fffb2dcbbb Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 16 Sep 2025 11:47:05 -0400 Subject: [PATCH 05/15] changes from feedback --- .../src/FileConfigProvider.ts | 1 - .../test/ConfigProvider.test.ts | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index 72d142d0760..3c0b08e9392 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -17,7 +17,6 @@ import { diagLogLevelFromString, getStringFromEnv, - getStringListFromEnv, } from '@opentelemetry/core'; import { ConfigurationModel, diff --git a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts index 2add1de6ddc..e7ea0365532 100644 --- a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts +++ b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts @@ -214,20 +214,5 @@ describe('ConfigProvider', function () { defaultConfig ); }); - - it('should initialize config with default values from valid config file and node resources', function () { - process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = - 'test/fixtures/short-config.yml'; - process.env.OTEL_NODE_RESOURCE_DETECTORS = 'env,host, serviceinstance'; - const expectedConfig = { - ...defaultConfig, - node_resource_detectors: ['env', 'host', 'serviceinstance'], - }; - const configProvider = createConfigProvider(); - assert.deepStrictEqual( - configProvider.getInstrumentationConfig(), - expectedConfig - ); - }); }); }); From 7a1aec4cb4d43871e0462a45682f61f84ffe4ae5 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 16 Sep 2025 12:42:11 -0400 Subject: [PATCH 06/15] create function by paramtre type --- .../opentelemetry-configuration/package.json | 1 + .../src/FileConfigProvider.ts | 32 +++----- .../opentelemetry-configuration/src/utils.ts | 79 +++++++++++++++++++ .../test/utils.test.ts | 69 ++++++++++++++++ 4 files changed, 159 insertions(+), 22 deletions(-) create mode 100644 experimental/packages/opentelemetry-configuration/src/utils.ts create mode 100644 experimental/packages/opentelemetry-configuration/test/utils.test.ts diff --git a/experimental/packages/opentelemetry-configuration/package.json b/experimental/packages/opentelemetry-configuration/package.json index 04cda7ff471..1f9513ccdfe 100644 --- a/experimental/packages/opentelemetry-configuration/package.json +++ b/experimental/packages/opentelemetry-configuration/package.json @@ -49,6 +49,7 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", + "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index 3c0b08e9392..7f6204061d6 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - diagLogLevelFromString, - getStringFromEnv, -} from '@opentelemetry/core'; +import { diagLogLevelFromString, getStringFromEnv } from '@opentelemetry/core'; import { ConfigurationModel, initializeDefaultConfiguration, @@ -25,6 +22,11 @@ import { import { ConfigProvider } from './IConfigProvider'; import * as fs from 'fs'; import * as yaml from 'yaml'; +import { + getBooleanFromConfigFile, + getNumberFromConfigFile, + getStringFromConfigFile, +} from './utils'; export class FileConfigProvider implements ConfigProvider { private _config: ConfigurationModel; @@ -65,29 +67,26 @@ function parseConfigFile(config: ConfigurationModel) { parsedContent['file_format'] && supportedFileVersions.includes(parsedContent['file_format']) ) { - const disabled = getValue(config.disabled, parsedContent['disabled']); + const disabled = getBooleanFromConfigFile(parsedContent['disabled']); if (disabled || disabled === false) { config.disabled = disabled; } - const logLevel = getValue( - config.log_level, + const logLevel = getNumberFromConfigFile( diagLogLevelFromString(parsedContent['log_level']) ); if (logLevel) { config.log_level = logLevel; } - const attrList = getValue( - config.resource.attributes_list, + const attrList = getStringFromConfigFile( parsedContent['resource']?.['attributes_list'] ); if (attrList) { config.resource.attributes_list = attrList; } - const schemaUrl = getValue( - config.resource.schema_url, + const schemaUrl = getStringFromConfigFile( parsedContent['resource']?.['schema_url'] ); if (schemaUrl) { @@ -102,17 +101,6 @@ function parseConfigFile(config: ConfigurationModel) { } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function getValue(obj: unknown, value: unknown): any { - if (typeof obj === 'boolean') { - const raw = String(value)?.trim().toLowerCase(); - if (raw === 'false') { - return false; - } - } - return value; -} - // eslint-disable-next-line @typescript-eslint/no-explicit-any function setResourceAttributes(config: ConfigurationModel, attributes: any[]) { if (attributes) { diff --git a/experimental/packages/opentelemetry-configuration/src/utils.ts b/experimental/packages/opentelemetry-configuration/src/utils.ts new file mode 100644 index 00000000000..56ad4a41196 --- /dev/null +++ b/experimental/packages/opentelemetry-configuration/src/utils.ts @@ -0,0 +1,79 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { diag } from '@opentelemetry/api'; +import { inspect } from 'util'; + +/** + * Retrieves a boolean value from a configuration file parameter. + * - Trims leading and trailing whitespace and ignores casing. + * - Returns `undefined` if the value is empty, unset, or contains only whitespace. + * - Returns `undefined` and a warning for values that cannot be mapped to a boolean. + * + * @param {unknown} value - The value from the config file. + * @returns {boolean} - The boolean value or `false` if the environment variable is unset empty, unset, or contains only whitespace. + */ +export function getBooleanFromConfigFile(value: unknown): boolean | undefined { + const raw = String(value)?.trim().toLowerCase(); + if (raw === 'true') { + return true; + } else if (raw === 'false') { + return false; + } else if (raw == null || raw === '') { + return undefined; + } else { + diag.warn(`Unknown value ${inspect(raw)}, expected 'true' or 'false'`); + return undefined; + } +} + +/** + * Retrieves a number from a configuration file parameter. + * - Returns `undefined` if the environment variable is empty, unset, or contains only whitespace. + * - Returns `undefined` and a warning if is not a number. + * - Returns a number in all other cases. + * + * @param {unknown} value - The value from the config file. + * @returns {number | undefined} - The number value or `undefined`. + */ +export function getNumberFromConfigFile(value: unknown): number | undefined { + const raw = String(value)?.trim(); + if (raw == null || raw.trim() === '') { + return undefined; + } + + const n = Number(raw); + if (isNaN(n)) { + diag.warn(`Unknown value ${inspect(raw)}, expected a number`); + return undefined; + } + + return n; +} + +/** + * Retrieves a string from a configuration file parameter. + * - Returns `undefined` if the environment variable is empty, unset, or contains only whitespace. + * + * @param {unknown} value - The value from the config file. + * @returns {string | undefined} - The string value or `undefined`. + */ +export function getStringFromConfigFile(value: unknown): string | undefined { + const raw = String(value)?.trim(); + if (value == null || raw === '') { + return undefined; + } + return raw; +} diff --git a/experimental/packages/opentelemetry-configuration/test/utils.test.ts b/experimental/packages/opentelemetry-configuration/test/utils.test.ts new file mode 100644 index 00000000000..7adf6d93a9e --- /dev/null +++ b/experimental/packages/opentelemetry-configuration/test/utils.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import { diag } from '@opentelemetry/api'; +import { + getBooleanFromConfigFile, + getNumberFromConfigFile, + getStringFromConfigFile, +} from '../src/utils'; + +describe('config utils', function () { + afterEach(function () { + sinon.restore(); + }); + + it('should return correct values for getBooleanFromConfigFile', function () { + assert.strictEqual(getBooleanFromConfigFile(null), undefined); + assert.strictEqual(getBooleanFromConfigFile(' '), undefined); + assert.strictEqual(getBooleanFromConfigFile(true), true); + assert.strictEqual(getBooleanFromConfigFile('true'), true); + assert.strictEqual(getBooleanFromConfigFile(false), false); + assert.strictEqual(getBooleanFromConfigFile('false'), false); + + const warnStub = sinon.stub(diag, 'warn'); + assert.strictEqual(getBooleanFromConfigFile('non-boolean'), undefined); + sinon.assert.calledOnceWithMatch( + warnStub, + `Unknown value 'non-boolean', expected 'true' or 'false'` + ); + }); + + it('should return correct values for getNumberFromConfigFile', function () { + assert.strictEqual(getNumberFromConfigFile(null), undefined); + assert.strictEqual(getNumberFromConfigFile(' '), undefined); + assert.strictEqual(getNumberFromConfigFile(1), 1); + assert.strictEqual(getNumberFromConfigFile(0), 0); + assert.strictEqual(getNumberFromConfigFile(100), 100); + + const warnStub = sinon.stub(diag, 'warn'); + assert.strictEqual(getNumberFromConfigFile('non-number'), undefined); + sinon.assert.calledOnceWithMatch( + warnStub, + `Unknown value 'non-number', expected a number` + ); + }); + + it('should return correct values for getStringFromConfigFile', function () { + assert.strictEqual(getStringFromConfigFile(null), undefined); + assert.strictEqual(getStringFromConfigFile(' '), undefined); + assert.strictEqual(getStringFromConfigFile(undefined), undefined); + assert.strictEqual(getStringFromConfigFile(1), '1'); + assert.strictEqual(getStringFromConfigFile('string-value'), 'string-value'); + }); +}); From 2297ee9ad8eee60be3ec21a28ee2ca4d1b0d3779 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 16 Sep 2025 12:44:04 -0400 Subject: [PATCH 07/15] update package lock --- package-lock.json | 243 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/package-lock.json b/package-lock.json index 41133e40980..03ffba5dba4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -834,6 +834,7 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", + "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", @@ -852,6 +853,92 @@ "dev": true, "license": "MIT" }, + "experimental/packages/opentelemetry-configuration/node_modules/eslint-plugin-n": { + "version": "17.23.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.0.tgz", + "integrity": "sha512-aPePGxUr5LezcXmMRBF83eK1MmqUYY1NdLdHC+jdpfc5b98eL7yDXY20gXJ6DcTxrHBhrLsfYYqo7J+m0h9YXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" + } + }, + "experimental/packages/opentelemetry-configuration/node_modules/eslint-plugin-n/node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "experimental/packages/opentelemetry-configuration/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "experimental/packages/opentelemetry-configuration/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "experimental/packages/opentelemetry-configuration/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "experimental/packages/opentelemetry-exporter-metrics-otlp-grpc": { "name": "@opentelemetry/exporter-metrics-otlp-grpc", "version": "0.205.0", @@ -11182,6 +11269,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/eslint-config-prettier": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", @@ -11218,6 +11321,28 @@ "eslint": ">=4.19.1" } }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, "node_modules/eslint-plugin-es/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -12740,6 +12865,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-uri": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", @@ -13014,6 +13152,13 @@ "node": ">= 4" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -21833,6 +21978,16 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -30038,6 +30193,7 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", + "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", @@ -30052,6 +30208,52 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", "dev": true + }, + "eslint-plugin-n": { + "version": "17.23.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.0.tgz", + "integrity": "sha512-aPePGxUr5LezcXmMRBF83eK1MmqUYY1NdLdHC+jdpfc5b98eL7yDXY20gXJ6DcTxrHBhrLsfYYqo7J+m0h9YXQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" + }, + "dependencies": { + "ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "requires": { + "picomatch": "^4.0.2" + } + } + } + }, + "globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true + }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true } } }, @@ -35221,6 +35423,15 @@ } } }, + "eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "requires": { + "semver": "^7.5.4" + } + }, "eslint-config-prettier": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", @@ -35255,6 +35466,17 @@ } } }, + "eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + } + }, "eslint-plugin-header": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", @@ -36253,6 +36475,15 @@ "pump": "^3.0.0" } }, + "get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "get-uri": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", @@ -36442,6 +36673,12 @@ } } }, + "globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, "gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -42616,6 +42853,12 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", From 97d90138fc22159a6a87526177e64d7acb391cac Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 16 Sep 2025 12:59:11 -0400 Subject: [PATCH 08/15] fix disabled --- .../packages/opentelemetry-configuration/src/configModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-configuration/src/configModel.ts b/experimental/packages/opentelemetry-configuration/src/configModel.ts index 83eaf6e6473..2e7b2ccf496 100644 --- a/experimental/packages/opentelemetry-configuration/src/configModel.ts +++ b/experimental/packages/opentelemetry-configuration/src/configModel.ts @@ -44,7 +44,7 @@ export interface ConfigurationModel { export function initializeDefaultConfiguration(): ConfigurationModel { const config: ConfigurationModel = { - disabled: true, + disabled: false, log_level: DiagLogLevel.INFO, node_resource_detectors: ['all'], resource: {}, From 1c3ce03f057dbc666a9ae789823e5b919e497269 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 19 Sep 2025 12:15:48 -0400 Subject: [PATCH 09/15] fix changelog --- experimental/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index db1298a0f8b..8ab3ad8a3eb 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -10,6 +10,8 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 ### :rocket: Features +* feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag + ### :bug: Bug Fixes * fix(instrumentation-http): respect requireParent flag when INVALID_SPAN_CONTEXT is used [#4788](https://github.com/open-telemetry/opentelemetry-js/pull/4788) @reberhardt7 @@ -48,7 +50,6 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 * when using headers, the Browser exporter now prefers `fetch` over `XMLHttpRequest` if present. Sending via `XMLHttpRequest` will be removed in a future release. * feat(opentelemetry-configuration): creation of basic ConfigProvider [#5809](https://github.com/open-telemetry/opentelemetry-js/pull/5809) @maryliag * feat(opentelemetry-configuration): creation of basic FileConfigProvider [#5863](https://github.com/open-telemetry/opentelemetry-js/pull/5863) @maryliag -* feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag * feat(sdk-node): Add support for multiple metric readers via the new `metricReaders` option in NodeSDK configuration. Users can now register multiple metric readers (e.g., Console, Prometheus) directly through the NodeSDK constructor. The old `metricReader` (singular) option is now deprecated and will show a warning if used, but remains supported for backward compatibility. Comprehensive tests and documentation have been added. [#5760](https://github.com/open-telemetry/opentelemetry-js/issues/5760) * **Migration:** - Before: From de08a18b46cdfc4b9ad12e35e65b54dc9c93705f Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 19 Sep 2025 22:32:29 -0400 Subject: [PATCH 10/15] remove import --- .../opentelemetry-configuration/package.json | 1 - package-lock.json | 243 ------------------ 2 files changed, 244 deletions(-) diff --git a/experimental/packages/opentelemetry-configuration/package.json b/experimental/packages/opentelemetry-configuration/package.json index 1f9513ccdfe..04cda7ff471 100644 --- a/experimental/packages/opentelemetry-configuration/package.json +++ b/experimental/packages/opentelemetry-configuration/package.json @@ -49,7 +49,6 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", - "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", diff --git a/package-lock.json b/package-lock.json index 8735aeb3c3a..45cf14f0b5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -834,7 +834,6 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", - "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", @@ -853,92 +852,6 @@ "dev": true, "license": "MIT" }, - "experimental/packages/opentelemetry-configuration/node_modules/eslint-plugin-n": { - "version": "17.23.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.0.tgz", - "integrity": "sha512-aPePGxUr5LezcXmMRBF83eK1MmqUYY1NdLdHC+jdpfc5b98eL7yDXY20gXJ6DcTxrHBhrLsfYYqo7J+m0h9YXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.5.0", - "enhanced-resolve": "^5.17.1", - "eslint-plugin-es-x": "^7.8.0", - "get-tsconfig": "^4.8.1", - "globals": "^15.11.0", - "globrex": "^0.1.2", - "ignore": "^5.3.2", - "semver": "^7.6.3", - "ts-declaration-location": "^1.0.6" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": ">=8.23.0" - } - }, - "experimental/packages/opentelemetry-configuration/node_modules/eslint-plugin-n/node_modules/ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", - "dev": true, - "funding": [ - { - "type": "ko-fi", - "url": "https://ko-fi.com/rebeccastevens" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" - } - ], - "license": "BSD-3-Clause", - "dependencies": { - "picomatch": "^4.0.2" - }, - "peerDependencies": { - "typescript": ">=4.0.0" - } - }, - "experimental/packages/opentelemetry-configuration/node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "experimental/packages/opentelemetry-configuration/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "experimental/packages/opentelemetry-configuration/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "experimental/packages/opentelemetry-exporter-metrics-otlp-grpc": { "name": "@opentelemetry/exporter-metrics-otlp-grpc", "version": "0.205.0", @@ -11269,22 +11182,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, "node_modules/eslint-config-prettier": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", @@ -11321,28 +11218,6 @@ "eslint": ">=4.19.1" } }, - "node_modules/eslint-plugin-es-x": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", - "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/ota-meshi", - "https://opencollective.com/eslint" - ], - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.11.0", - "eslint-compat-utils": "^0.5.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, "node_modules/eslint-plugin-es/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -12865,19 +12740,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, "node_modules/get-uri": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", @@ -13152,13 +13014,6 @@ "node": ">= 4" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true, - "license": "MIT" - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -21978,16 +21833,6 @@ "node": ">=8" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -30193,7 +30038,6 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", - "eslint-plugin-n": "^17.23.0", "lerna": "6.6.2", "mocha": "11.7.2", "nyc": "17.1.0", @@ -30208,52 +30052,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", "dev": true - }, - "eslint-plugin-n": { - "version": "17.23.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.0.tgz", - "integrity": "sha512-aPePGxUr5LezcXmMRBF83eK1MmqUYY1NdLdHC+jdpfc5b98eL7yDXY20gXJ6DcTxrHBhrLsfYYqo7J+m0h9YXQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.5.0", - "enhanced-resolve": "^5.17.1", - "eslint-plugin-es-x": "^7.8.0", - "get-tsconfig": "^4.8.1", - "globals": "^15.11.0", - "globrex": "^0.1.2", - "ignore": "^5.3.2", - "semver": "^7.6.3", - "ts-declaration-location": "^1.0.6" - }, - "dependencies": { - "ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", - "dev": true, - "requires": { - "picomatch": "^4.0.2" - } - } - } - }, - "globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "dev": true - }, - "ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true - }, - "picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true } } }, @@ -35423,15 +35221,6 @@ } } }, - "eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "requires": { - "semver": "^7.5.4" - } - }, "eslint-config-prettier": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", @@ -35466,17 +35255,6 @@ } } }, - "eslint-plugin-es-x": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", - "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.11.0", - "eslint-compat-utils": "^0.5.1" - } - }, "eslint-plugin-header": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", @@ -36475,15 +36253,6 @@ "pump": "^3.0.0" } }, - "get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", - "dev": true, - "requires": { - "resolve-pkg-maps": "^1.0.0" - } - }, "get-uri": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", @@ -36673,12 +36442,6 @@ } } }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, "gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -42853,12 +42616,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true - }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", From a662970e812b97716908d55c240cacd171f1f136 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 19 Sep 2025 22:35:42 -0400 Subject: [PATCH 11/15] feat(sampler-composite): add experimental implementation of composite sampling spec (#5839) Co-authored-by: Trent Mick --- experimental/CHANGELOG.md | 1 + .../packages/sampler-composite/.eslintignore | 1 + .../packages/sampler-composite/.eslintrc.js | 8 + .../packages/sampler-composite/README.md | 57 +++ .../packages/sampler-composite/package.json | 70 +++ .../sampler-composite/src/alwaysoff.ts | 41 ++ .../sampler-composite/src/alwayson.ts | 41 ++ .../sampler-composite/src/composite.ts | 126 ++++++ .../packages/sampler-composite/src/index.ts | 22 + .../sampler-composite/src/parentthreshold.ts | 89 ++++ .../sampler-composite/src/traceidratio.ts | 78 ++++ .../sampler-composite/src/tracestate.ts | 156 +++++++ .../packages/sampler-composite/src/types.ts | 44 ++ .../packages/sampler-composite/src/util.ts | 31 ++ .../sampler-composite/test/alwaysoff.test.ts | 72 +++ .../sampler-composite/test/alwayson.test.ts | 72 +++ .../sampler-composite/test/sampler.test.ts | 192 ++++++++ .../test/traceidratio.test.ts | 87 ++++ .../sampler-composite/test/tracestate.test.ts | 70 +++ .../packages/sampler-composite/test/util.ts | 48 ++ .../sampler-composite/tsconfig.esm.json | 23 + .../sampler-composite/tsconfig.esnext.json | 23 + .../packages/sampler-composite/tsconfig.json | 24 + package-lock.json | 424 ++++++++++++++++++ tsconfig.esm.json | 3 + tsconfig.esnext.json | 3 + tsconfig.json | 4 + 27 files changed, 1810 insertions(+) create mode 100644 experimental/packages/sampler-composite/.eslintignore create mode 100644 experimental/packages/sampler-composite/.eslintrc.js create mode 100644 experimental/packages/sampler-composite/README.md create mode 100644 experimental/packages/sampler-composite/package.json create mode 100644 experimental/packages/sampler-composite/src/alwaysoff.ts create mode 100644 experimental/packages/sampler-composite/src/alwayson.ts create mode 100644 experimental/packages/sampler-composite/src/composite.ts create mode 100644 experimental/packages/sampler-composite/src/index.ts create mode 100644 experimental/packages/sampler-composite/src/parentthreshold.ts create mode 100644 experimental/packages/sampler-composite/src/traceidratio.ts create mode 100644 experimental/packages/sampler-composite/src/tracestate.ts create mode 100644 experimental/packages/sampler-composite/src/types.ts create mode 100644 experimental/packages/sampler-composite/src/util.ts create mode 100644 experimental/packages/sampler-composite/test/alwaysoff.test.ts create mode 100644 experimental/packages/sampler-composite/test/alwayson.test.ts create mode 100644 experimental/packages/sampler-composite/test/sampler.test.ts create mode 100644 experimental/packages/sampler-composite/test/traceidratio.test.ts create mode 100644 experimental/packages/sampler-composite/test/tracestate.test.ts create mode 100644 experimental/packages/sampler-composite/test/util.ts create mode 100644 experimental/packages/sampler-composite/tsconfig.esm.json create mode 100644 experimental/packages/sampler-composite/tsconfig.esnext.json create mode 100644 experimental/packages/sampler-composite/tsconfig.json diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 8ab3ad8a3eb..c53f0ab68c0 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -10,6 +10,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 ### :rocket: Features +* feat(sampler-composite): Added experimental implementations of draft composite sampling spec [#5839](https://github.com/open-telemetry/opentelemetry-js/pull/5839) @anuraaga * feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag ### :bug: Bug Fixes diff --git a/experimental/packages/sampler-composite/.eslintignore b/experimental/packages/sampler-composite/.eslintignore new file mode 100644 index 00000000000..378eac25d31 --- /dev/null +++ b/experimental/packages/sampler-composite/.eslintignore @@ -0,0 +1 @@ +build diff --git a/experimental/packages/sampler-composite/.eslintrc.js b/experimental/packages/sampler-composite/.eslintrc.js new file mode 100644 index 00000000000..0fe1bbf975f --- /dev/null +++ b/experimental/packages/sampler-composite/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + "env": { + "mocha": true, + "commonjs": true, + "shared-node-browser": true + }, + ...require('../../../eslint.base.js') +} diff --git a/experimental/packages/sampler-composite/README.md b/experimental/packages/sampler-composite/README.md new file mode 100644 index 00000000000..6fce8346e41 --- /dev/null +++ b/experimental/packages/sampler-composite/README.md @@ -0,0 +1,57 @@ +# OpenTelemetry Composite Sampling + +[![NPM Published Version][npm-img]][npm-url] +[![Apache License][license-image]][license-image] + +**Note: This is an experimental package under active development. New releases may include breaking changes.** + +This package provides implementations of composite samplers that propagate sampling information across a trace. +This implements the [experimental specification][probability-sampling]. + +Currently `ComposableRuleBased` and `ComposableAnnotating` are not implemented. + +## Quick Start + +To get started you will need to install a compatible OpenTelemetry SDK. + +### Samplers + +This module exports samplers that follow the general behavior of the standard SDK samplers, but ensuring +it is consistent across a trace by using the tracestate header. Notably, the tracestate can be examined +in exported spans to reconstruct population metrics. + +```typescript +import { + createCompositeSampler, + createComposableAlwaysOffSampler, + createComposableAlwaysOnSampler, + createComposableParentThresholdSampler, + createComposableTraceIDRatioBasedSampler, +} from '@opentelemetry/sampler-composite'; + +// never sample +const sampler = createCompositeSampler(createComposableAlwaysOffSampler()); +// always sample +const sampler = createCompositeSampler(createComposableAlwaysOnSampler()); +// follow the parent, or otherwise sample with a probability if root +const sampler = createCompositeSampler( + createComposableParentThresholdSampler(createComposableTraceIDRatioBasedSampler(0.3))); +``` + +## Useful links + +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[npm-url]: https://www.npmjs.com/package/@opentelemetry/sampler-composite +[npm-img]: https://badge.fury.io/js/%40opentelemetry%sampler-composite.svg + +[probability-sampling]: https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/ diff --git a/experimental/packages/sampler-composite/package.json b/experimental/packages/sampler-composite/package.json new file mode 100644 index 00000000000..fef7b992500 --- /dev/null +++ b/experimental/packages/sampler-composite/package.json @@ -0,0 +1,70 @@ +{ + "name": "@opentelemetry/sampler-composite", + "private": false, + "publishConfig": { + "access": "public" + }, + "version": "0.205.0", + "description": "Composite samplers for OpenTelemetry tracing", + "module": "build/esm/index.js", + "esnext": "build/esnext/index.js", + "types": "build/src/index.d.ts", + "main": "build/src/index.js", + "repository": "open-telemetry/opentelemetry-js", + "scripts": { + "prepublishOnly": "npm run compile", + "compile": "tsc --build", + "clean": "tsc --build --clean", + "test": "nyc mocha 'test/**/*.test.ts'", + "tdd": "npm run test -- --watch-extensions ts --watch", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "version": "node ../../../scripts/version-update.js", + "watch": "tsc --build --watch", + "precompile": "lerna run version --scope @opentelemetry/sampler-composite --include-dependencies", + "prewatch": "npm run precompile", + "peer-api-check": "node ../../../scripts/peer-api-check.js", + "align-api-deps": "node ../../../scripts/align-api-deps.js" + }, + "keywords": [ + "opentelemetry", + "nodejs", + "sampling", + "tracing" + ], + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "files": [ + "build/esm/**/*.js", + "build/esm/**/*.js.map", + "build/esm/**/*.d.ts", + "build/esnext/**/*.js", + "build/esnext/**/*.js.map", + "build/esnext/**/*.d.ts", + "build/src/**/*.js", + "build/src/**/*.js.map", + "build/src/**/*.d.ts", + "LICENSE", + "README.md" + ], + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "devDependencies": { + "@opentelemetry/api": "1.9.0", + "@types/mocha": "10.0.10", + "@types/node": "18.6.5", + "lerna": "6.6.2", + "mocha": "11.1.0", + "nyc": "17.1.0" + }, + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/sampler-composite", + "sideEffects": false +} diff --git a/experimental/packages/sampler-composite/src/alwaysoff.ts b/experimental/packages/sampler-composite/src/alwaysoff.ts new file mode 100644 index 00000000000..2c41635cdee --- /dev/null +++ b/experimental/packages/sampler-composite/src/alwaysoff.ts @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { ComposableSampler, SamplingIntent } from './types'; +import { INVALID_THRESHOLD } from './util'; + +const intent: SamplingIntent = { + threshold: INVALID_THRESHOLD, + thresholdReliable: false, +}; + +class ComposableAlwaysOffSampler implements ComposableSampler { + getSamplingIntent(): SamplingIntent { + return intent; + } + + toString(): string { + return 'ComposableAlwaysOffSampler'; + } +} + +const _sampler = new ComposableAlwaysOffSampler(); + +/** + * Returns a composable sampler that does not sample any span. + */ +export function createComposableAlwaysOffSampler(): ComposableSampler { + return _sampler; +} diff --git a/experimental/packages/sampler-composite/src/alwayson.ts b/experimental/packages/sampler-composite/src/alwayson.ts new file mode 100644 index 00000000000..832d81e665b --- /dev/null +++ b/experimental/packages/sampler-composite/src/alwayson.ts @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { ComposableSampler, SamplingIntent } from './types'; +import { MIN_THRESHOLD } from './util'; + +const intent: SamplingIntent = { + threshold: MIN_THRESHOLD, + thresholdReliable: true, +}; + +class ComposableAlwaysOnSampler implements ComposableSampler { + getSamplingIntent(): SamplingIntent { + return intent; + } + + toString(): string { + return 'ComposableAlwaysOnSampler'; + } +} + +const _sampler = new ComposableAlwaysOnSampler(); + +/** + * Returns a composable sampler that samples all span. + */ +export function createComposableAlwaysOnSampler(): ComposableSampler { + return _sampler; +} diff --git a/experimental/packages/sampler-composite/src/composite.ts b/experimental/packages/sampler-composite/src/composite.ts new file mode 100644 index 00000000000..0a8a90e0620 --- /dev/null +++ b/experimental/packages/sampler-composite/src/composite.ts @@ -0,0 +1,126 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Context, + SpanKind, + Attributes, + Link, + TraceState, + trace, +} from '@opentelemetry/api'; +import { TraceState as CoreTraceState } from '@opentelemetry/core'; +import { + Sampler, + SamplingDecision, + SamplingResult, +} from '@opentelemetry/sdk-trace-base'; +import { ComposableSampler } from './types'; +import { parseOtelTraceState, serializeTraceState } from './tracestate'; +import { + INVALID_THRESHOLD, + isValidRandomValue, + isValidThreshold, +} from './util'; + +class CompositeSampler implements Sampler { + constructor(private readonly delegate: ComposableSampler) {} + + shouldSample( + context: Context, + traceId: string, + spanName: string, + spanKind: SpanKind, + attributes: Attributes, + links: Link[] + ): SamplingResult { + const spanContext = trace.getSpanContext(context); + + const traceState = spanContext?.traceState; + let otTraceState = parseOtelTraceState(traceState); + + const intent = this.delegate.getSamplingIntent( + context, + traceId, + spanName, + spanKind, + attributes, + links + ); + + let adjustedCountCorrect = false; + let sampled = false; + if (isValidThreshold(intent.threshold)) { + adjustedCountCorrect = intent.thresholdReliable; + let randomness: bigint; + if (isValidRandomValue(otTraceState.randomValue)) { + randomness = otTraceState.randomValue; + } else { + // Use last 56 bits of trace_id as randomness. + randomness = BigInt(`0x${traceId.slice(-14)}`); + } + sampled = intent.threshold <= randomness; + } + + const decision = sampled + ? SamplingDecision.RECORD_AND_SAMPLED + : SamplingDecision.NOT_RECORD; + if (sampled && adjustedCountCorrect) { + otTraceState = { + ...otTraceState, + threshold: intent.threshold, + }; + } else { + otTraceState = { + ...otTraceState, + threshold: INVALID_THRESHOLD, + }; + } + + const otts = serializeTraceState(otTraceState); + + let newTraceState: TraceState | undefined; + if (traceState) { + newTraceState = traceState; + if (intent.updateTraceState) { + newTraceState = intent.updateTraceState(newTraceState); + } + } + if (otts) { + if (!newTraceState) { + newTraceState = new CoreTraceState(); + } + newTraceState = newTraceState.set('ot', otts); + } + + return { + decision, + attributes: intent.attributes, + traceState: newTraceState, + }; + } + + toString(): string { + return this.delegate.toString(); + } +} + +/** + * Returns a composite sampler that uses a composable sampler to make its + * sampling decisions while handling tracestate. + */ +export function createCompositeSampler(delegate: ComposableSampler): Sampler { + return new CompositeSampler(delegate); +} diff --git a/experimental/packages/sampler-composite/src/index.ts b/experimental/packages/sampler-composite/src/index.ts new file mode 100644 index 00000000000..91e68bf22e6 --- /dev/null +++ b/experimental/packages/sampler-composite/src/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { createComposableAlwaysOffSampler } from './alwaysoff'; +export { createComposableAlwaysOnSampler } from './alwayson'; +export { createComposableTraceIDRatioBasedSampler } from './traceidratio'; +export { createComposableParentThresholdSampler } from './parentthreshold'; +export { createCompositeSampler } from './composite'; +export type { ComposableSampler, SamplingIntent } from './types'; diff --git a/experimental/packages/sampler-composite/src/parentthreshold.ts b/experimental/packages/sampler-composite/src/parentthreshold.ts new file mode 100644 index 00000000000..a01a8d4eda1 --- /dev/null +++ b/experimental/packages/sampler-composite/src/parentthreshold.ts @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Attributes, + Context, + isSpanContextValid, + Link, + SpanKind, + TraceFlags, + trace, +} from '@opentelemetry/api'; +import { ComposableSampler, SamplingIntent } from './types'; +import { parseOtelTraceState } from './tracestate'; +import { INVALID_THRESHOLD, isValidThreshold, MIN_THRESHOLD } from './util'; + +class ComposableParentThresholdSampler implements ComposableSampler { + private readonly description: string; + + constructor(private readonly rootSampler: ComposableSampler) { + this.description = `ComposableParentThresholdSampler(rootSampler=${rootSampler})`; + } + + getSamplingIntent( + context: Context, + traceId: string, + spanName: string, + spanKind: SpanKind, + attributes: Attributes, + links: Link[] + ): SamplingIntent { + const parentSpanContext = trace.getSpanContext(context); + if (!parentSpanContext || !isSpanContextValid(parentSpanContext)) { + return this.rootSampler.getSamplingIntent( + context, + traceId, + spanName, + spanKind, + attributes, + links + ); + } + + const otTraceState = parseOtelTraceState(parentSpanContext.traceState); + + if (isValidThreshold(otTraceState.threshold)) { + return { + threshold: otTraceState.threshold, + thresholdReliable: true, + }; + } + + const threshold = + parentSpanContext.traceFlags & TraceFlags.SAMPLED + ? MIN_THRESHOLD + : INVALID_THRESHOLD; + return { + threshold, + thresholdReliable: false, + }; + } + + toString(): string { + return this.description; + } +} + +/** + * Returns a composable sampler that respects the sampling decision of the + * parent span or falls back to the given sampler if it is a root span. + */ +export function createComposableParentThresholdSampler( + rootSampler: ComposableSampler +): ComposableSampler { + return new ComposableParentThresholdSampler(rootSampler); +} diff --git a/experimental/packages/sampler-composite/src/traceidratio.ts b/experimental/packages/sampler-composite/src/traceidratio.ts new file mode 100644 index 00000000000..85f342c8c14 --- /dev/null +++ b/experimental/packages/sampler-composite/src/traceidratio.ts @@ -0,0 +1,78 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComposableSampler, SamplingIntent } from './types'; +import { INVALID_THRESHOLD, MAX_THRESHOLD } from './util'; +import { serializeTh } from './tracestate'; + +class ComposableTraceIDRatioBasedSampler implements ComposableSampler { + private readonly intent: SamplingIntent; + private readonly description: string; + + constructor(ratio: number) { + if (ratio < 0 || ratio > 1) { + throw new Error( + `Invalid sampling probability: ${ratio}. Must be between 0 and 1.` + ); + } + const threshold = calculateThreshold(ratio); + const thresholdStr = + threshold === MAX_THRESHOLD ? 'max' : serializeTh(threshold); + if (threshold !== MAX_THRESHOLD) { + this.intent = { + threshold: threshold, + thresholdReliable: true, + }; + } else { + // Same as AlwaysOff, notably the threshold is not considered reliable. The spec mentions + // returning an instance of ComposableAlwaysOffSampler in this case but it seems clearer + // if the description of the sampler matches the user's request. + this.intent = { + threshold: INVALID_THRESHOLD, + thresholdReliable: false, + }; + } + this.description = `ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})`; + } + + getSamplingIntent(): SamplingIntent { + return this.intent; + } + + toString(): string { + return this.description; + } +} + +/** + * Returns a composable sampler that samples each span with a fixed ratio. + */ +export function createComposableTraceIDRatioBasedSampler( + ratio: number +): ComposableSampler { + return new ComposableTraceIDRatioBasedSampler(ratio); +} + +const probabilityThresholdScale = Math.pow(2, 56); + +// TODO: Reduce threshold precision following spec recommendation of 4 +// to reduce size of serialized tracestate. +function calculateThreshold(samplingProbability: number): bigint { + return ( + MAX_THRESHOLD - + BigInt(Math.round(samplingProbability * probabilityThresholdScale)) + ); +} diff --git a/experimental/packages/sampler-composite/src/tracestate.ts b/experimental/packages/sampler-composite/src/tracestate.ts new file mode 100644 index 00000000000..8d12d218a65 --- /dev/null +++ b/experimental/packages/sampler-composite/src/tracestate.ts @@ -0,0 +1,156 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TraceState } from '@opentelemetry/api'; +import { + INVALID_RANDOM_VALUE, + INVALID_THRESHOLD, + isValidRandomValue, + isValidThreshold, + MAX_THRESHOLD, +} from './util'; + +export type OtelTraceState = { + /** The random value for sampling decisions in the trace. */ + randomValue: bigint; + /** The upstream threshold for sampling decisions. */ + threshold: bigint; + /** The rest of the "ot" tracestate value. */ + rest?: string[]; +}; + +export const INVALID_TRACE_STATE: OtelTraceState = Object.freeze({ + randomValue: INVALID_RANDOM_VALUE, + threshold: INVALID_THRESHOLD, +}); + +const TRACE_STATE_SIZE_LIMIT = 256; +const MAX_VALUE_LENGTH = 14; // 56 bits, 4 bits per hex digit + +export function parseOtelTraceState( + traceState: TraceState | undefined +): OtelTraceState { + const ot = traceState?.get('ot'); + if (!ot || ot.length > TRACE_STATE_SIZE_LIMIT) { + return INVALID_TRACE_STATE; + } + + let threshold = INVALID_THRESHOLD; + let randomValue = INVALID_RANDOM_VALUE; + + // Parse based on https://opentelemetry.io/docs/specs/otel/trace/tracestate-handling/ + const members = ot.split(';'); + let rest: string[] | undefined; + for (const member of members) { + if (member.startsWith('th:')) { + threshold = parseTh(member.slice('th:'.length), INVALID_THRESHOLD); + continue; + } + if (member.startsWith('rv:')) { + randomValue = parseRv(member.slice('rv:'.length), INVALID_RANDOM_VALUE); + continue; + } + if (!rest) { + rest = []; + } + rest.push(member); + } + + return { + randomValue, + threshold, + rest, + }; +} + +export function serializeTraceState(otTraceState: OtelTraceState): string { + if ( + !isValidThreshold(otTraceState.threshold) && + !isValidRandomValue(otTraceState.randomValue) && + !otTraceState.rest + ) { + return ''; + } + + const parts: string[] = []; + if ( + isValidThreshold(otTraceState.threshold) && + otTraceState.threshold !== MAX_THRESHOLD + ) { + parts.push(`th:${serializeTh(otTraceState.threshold)}`); + } + if (isValidRandomValue(otTraceState.randomValue)) { + parts.push(`rv:${serializeRv(otTraceState.randomValue)}`); + } + if (otTraceState.rest) { + parts.push(...otTraceState.rest); + } + let res = parts.join(';'); + while (res.length > TRACE_STATE_SIZE_LIMIT) { + const lastSemicolon = res.lastIndexOf(';'); + if (lastSemicolon === -1) { + break; + } + res = res.slice(0, lastSemicolon); + } + return res; +} + +function parseTh(value: string, defaultValue: bigint): bigint { + if (!value || value.length > MAX_VALUE_LENGTH) { + return defaultValue; + } + + try { + return BigInt('0x' + value.padEnd(MAX_VALUE_LENGTH, '0')); + } catch { + return defaultValue; + } +} + +function parseRv(value: string, defaultValue: bigint): bigint { + if (!value || value.length !== MAX_VALUE_LENGTH) { + return defaultValue; + } + + try { + return BigInt(`0x${value}`); + } catch { + return defaultValue; + } +} + +// hex value without trailing zeros +export function serializeTh(threshold: bigint): string { + if (threshold === 0n) { + return '0'; + } + + const value = threshold.toString(16).padStart(MAX_VALUE_LENGTH, '0'); + let idxAfterNonZero = value.length; + for (let i = value.length - 1; i >= 0; i--) { + if (value[i] !== '0') { + idxAfterNonZero = i + 1; + break; + } + } + // Checked at beginning so there is definitely a nonzero. + return value.slice(0, idxAfterNonZero); +} + +function serializeRv(randomValue: bigint): string { + return randomValue.toString(16).padStart(MAX_VALUE_LENGTH, '0'); +} diff --git a/experimental/packages/sampler-composite/src/types.ts b/experimental/packages/sampler-composite/src/types.ts new file mode 100644 index 00000000000..3743a38c071 --- /dev/null +++ b/experimental/packages/sampler-composite/src/types.ts @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Attributes, TraceState } from '@opentelemetry/api'; +import { type Sampler } from '@opentelemetry/sdk-trace-base'; + +/** Information to make a sampling decision. */ +export type SamplingIntent = { + /** The sampling threshold value. A lower threshold increases the likelihood of sampling. */ + threshold: bigint; + + /** Whether the threshold can be reliably used for Span-to-Metrics estimation. */ + thresholdReliable: boolean; + + /** Any attributes to add to the span for the sampling result. */ + attributes?: Attributes; + + /** How to update the TraceState for the span. */ + updateTraceState?: (ts: TraceState | undefined) => TraceState | undefined; +}; + +/** A sampler that can be composed to make a final sampling decision. */ +export interface ComposableSampler { + /** Returns the information to make a sampling decision. */ + getSamplingIntent( + ...args: Parameters + ): SamplingIntent; + + /** Returns the sampler name or short description with the configuration. */ + toString(): string; +} diff --git a/experimental/packages/sampler-composite/src/util.ts b/experimental/packages/sampler-composite/src/util.ts new file mode 100644 index 00000000000..5ba900c427e --- /dev/null +++ b/experimental/packages/sampler-composite/src/util.ts @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const INVALID_THRESHOLD = -1n; +export const INVALID_RANDOM_VALUE = -1n; + +const RANDOM_VALUE_BITS = 56n; +export const MAX_THRESHOLD = 1n << RANDOM_VALUE_BITS; // 0% sampling +export const MIN_THRESHOLD = 0n; // 100% sampling +const MAX_RANDOM_VALUE = MAX_THRESHOLD - 1n; + +export function isValidThreshold(threshold: bigint): boolean { + return threshold >= MIN_THRESHOLD && threshold <= MAX_THRESHOLD; +} + +export function isValidRandomValue(randomValue: bigint): boolean { + return randomValue >= 0n && randomValue <= MAX_RANDOM_VALUE; +} diff --git a/experimental/packages/sampler-composite/test/alwaysoff.test.ts b/experimental/packages/sampler-composite/test/alwaysoff.test.ts new file mode 100644 index 00000000000..e10c9c28274 --- /dev/null +++ b/experimental/packages/sampler-composite/test/alwaysoff.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; + +import { context, SpanKind } from '@opentelemetry/api'; +import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; + +import { + createCompositeSampler, + createComposableAlwaysOffSampler, +} from '../src'; +import { traceIdGenerator } from './util'; + +describe('ComposableAlwaysOffSampler', () => { + const composableSampler = createComposableAlwaysOffSampler(); + + it('should have a description', () => { + assert.strictEqual( + composableSampler.toString(), + 'ComposableAlwaysOffSampler' + ); + }); + + it('should have a constant threshold', () => { + assert.strictEqual( + composableSampler.getSamplingIntent( + context.active(), + 'unused', + 'span', + SpanKind.SERVER, + {}, + [] + ).threshold, + -1n + ); + }); + + it('should never sample', () => { + const sampler = createCompositeSampler(composableSampler); + const generator = traceIdGenerator(); + let numSampled = 0; + for (let i = 0; i < 10000; i++) { + const result = sampler.shouldSample( + context.active(), + generator(), + 'span', + SpanKind.SERVER, + {}, + [] + ); + if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { + numSampled++; + } + assert.strictEqual(result.traceState, undefined); + } + assert.strictEqual(numSampled, 0); + }); +}); diff --git a/experimental/packages/sampler-composite/test/alwayson.test.ts b/experimental/packages/sampler-composite/test/alwayson.test.ts new file mode 100644 index 00000000000..7a29a1fa8c3 --- /dev/null +++ b/experimental/packages/sampler-composite/test/alwayson.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; + +import { context, SpanKind } from '@opentelemetry/api'; +import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; + +import { + createCompositeSampler, + createComposableAlwaysOnSampler, +} from '../src'; +import { traceIdGenerator } from './util'; + +describe('ComposableAlwaysOnSampler', () => { + const composableSampler = createComposableAlwaysOnSampler(); + + it('should have a description', () => { + assert.strictEqual( + composableSampler.toString(), + 'ComposableAlwaysOnSampler' + ); + }); + + it('should have a constant threshold', () => { + assert.strictEqual( + composableSampler.getSamplingIntent( + context.active(), + 'unused', + 'span', + SpanKind.SERVER, + {}, + [] + ).threshold, + 0n + ); + }); + + it('should always sample', () => { + const sampler = createCompositeSampler(composableSampler); + const generator = traceIdGenerator(); + let numSampled = 0; + for (let i = 0; i < 10000; i++) { + const result = sampler.shouldSample( + context.active(), + generator(), + 'span', + SpanKind.SERVER, + {}, + [] + ); + if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { + numSampled++; + } + assert.strictEqual(result.traceState?.get('ot'), 'th:0'); + } + assert.strictEqual(numSampled, 10000); + }); +}); diff --git a/experimental/packages/sampler-composite/test/sampler.test.ts b/experimental/packages/sampler-composite/test/sampler.test.ts new file mode 100644 index 00000000000..86383d93ec7 --- /dev/null +++ b/experimental/packages/sampler-composite/test/sampler.test.ts @@ -0,0 +1,192 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; + +import { + context, + SpanContext, + SpanKind, + TraceFlags, + trace, +} from '@opentelemetry/api'; +import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; + +import { + createCompositeSampler, + createComposableAlwaysOffSampler, + createComposableAlwaysOnSampler, + createComposableParentThresholdSampler, + createComposableTraceIDRatioBasedSampler, +} from '../src'; +import { INVALID_RANDOM_VALUE, INVALID_THRESHOLD } from '../src/util'; +import { + INVALID_TRACE_STATE, + parseOtelTraceState, + serializeTraceState, +} from '../src/tracestate'; +import { TraceState } from '@opentelemetry/core'; + +describe('ConsistentSampler', () => { + const traceId = '00112233445566778800000000000000'; + const spanId = '0123456789abcdef'; + + [ + { + sampler: createComposableAlwaysOnSampler(), + parentSampled: true, + parentThreshold: undefined, + parentRandomValue: undefined, + sampled: true, + threshold: 0n, + randomValue: INVALID_RANDOM_VALUE, + testId: 'min threshold no parent random value', + }, + { + sampler: createComposableAlwaysOnSampler(), + parentSampled: true, + parentThreshold: undefined, + parentRandomValue: 0x7f99aa40c02744n, + sampled: true, + threshold: 0n, + randomValue: 0x7f99aa40c02744n, + testId: 'min threshold with parent random value', + }, + { + sampler: createComposableAlwaysOffSampler(), + parentSampled: true, + parentThreshold: undefined, + parentRandomValue: undefined, + sampled: false, + threshold: INVALID_THRESHOLD, + randomValue: INVALID_RANDOM_VALUE, + testId: 'max threshold', + }, + { + sampler: createComposableParentThresholdSampler( + createComposableAlwaysOnSampler() + ), + parentSampled: false, + parentThreshold: 0x7f99aa40c02744n, + parentRandomValue: 0x7f99aa40c02744n, + sampled: true, + threshold: 0x7f99aa40c02744n, + randomValue: 0x7f99aa40c02744n, + testId: 'parent based in consistent mode', + }, + { + sampler: createComposableParentThresholdSampler( + createComposableAlwaysOnSampler() + ), + parentSampled: true, + parentThreshold: undefined, + parentRandomValue: undefined, + sampled: true, + threshold: INVALID_THRESHOLD, + randomValue: INVALID_RANDOM_VALUE, + testId: 'parent based in legacy mode', + }, + { + sampler: createComposableTraceIDRatioBasedSampler(0.5), + parentSampled: true, + parentThreshold: undefined, + parentRandomValue: 0x7fffffffffffffn, + sampled: false, + threshold: INVALID_THRESHOLD, + randomValue: 0x7fffffffffffffn, + testId: 'half threshold not sampled', + }, + { + sampler: createComposableTraceIDRatioBasedSampler(0.5), + parentSampled: false, + parentThreshold: undefined, + parentRandomValue: 0x80000000000000n, + sampled: true, + threshold: 0x80000000000000n, + randomValue: 0x80000000000000n, + testId: 'half threshold sampled', + }, + { + sampler: createComposableTraceIDRatioBasedSampler(1.0), + parentSampled: false, + parentThreshold: 0x80000000000000n, + parentRandomValue: 0x80000000000000n, + sampled: true, + threshold: 0n, + randomValue: 0x80000000000000n, + testId: 'parent inviolating invariant', + }, + ].forEach( + ({ + sampler, + parentSampled, + parentThreshold, + parentRandomValue, + sampled, + threshold, + randomValue, + testId, + }) => { + it(`should sample with ${testId}`, () => { + let parentOtTraceState = INVALID_TRACE_STATE; + if (parentThreshold !== undefined) { + parentOtTraceState = { + ...parentOtTraceState, + threshold: parentThreshold, + }; + } + if (parentRandomValue !== undefined) { + parentOtTraceState = { + ...parentOtTraceState, + randomValue: parentRandomValue, + }; + } + const parentOt = serializeTraceState(parentOtTraceState); + const parentTraceState = parentOt + ? new TraceState().set('ot', parentOt) + : undefined; + const traceFlags = parentSampled ? TraceFlags.SAMPLED : TraceFlags.NONE; + const parentSpanContext: SpanContext = { + traceId, + spanId, + traceFlags, + traceState: parentTraceState, + }; + const parentContext = trace.setSpanContext( + context.active(), + parentSpanContext + ); + + const result = createCompositeSampler(sampler).shouldSample( + parentContext, + traceId, + 'name', + SpanKind.INTERNAL, + {}, + [] + ); + const expectedDecision = sampled + ? SamplingDecision.RECORD_AND_SAMPLED + : SamplingDecision.NOT_RECORD; + const state = parseOtelTraceState(result.traceState); + + assert.strictEqual(result.decision, expectedDecision); + assert.strictEqual(state.threshold, threshold); + assert.strictEqual(state.randomValue, randomValue); + }); + } + ); +}); diff --git a/experimental/packages/sampler-composite/test/traceidratio.test.ts b/experimental/packages/sampler-composite/test/traceidratio.test.ts new file mode 100644 index 00000000000..fc9499aa088 --- /dev/null +++ b/experimental/packages/sampler-composite/test/traceidratio.test.ts @@ -0,0 +1,87 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as assert from 'assert'; + +import { context, SpanKind } from '@opentelemetry/api'; +import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; + +import { + createCompositeSampler, + createComposableTraceIDRatioBasedSampler, +} from '../src'; +import { traceIdGenerator } from './util'; +import { parseOtelTraceState } from '../src/tracestate'; +import { INVALID_RANDOM_VALUE } from '../src/util'; + +describe('ComposableTraceIDRatioBasedSampler', () => { + [ + { ratio: 1.0, thresholdStr: '0' }, + { ratio: 0.5, thresholdStr: '8' }, + { ratio: 0.25, thresholdStr: 'c' }, + { ratio: 1e-300, thresholdStr: 'max' }, + { ratio: 0, thresholdStr: 'max' }, + ].forEach(({ ratio, thresholdStr }) => { + it(`should have a description for ratio ${ratio}`, () => { + const sampler = createComposableTraceIDRatioBasedSampler(ratio); + assert.strictEqual( + sampler.toString(), + `ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})` + ); + }); + }); + + [ + { ratio: 1.0, threshold: 0n }, + { ratio: 0.5, threshold: 36028797018963968n }, + { ratio: 0.25, threshold: 54043195528445952n }, + { ratio: 0.125, threshold: 63050394783186944n }, + { ratio: 0.0, threshold: 72057594037927936n }, + { ratio: 0.45, threshold: 39631676720860364n }, + { ratio: 0.2, threshold: 57646075230342348n }, + { ratio: 0.13, threshold: 62690106812997304n }, + { ratio: 0.05, threshold: 68454714336031539n }, + ].forEach(({ ratio, threshold }) => { + it(`should sample spans with ratio ${ratio}`, () => { + const sampler = createCompositeSampler( + createComposableTraceIDRatioBasedSampler(ratio) + ); + + const generator = traceIdGenerator(); + let numSampled = 0; + for (let i = 0; i < 10000; i++) { + const result = sampler.shouldSample( + context.active(), + generator(), + 'span', + SpanKind.SERVER, + {}, + [] + ); + if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { + numSampled++; + const otTraceState = parseOtelTraceState(result.traceState); + assert.strictEqual(otTraceState?.threshold, threshold); + assert.strictEqual(otTraceState?.randomValue, INVALID_RANDOM_VALUE); + } + } + const expectedNumSampled = 10000 * ratio; + assert.ok( + Math.abs(numSampled - expectedNumSampled) < 50, + `expected ${expectedNumSampled}, have ${numSampled}` + ); + }); + }); +}); diff --git a/experimental/packages/sampler-composite/test/tracestate.test.ts b/experimental/packages/sampler-composite/test/tracestate.test.ts new file mode 100644 index 00000000000..3e439029533 --- /dev/null +++ b/experimental/packages/sampler-composite/test/tracestate.test.ts @@ -0,0 +1,70 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; +import { serializeTraceState, parseOtelTraceState } from '../src/tracestate'; +import { TraceState } from '@opentelemetry/core'; + +describe('OtelTraceState', () => { + [ + { input: 'a', output: 'a' }, + { input: '#', output: '#' }, + { input: 'rv:1234567890abcd', output: 'rv:1234567890abcd' }, + { input: 'rv:01020304050607', output: 'rv:01020304050607' }, + { input: 'rv:1234567890abcde', output: '' }, + { input: 'th:1234567890abcd', output: 'th:1234567890abcd' }, + { input: 'th:1234567890abcd', output: 'th:1234567890abcd' }, + { input: 'th:10000000000000', output: 'th:1' }, + { input: 'th:1234500000000', output: 'th:12345' }, + { input: 'th:0', output: 'th:0' }, + { input: 'th:100000000000000', output: '' }, + { input: 'th:1234567890abcde', output: '' }, + { + input: `a:${''.padEnd(214, 'X')};rv:1234567890abcd;th:1234567890abcd;x:3`, + output: `th:1234567890abcd;rv:1234567890abcd;a:${''.padEnd(214, 'X')};x:3`, + testId: 'long', + }, + { input: 'th:x', output: '' }, + { input: 'th:100000000000000', output: '' }, + { input: 'th:10000000000000', output: 'th:1' }, + { input: 'th:1000000000000', output: 'th:1' }, + { input: 'th:100000000000', output: 'th:1' }, + { input: 'th:10000000000', output: 'th:1' }, + { input: 'th:1000000000', output: 'th:1' }, + { input: 'th:100000000', output: 'th:1' }, + { input: 'th:10000000', output: 'th:1' }, + { input: 'th:1000000', output: 'th:1' }, + { input: 'th:100000', output: 'th:1' }, + { input: 'th:10000', output: 'th:1' }, + { input: 'th:1000', output: 'th:1' }, + { input: 'th:100', output: 'th:1' }, + { input: 'th:10', output: 'th:1' }, + { input: 'th:1', output: 'th:1' }, + { input: 'th:10000000000001', output: 'th:10000000000001' }, + { input: 'th:10000000000010', output: 'th:1000000000001' }, + { input: 'rv:x', output: '' }, + { input: 'rv:100000000000000', output: '' }, + { input: 'rv:10000000000000', output: 'rv:10000000000000' }, + { input: 'rv:1000000000000', output: '' }, + ].forEach(({ input, output, testId }) => { + it(`should round trip ${testId || `from ${input} to ${output}`}`, () => { + const result = serializeTraceState( + parseOtelTraceState(new TraceState().set('ot', input)) + ); + assert.strictEqual(result, output); + }); + }); +}); diff --git a/experimental/packages/sampler-composite/test/util.ts b/experimental/packages/sampler-composite/test/util.ts new file mode 100644 index 00000000000..a4b393aa5d4 --- /dev/null +++ b/experimental/packages/sampler-composite/test/util.ts @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Use a fixed seed simple but reasonable random number generator for consistent tests. +// Unlike many languages, there isn't a way to set the seed of the built-in random. + +function splitmix32(a: number) { + return function () { + a |= 0; + a = (a + 0x9e3779b9) | 0; + let t = a ^ (a >>> 16); + t = Math.imul(t, 0x21f0aaad); + t = t ^ (t >>> 15); + t = Math.imul(t, 0x735a2d97); + return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296; + }; +} + +export function traceIdGenerator(): () => string { + const seed = 0xdeadbeef; + const random = splitmix32(seed); + // Pre-mix the state. + for (let i = 0; i < 15; i++) { + random(); + } + return () => { + const parts: string[] = []; + // 32-bit randoms, concatenate 4 of them + for (let i = 0; i < 4; i++) { + const val = Math.round(random() * 0xffffffff); + parts.push(val.toString(16).padStart(8, '0')); + } + return parts.join(''); + }; +} diff --git a/experimental/packages/sampler-composite/tsconfig.esm.json b/experimental/packages/sampler-composite/tsconfig.esm.json new file mode 100644 index 00000000000..5fe96d554ba --- /dev/null +++ b/experimental/packages/sampler-composite/tsconfig.esm.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.esm.json", + "compilerOptions": { + "allowJs": true, + "outDir": "build/esm", + "rootDir": "src", + "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { + "path": "../../../api" + }, + { + "path": "../../../packages/opentelemetry-core" + }, + { + "path": "../../../packages/opentelemetry-sdk-trace-base" + } + ] +} diff --git a/experimental/packages/sampler-composite/tsconfig.esnext.json b/experimental/packages/sampler-composite/tsconfig.esnext.json new file mode 100644 index 00000000000..17ed0461704 --- /dev/null +++ b/experimental/packages/sampler-composite/tsconfig.esnext.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.esnext.json", + "compilerOptions": { + "allowJs": true, + "outDir": "build/esnext", + "rootDir": "src", + "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo" + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { + "path": "../../../api" + }, + { + "path": "../../../packages/opentelemetry-core" + }, + { + "path": "../../../packages/opentelemetry-sdk-trace-base" + } + ] +} diff --git a/experimental/packages/sampler-composite/tsconfig.json b/experimental/packages/sampler-composite/tsconfig.json new file mode 100644 index 00000000000..eb6f0a3a273 --- /dev/null +++ b/experimental/packages/sampler-composite/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "allowJs": true, + "outDir": "build", + "rootDir": "." + }, + "files": [], + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "references": [ + { + "path": "../../../api" + }, + { + "path": "../../../packages/opentelemetry-core" + }, + { + "path": "../../../packages/opentelemetry-sdk-trace-base" + } + ] +} diff --git a/package-lock.json b/package-lock.json index 45cf14f0b5e..e4c17675ee5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1449,6 +1449,257 @@ "@opentelemetry/api": "^1.3.0" } }, + "experimental/packages/sampler-composite": { + "name": "@opentelemetry/sampler-composite", + "version": "0.205.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "devDependencies": { + "@opentelemetry/api": "1.9.0", + "@types/mocha": "10.0.10", + "@types/node": "18.6.5", + "lerna": "6.6.2", + "mocha": "11.1.0", + "nyc": "17.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "experimental/packages/sampler-composite/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "experimental/packages/sampler-composite/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "experimental/packages/sampler-composite/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "experimental/packages/sampler-composite/node_modules/@types/node": { + "version": "18.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", + "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", + "dev": true, + "license": "MIT" + }, + "experimental/packages/sampler-composite/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "experimental/packages/sampler-composite/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "experimental/packages/sampler-composite/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "experimental/packages/sampler-composite/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "experimental/packages/sampler-composite/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "experimental/packages/sampler-composite/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "experimental/packages/sampler-composite/node_modules/mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "experimental/packages/sampler-composite/node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "experimental/packages/sampler-composite/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "experimental/packages/sampler-composite/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "experimental/packages/sampler-composite/node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" + }, + "experimental/packages/sampler-composite/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "experimental/packages/sampler-jaeger-remote": { "name": "@opentelemetry/sampler-jaeger-remote", "version": "0.205.0", @@ -5963,6 +6214,10 @@ "resolved": "packages/opentelemetry-resources", "link": true }, + "node_modules/@opentelemetry/sampler-composite": { + "resolved": "experimental/packages/sampler-composite", + "link": true + }, "node_modules/@opentelemetry/sampler-jaeger-remote": { "resolved": "experimental/packages/sampler-jaeger-remote", "link": true @@ -31041,6 +31296,175 @@ } } }, + "@opentelemetry/sampler-composite": { + "version": "file:experimental/packages/sampler-composite", + "requires": { + "@opentelemetry/api": "1.9.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "@types/mocha": "10.0.10", + "@types/node": "18.6.5", + "lerna": "6.6.2", + "mocha": "11.1.0", + "nyc": "17.1.0" + }, + "dependencies": { + "@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "requires": { + "@opentelemetry/semantic-conventions": "^1.29.0" + } + }, + "@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "requires": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "requires": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + } + }, + "@types/node": { + "version": "18.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", + "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true + }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, "@opentelemetry/sampler-jaeger-remote": { "version": "file:experimental/packages/sampler-jaeger-remote", "requires": { diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 2bb983f4064..711743009ba 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -44,6 +44,9 @@ { "path": "experimental/packages/otlp-transformer/tsconfig.esm.json" }, + { + "path": "experimental/packages/sampler-composite/tsconfig.esm.json" + }, { "path": "experimental/packages/sdk-logs/tsconfig.esm.json" }, diff --git a/tsconfig.esnext.json b/tsconfig.esnext.json index ac540a88b2d..cfc96b3bda9 100644 --- a/tsconfig.esnext.json +++ b/tsconfig.esnext.json @@ -44,6 +44,9 @@ { "path": "experimental/packages/otlp-transformer/tsconfig.esnext.json" }, + { + "path": "experimental/packages/sampler-composite/tsconfig.esnext.json" + }, { "path": "experimental/packages/sdk-logs/tsconfig.esnext.json" }, diff --git a/tsconfig.json b/tsconfig.json index ee5c10de7b4..58f4ff7e340 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,7 @@ "experimental/packages/otlp-exporter-base", "experimental/packages/otlp-grpc-exporter-base", "experimental/packages/otlp-transformer", + "experimental/packages/sampler-composite", "experimental/packages/sampler-jaeger-remote", "experimental/packages/sdk-logs", "experimental/packages/shim-opencensus", @@ -126,6 +127,9 @@ { "path": "experimental/packages/otlp-transformer" }, + { + "path": "experimental/packages/sampler-composite" + }, { "path": "experimental/packages/sampler-jaeger-remote" }, From 537e20c27e6f60bec381bdea7578249bf40b3694 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 19 Sep 2025 22:39:30 -0400 Subject: [PATCH 12/15] Revert "feat(sampler-composite): add experimental implementation of composite sampling spec (#5839)" This reverts commit a662970e812b97716908d55c240cacd171f1f136. --- experimental/CHANGELOG.md | 1 - .../packages/sampler-composite/.eslintignore | 1 - .../packages/sampler-composite/.eslintrc.js | 8 - .../packages/sampler-composite/README.md | 57 --- .../packages/sampler-composite/package.json | 70 --- .../sampler-composite/src/alwaysoff.ts | 41 -- .../sampler-composite/src/alwayson.ts | 41 -- .../sampler-composite/src/composite.ts | 126 ------ .../packages/sampler-composite/src/index.ts | 22 - .../sampler-composite/src/parentthreshold.ts | 89 ---- .../sampler-composite/src/traceidratio.ts | 78 ---- .../sampler-composite/src/tracestate.ts | 156 ------- .../packages/sampler-composite/src/types.ts | 44 -- .../packages/sampler-composite/src/util.ts | 31 -- .../sampler-composite/test/alwaysoff.test.ts | 72 --- .../sampler-composite/test/alwayson.test.ts | 72 --- .../sampler-composite/test/sampler.test.ts | 192 -------- .../test/traceidratio.test.ts | 87 ---- .../sampler-composite/test/tracestate.test.ts | 70 --- .../packages/sampler-composite/test/util.ts | 48 -- .../sampler-composite/tsconfig.esm.json | 23 - .../sampler-composite/tsconfig.esnext.json | 23 - .../packages/sampler-composite/tsconfig.json | 24 - package-lock.json | 424 ------------------ tsconfig.esm.json | 3 - tsconfig.esnext.json | 3 - tsconfig.json | 4 - 27 files changed, 1810 deletions(-) delete mode 100644 experimental/packages/sampler-composite/.eslintignore delete mode 100644 experimental/packages/sampler-composite/.eslintrc.js delete mode 100644 experimental/packages/sampler-composite/README.md delete mode 100644 experimental/packages/sampler-composite/package.json delete mode 100644 experimental/packages/sampler-composite/src/alwaysoff.ts delete mode 100644 experimental/packages/sampler-composite/src/alwayson.ts delete mode 100644 experimental/packages/sampler-composite/src/composite.ts delete mode 100644 experimental/packages/sampler-composite/src/index.ts delete mode 100644 experimental/packages/sampler-composite/src/parentthreshold.ts delete mode 100644 experimental/packages/sampler-composite/src/traceidratio.ts delete mode 100644 experimental/packages/sampler-composite/src/tracestate.ts delete mode 100644 experimental/packages/sampler-composite/src/types.ts delete mode 100644 experimental/packages/sampler-composite/src/util.ts delete mode 100644 experimental/packages/sampler-composite/test/alwaysoff.test.ts delete mode 100644 experimental/packages/sampler-composite/test/alwayson.test.ts delete mode 100644 experimental/packages/sampler-composite/test/sampler.test.ts delete mode 100644 experimental/packages/sampler-composite/test/traceidratio.test.ts delete mode 100644 experimental/packages/sampler-composite/test/tracestate.test.ts delete mode 100644 experimental/packages/sampler-composite/test/util.ts delete mode 100644 experimental/packages/sampler-composite/tsconfig.esm.json delete mode 100644 experimental/packages/sampler-composite/tsconfig.esnext.json delete mode 100644 experimental/packages/sampler-composite/tsconfig.json diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index c53f0ab68c0..8ab3ad8a3eb 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -10,7 +10,6 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 ### :rocket: Features -* feat(sampler-composite): Added experimental implementations of draft composite sampling spec [#5839](https://github.com/open-telemetry/opentelemetry-js/pull/5839) @anuraaga * feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag ### :bug: Bug Fixes diff --git a/experimental/packages/sampler-composite/.eslintignore b/experimental/packages/sampler-composite/.eslintignore deleted file mode 100644 index 378eac25d31..00000000000 --- a/experimental/packages/sampler-composite/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/experimental/packages/sampler-composite/.eslintrc.js b/experimental/packages/sampler-composite/.eslintrc.js deleted file mode 100644 index 0fe1bbf975f..00000000000 --- a/experimental/packages/sampler-composite/.eslintrc.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - "env": { - "mocha": true, - "commonjs": true, - "shared-node-browser": true - }, - ...require('../../../eslint.base.js') -} diff --git a/experimental/packages/sampler-composite/README.md b/experimental/packages/sampler-composite/README.md deleted file mode 100644 index 6fce8346e41..00000000000 --- a/experimental/packages/sampler-composite/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# OpenTelemetry Composite Sampling - -[![NPM Published Version][npm-img]][npm-url] -[![Apache License][license-image]][license-image] - -**Note: This is an experimental package under active development. New releases may include breaking changes.** - -This package provides implementations of composite samplers that propagate sampling information across a trace. -This implements the [experimental specification][probability-sampling]. - -Currently `ComposableRuleBased` and `ComposableAnnotating` are not implemented. - -## Quick Start - -To get started you will need to install a compatible OpenTelemetry SDK. - -### Samplers - -This module exports samplers that follow the general behavior of the standard SDK samplers, but ensuring -it is consistent across a trace by using the tracestate header. Notably, the tracestate can be examined -in exported spans to reconstruct population metrics. - -```typescript -import { - createCompositeSampler, - createComposableAlwaysOffSampler, - createComposableAlwaysOnSampler, - createComposableParentThresholdSampler, - createComposableTraceIDRatioBasedSampler, -} from '@opentelemetry/sampler-composite'; - -// never sample -const sampler = createCompositeSampler(createComposableAlwaysOffSampler()); -// always sample -const sampler = createCompositeSampler(createComposableAlwaysOnSampler()); -// follow the parent, or otherwise sample with a probability if root -const sampler = createCompositeSampler( - createComposableParentThresholdSampler(createComposableTraceIDRatioBasedSampler(0.3))); -``` - -## Useful links - -- For more information on OpenTelemetry, visit: -- For more about OpenTelemetry JavaScript: -- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] - -## License - -Apache 2.0 - See [LICENSE][license-url] for more information. - -[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions -[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE -[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat -[npm-url]: https://www.npmjs.com/package/@opentelemetry/sampler-composite -[npm-img]: https://badge.fury.io/js/%40opentelemetry%sampler-composite.svg - -[probability-sampling]: https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/ diff --git a/experimental/packages/sampler-composite/package.json b/experimental/packages/sampler-composite/package.json deleted file mode 100644 index fef7b992500..00000000000 --- a/experimental/packages/sampler-composite/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "@opentelemetry/sampler-composite", - "private": false, - "publishConfig": { - "access": "public" - }, - "version": "0.205.0", - "description": "Composite samplers for OpenTelemetry tracing", - "module": "build/esm/index.js", - "esnext": "build/esnext/index.js", - "types": "build/src/index.d.ts", - "main": "build/src/index.js", - "repository": "open-telemetry/opentelemetry-js", - "scripts": { - "prepublishOnly": "npm run compile", - "compile": "tsc --build", - "clean": "tsc --build --clean", - "test": "nyc mocha 'test/**/*.test.ts'", - "tdd": "npm run test -- --watch-extensions ts --watch", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", - "version": "node ../../../scripts/version-update.js", - "watch": "tsc --build --watch", - "precompile": "lerna run version --scope @opentelemetry/sampler-composite --include-dependencies", - "prewatch": "npm run precompile", - "peer-api-check": "node ../../../scripts/peer-api-check.js", - "align-api-deps": "node ../../../scripts/align-api-deps.js" - }, - "keywords": [ - "opentelemetry", - "nodejs", - "sampling", - "tracing" - ], - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "files": [ - "build/esm/**/*.js", - "build/esm/**/*.js.map", - "build/esm/**/*.d.ts", - "build/esnext/**/*.js", - "build/esnext/**/*.js.map", - "build/esnext/**/*.d.ts", - "build/src/**/*.js", - "build/src/**/*.js.map", - "build/src/**/*.d.ts", - "LICENSE", - "README.md" - ], - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "devDependencies": { - "@opentelemetry/api": "1.9.0", - "@types/mocha": "10.0.10", - "@types/node": "18.6.5", - "lerna": "6.6.2", - "mocha": "11.1.0", - "nyc": "17.1.0" - }, - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/sampler-composite", - "sideEffects": false -} diff --git a/experimental/packages/sampler-composite/src/alwaysoff.ts b/experimental/packages/sampler-composite/src/alwaysoff.ts deleted file mode 100644 index 2c41635cdee..00000000000 --- a/experimental/packages/sampler-composite/src/alwaysoff.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import type { ComposableSampler, SamplingIntent } from './types'; -import { INVALID_THRESHOLD } from './util'; - -const intent: SamplingIntent = { - threshold: INVALID_THRESHOLD, - thresholdReliable: false, -}; - -class ComposableAlwaysOffSampler implements ComposableSampler { - getSamplingIntent(): SamplingIntent { - return intent; - } - - toString(): string { - return 'ComposableAlwaysOffSampler'; - } -} - -const _sampler = new ComposableAlwaysOffSampler(); - -/** - * Returns a composable sampler that does not sample any span. - */ -export function createComposableAlwaysOffSampler(): ComposableSampler { - return _sampler; -} diff --git a/experimental/packages/sampler-composite/src/alwayson.ts b/experimental/packages/sampler-composite/src/alwayson.ts deleted file mode 100644 index 832d81e665b..00000000000 --- a/experimental/packages/sampler-composite/src/alwayson.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import type { ComposableSampler, SamplingIntent } from './types'; -import { MIN_THRESHOLD } from './util'; - -const intent: SamplingIntent = { - threshold: MIN_THRESHOLD, - thresholdReliable: true, -}; - -class ComposableAlwaysOnSampler implements ComposableSampler { - getSamplingIntent(): SamplingIntent { - return intent; - } - - toString(): string { - return 'ComposableAlwaysOnSampler'; - } -} - -const _sampler = new ComposableAlwaysOnSampler(); - -/** - * Returns a composable sampler that samples all span. - */ -export function createComposableAlwaysOnSampler(): ComposableSampler { - return _sampler; -} diff --git a/experimental/packages/sampler-composite/src/composite.ts b/experimental/packages/sampler-composite/src/composite.ts deleted file mode 100644 index 0a8a90e0620..00000000000 --- a/experimental/packages/sampler-composite/src/composite.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { - Context, - SpanKind, - Attributes, - Link, - TraceState, - trace, -} from '@opentelemetry/api'; -import { TraceState as CoreTraceState } from '@opentelemetry/core'; -import { - Sampler, - SamplingDecision, - SamplingResult, -} from '@opentelemetry/sdk-trace-base'; -import { ComposableSampler } from './types'; -import { parseOtelTraceState, serializeTraceState } from './tracestate'; -import { - INVALID_THRESHOLD, - isValidRandomValue, - isValidThreshold, -} from './util'; - -class CompositeSampler implements Sampler { - constructor(private readonly delegate: ComposableSampler) {} - - shouldSample( - context: Context, - traceId: string, - spanName: string, - spanKind: SpanKind, - attributes: Attributes, - links: Link[] - ): SamplingResult { - const spanContext = trace.getSpanContext(context); - - const traceState = spanContext?.traceState; - let otTraceState = parseOtelTraceState(traceState); - - const intent = this.delegate.getSamplingIntent( - context, - traceId, - spanName, - spanKind, - attributes, - links - ); - - let adjustedCountCorrect = false; - let sampled = false; - if (isValidThreshold(intent.threshold)) { - adjustedCountCorrect = intent.thresholdReliable; - let randomness: bigint; - if (isValidRandomValue(otTraceState.randomValue)) { - randomness = otTraceState.randomValue; - } else { - // Use last 56 bits of trace_id as randomness. - randomness = BigInt(`0x${traceId.slice(-14)}`); - } - sampled = intent.threshold <= randomness; - } - - const decision = sampled - ? SamplingDecision.RECORD_AND_SAMPLED - : SamplingDecision.NOT_RECORD; - if (sampled && adjustedCountCorrect) { - otTraceState = { - ...otTraceState, - threshold: intent.threshold, - }; - } else { - otTraceState = { - ...otTraceState, - threshold: INVALID_THRESHOLD, - }; - } - - const otts = serializeTraceState(otTraceState); - - let newTraceState: TraceState | undefined; - if (traceState) { - newTraceState = traceState; - if (intent.updateTraceState) { - newTraceState = intent.updateTraceState(newTraceState); - } - } - if (otts) { - if (!newTraceState) { - newTraceState = new CoreTraceState(); - } - newTraceState = newTraceState.set('ot', otts); - } - - return { - decision, - attributes: intent.attributes, - traceState: newTraceState, - }; - } - - toString(): string { - return this.delegate.toString(); - } -} - -/** - * Returns a composite sampler that uses a composable sampler to make its - * sampling decisions while handling tracestate. - */ -export function createCompositeSampler(delegate: ComposableSampler): Sampler { - return new CompositeSampler(delegate); -} diff --git a/experimental/packages/sampler-composite/src/index.ts b/experimental/packages/sampler-composite/src/index.ts deleted file mode 100644 index 91e68bf22e6..00000000000 --- a/experimental/packages/sampler-composite/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { createComposableAlwaysOffSampler } from './alwaysoff'; -export { createComposableAlwaysOnSampler } from './alwayson'; -export { createComposableTraceIDRatioBasedSampler } from './traceidratio'; -export { createComposableParentThresholdSampler } from './parentthreshold'; -export { createCompositeSampler } from './composite'; -export type { ComposableSampler, SamplingIntent } from './types'; diff --git a/experimental/packages/sampler-composite/src/parentthreshold.ts b/experimental/packages/sampler-composite/src/parentthreshold.ts deleted file mode 100644 index a01a8d4eda1..00000000000 --- a/experimental/packages/sampler-composite/src/parentthreshold.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - Attributes, - Context, - isSpanContextValid, - Link, - SpanKind, - TraceFlags, - trace, -} from '@opentelemetry/api'; -import { ComposableSampler, SamplingIntent } from './types'; -import { parseOtelTraceState } from './tracestate'; -import { INVALID_THRESHOLD, isValidThreshold, MIN_THRESHOLD } from './util'; - -class ComposableParentThresholdSampler implements ComposableSampler { - private readonly description: string; - - constructor(private readonly rootSampler: ComposableSampler) { - this.description = `ComposableParentThresholdSampler(rootSampler=${rootSampler})`; - } - - getSamplingIntent( - context: Context, - traceId: string, - spanName: string, - spanKind: SpanKind, - attributes: Attributes, - links: Link[] - ): SamplingIntent { - const parentSpanContext = trace.getSpanContext(context); - if (!parentSpanContext || !isSpanContextValid(parentSpanContext)) { - return this.rootSampler.getSamplingIntent( - context, - traceId, - spanName, - spanKind, - attributes, - links - ); - } - - const otTraceState = parseOtelTraceState(parentSpanContext.traceState); - - if (isValidThreshold(otTraceState.threshold)) { - return { - threshold: otTraceState.threshold, - thresholdReliable: true, - }; - } - - const threshold = - parentSpanContext.traceFlags & TraceFlags.SAMPLED - ? MIN_THRESHOLD - : INVALID_THRESHOLD; - return { - threshold, - thresholdReliable: false, - }; - } - - toString(): string { - return this.description; - } -} - -/** - * Returns a composable sampler that respects the sampling decision of the - * parent span or falls back to the given sampler if it is a root span. - */ -export function createComposableParentThresholdSampler( - rootSampler: ComposableSampler -): ComposableSampler { - return new ComposableParentThresholdSampler(rootSampler); -} diff --git a/experimental/packages/sampler-composite/src/traceidratio.ts b/experimental/packages/sampler-composite/src/traceidratio.ts deleted file mode 100644 index 85f342c8c14..00000000000 --- a/experimental/packages/sampler-composite/src/traceidratio.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ComposableSampler, SamplingIntent } from './types'; -import { INVALID_THRESHOLD, MAX_THRESHOLD } from './util'; -import { serializeTh } from './tracestate'; - -class ComposableTraceIDRatioBasedSampler implements ComposableSampler { - private readonly intent: SamplingIntent; - private readonly description: string; - - constructor(ratio: number) { - if (ratio < 0 || ratio > 1) { - throw new Error( - `Invalid sampling probability: ${ratio}. Must be between 0 and 1.` - ); - } - const threshold = calculateThreshold(ratio); - const thresholdStr = - threshold === MAX_THRESHOLD ? 'max' : serializeTh(threshold); - if (threshold !== MAX_THRESHOLD) { - this.intent = { - threshold: threshold, - thresholdReliable: true, - }; - } else { - // Same as AlwaysOff, notably the threshold is not considered reliable. The spec mentions - // returning an instance of ComposableAlwaysOffSampler in this case but it seems clearer - // if the description of the sampler matches the user's request. - this.intent = { - threshold: INVALID_THRESHOLD, - thresholdReliable: false, - }; - } - this.description = `ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})`; - } - - getSamplingIntent(): SamplingIntent { - return this.intent; - } - - toString(): string { - return this.description; - } -} - -/** - * Returns a composable sampler that samples each span with a fixed ratio. - */ -export function createComposableTraceIDRatioBasedSampler( - ratio: number -): ComposableSampler { - return new ComposableTraceIDRatioBasedSampler(ratio); -} - -const probabilityThresholdScale = Math.pow(2, 56); - -// TODO: Reduce threshold precision following spec recommendation of 4 -// to reduce size of serialized tracestate. -function calculateThreshold(samplingProbability: number): bigint { - return ( - MAX_THRESHOLD - - BigInt(Math.round(samplingProbability * probabilityThresholdScale)) - ); -} diff --git a/experimental/packages/sampler-composite/src/tracestate.ts b/experimental/packages/sampler-composite/src/tracestate.ts deleted file mode 100644 index 8d12d218a65..00000000000 --- a/experimental/packages/sampler-composite/src/tracestate.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { TraceState } from '@opentelemetry/api'; -import { - INVALID_RANDOM_VALUE, - INVALID_THRESHOLD, - isValidRandomValue, - isValidThreshold, - MAX_THRESHOLD, -} from './util'; - -export type OtelTraceState = { - /** The random value for sampling decisions in the trace. */ - randomValue: bigint; - /** The upstream threshold for sampling decisions. */ - threshold: bigint; - /** The rest of the "ot" tracestate value. */ - rest?: string[]; -}; - -export const INVALID_TRACE_STATE: OtelTraceState = Object.freeze({ - randomValue: INVALID_RANDOM_VALUE, - threshold: INVALID_THRESHOLD, -}); - -const TRACE_STATE_SIZE_LIMIT = 256; -const MAX_VALUE_LENGTH = 14; // 56 bits, 4 bits per hex digit - -export function parseOtelTraceState( - traceState: TraceState | undefined -): OtelTraceState { - const ot = traceState?.get('ot'); - if (!ot || ot.length > TRACE_STATE_SIZE_LIMIT) { - return INVALID_TRACE_STATE; - } - - let threshold = INVALID_THRESHOLD; - let randomValue = INVALID_RANDOM_VALUE; - - // Parse based on https://opentelemetry.io/docs/specs/otel/trace/tracestate-handling/ - const members = ot.split(';'); - let rest: string[] | undefined; - for (const member of members) { - if (member.startsWith('th:')) { - threshold = parseTh(member.slice('th:'.length), INVALID_THRESHOLD); - continue; - } - if (member.startsWith('rv:')) { - randomValue = parseRv(member.slice('rv:'.length), INVALID_RANDOM_VALUE); - continue; - } - if (!rest) { - rest = []; - } - rest.push(member); - } - - return { - randomValue, - threshold, - rest, - }; -} - -export function serializeTraceState(otTraceState: OtelTraceState): string { - if ( - !isValidThreshold(otTraceState.threshold) && - !isValidRandomValue(otTraceState.randomValue) && - !otTraceState.rest - ) { - return ''; - } - - const parts: string[] = []; - if ( - isValidThreshold(otTraceState.threshold) && - otTraceState.threshold !== MAX_THRESHOLD - ) { - parts.push(`th:${serializeTh(otTraceState.threshold)}`); - } - if (isValidRandomValue(otTraceState.randomValue)) { - parts.push(`rv:${serializeRv(otTraceState.randomValue)}`); - } - if (otTraceState.rest) { - parts.push(...otTraceState.rest); - } - let res = parts.join(';'); - while (res.length > TRACE_STATE_SIZE_LIMIT) { - const lastSemicolon = res.lastIndexOf(';'); - if (lastSemicolon === -1) { - break; - } - res = res.slice(0, lastSemicolon); - } - return res; -} - -function parseTh(value: string, defaultValue: bigint): bigint { - if (!value || value.length > MAX_VALUE_LENGTH) { - return defaultValue; - } - - try { - return BigInt('0x' + value.padEnd(MAX_VALUE_LENGTH, '0')); - } catch { - return defaultValue; - } -} - -function parseRv(value: string, defaultValue: bigint): bigint { - if (!value || value.length !== MAX_VALUE_LENGTH) { - return defaultValue; - } - - try { - return BigInt(`0x${value}`); - } catch { - return defaultValue; - } -} - -// hex value without trailing zeros -export function serializeTh(threshold: bigint): string { - if (threshold === 0n) { - return '0'; - } - - const value = threshold.toString(16).padStart(MAX_VALUE_LENGTH, '0'); - let idxAfterNonZero = value.length; - for (let i = value.length - 1; i >= 0; i--) { - if (value[i] !== '0') { - idxAfterNonZero = i + 1; - break; - } - } - // Checked at beginning so there is definitely a nonzero. - return value.slice(0, idxAfterNonZero); -} - -function serializeRv(randomValue: bigint): string { - return randomValue.toString(16).padStart(MAX_VALUE_LENGTH, '0'); -} diff --git a/experimental/packages/sampler-composite/src/types.ts b/experimental/packages/sampler-composite/src/types.ts deleted file mode 100644 index 3743a38c071..00000000000 --- a/experimental/packages/sampler-composite/src/types.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Attributes, TraceState } from '@opentelemetry/api'; -import { type Sampler } from '@opentelemetry/sdk-trace-base'; - -/** Information to make a sampling decision. */ -export type SamplingIntent = { - /** The sampling threshold value. A lower threshold increases the likelihood of sampling. */ - threshold: bigint; - - /** Whether the threshold can be reliably used for Span-to-Metrics estimation. */ - thresholdReliable: boolean; - - /** Any attributes to add to the span for the sampling result. */ - attributes?: Attributes; - - /** How to update the TraceState for the span. */ - updateTraceState?: (ts: TraceState | undefined) => TraceState | undefined; -}; - -/** A sampler that can be composed to make a final sampling decision. */ -export interface ComposableSampler { - /** Returns the information to make a sampling decision. */ - getSamplingIntent( - ...args: Parameters - ): SamplingIntent; - - /** Returns the sampler name or short description with the configuration. */ - toString(): string; -} diff --git a/experimental/packages/sampler-composite/src/util.ts b/experimental/packages/sampler-composite/src/util.ts deleted file mode 100644 index 5ba900c427e..00000000000 --- a/experimental/packages/sampler-composite/src/util.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export const INVALID_THRESHOLD = -1n; -export const INVALID_RANDOM_VALUE = -1n; - -const RANDOM_VALUE_BITS = 56n; -export const MAX_THRESHOLD = 1n << RANDOM_VALUE_BITS; // 0% sampling -export const MIN_THRESHOLD = 0n; // 100% sampling -const MAX_RANDOM_VALUE = MAX_THRESHOLD - 1n; - -export function isValidThreshold(threshold: bigint): boolean { - return threshold >= MIN_THRESHOLD && threshold <= MAX_THRESHOLD; -} - -export function isValidRandomValue(randomValue: bigint): boolean { - return randomValue >= 0n && randomValue <= MAX_RANDOM_VALUE; -} diff --git a/experimental/packages/sampler-composite/test/alwaysoff.test.ts b/experimental/packages/sampler-composite/test/alwaysoff.test.ts deleted file mode 100644 index e10c9c28274..00000000000 --- a/experimental/packages/sampler-composite/test/alwaysoff.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as assert from 'assert'; - -import { context, SpanKind } from '@opentelemetry/api'; -import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; - -import { - createCompositeSampler, - createComposableAlwaysOffSampler, -} from '../src'; -import { traceIdGenerator } from './util'; - -describe('ComposableAlwaysOffSampler', () => { - const composableSampler = createComposableAlwaysOffSampler(); - - it('should have a description', () => { - assert.strictEqual( - composableSampler.toString(), - 'ComposableAlwaysOffSampler' - ); - }); - - it('should have a constant threshold', () => { - assert.strictEqual( - composableSampler.getSamplingIntent( - context.active(), - 'unused', - 'span', - SpanKind.SERVER, - {}, - [] - ).threshold, - -1n - ); - }); - - it('should never sample', () => { - const sampler = createCompositeSampler(composableSampler); - const generator = traceIdGenerator(); - let numSampled = 0; - for (let i = 0; i < 10000; i++) { - const result = sampler.shouldSample( - context.active(), - generator(), - 'span', - SpanKind.SERVER, - {}, - [] - ); - if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { - numSampled++; - } - assert.strictEqual(result.traceState, undefined); - } - assert.strictEqual(numSampled, 0); - }); -}); diff --git a/experimental/packages/sampler-composite/test/alwayson.test.ts b/experimental/packages/sampler-composite/test/alwayson.test.ts deleted file mode 100644 index 7a29a1fa8c3..00000000000 --- a/experimental/packages/sampler-composite/test/alwayson.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as assert from 'assert'; - -import { context, SpanKind } from '@opentelemetry/api'; -import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; - -import { - createCompositeSampler, - createComposableAlwaysOnSampler, -} from '../src'; -import { traceIdGenerator } from './util'; - -describe('ComposableAlwaysOnSampler', () => { - const composableSampler = createComposableAlwaysOnSampler(); - - it('should have a description', () => { - assert.strictEqual( - composableSampler.toString(), - 'ComposableAlwaysOnSampler' - ); - }); - - it('should have a constant threshold', () => { - assert.strictEqual( - composableSampler.getSamplingIntent( - context.active(), - 'unused', - 'span', - SpanKind.SERVER, - {}, - [] - ).threshold, - 0n - ); - }); - - it('should always sample', () => { - const sampler = createCompositeSampler(composableSampler); - const generator = traceIdGenerator(); - let numSampled = 0; - for (let i = 0; i < 10000; i++) { - const result = sampler.shouldSample( - context.active(), - generator(), - 'span', - SpanKind.SERVER, - {}, - [] - ); - if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { - numSampled++; - } - assert.strictEqual(result.traceState?.get('ot'), 'th:0'); - } - assert.strictEqual(numSampled, 10000); - }); -}); diff --git a/experimental/packages/sampler-composite/test/sampler.test.ts b/experimental/packages/sampler-composite/test/sampler.test.ts deleted file mode 100644 index 86383d93ec7..00000000000 --- a/experimental/packages/sampler-composite/test/sampler.test.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as assert from 'assert'; - -import { - context, - SpanContext, - SpanKind, - TraceFlags, - trace, -} from '@opentelemetry/api'; -import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; - -import { - createCompositeSampler, - createComposableAlwaysOffSampler, - createComposableAlwaysOnSampler, - createComposableParentThresholdSampler, - createComposableTraceIDRatioBasedSampler, -} from '../src'; -import { INVALID_RANDOM_VALUE, INVALID_THRESHOLD } from '../src/util'; -import { - INVALID_TRACE_STATE, - parseOtelTraceState, - serializeTraceState, -} from '../src/tracestate'; -import { TraceState } from '@opentelemetry/core'; - -describe('ConsistentSampler', () => { - const traceId = '00112233445566778800000000000000'; - const spanId = '0123456789abcdef'; - - [ - { - sampler: createComposableAlwaysOnSampler(), - parentSampled: true, - parentThreshold: undefined, - parentRandomValue: undefined, - sampled: true, - threshold: 0n, - randomValue: INVALID_RANDOM_VALUE, - testId: 'min threshold no parent random value', - }, - { - sampler: createComposableAlwaysOnSampler(), - parentSampled: true, - parentThreshold: undefined, - parentRandomValue: 0x7f99aa40c02744n, - sampled: true, - threshold: 0n, - randomValue: 0x7f99aa40c02744n, - testId: 'min threshold with parent random value', - }, - { - sampler: createComposableAlwaysOffSampler(), - parentSampled: true, - parentThreshold: undefined, - parentRandomValue: undefined, - sampled: false, - threshold: INVALID_THRESHOLD, - randomValue: INVALID_RANDOM_VALUE, - testId: 'max threshold', - }, - { - sampler: createComposableParentThresholdSampler( - createComposableAlwaysOnSampler() - ), - parentSampled: false, - parentThreshold: 0x7f99aa40c02744n, - parentRandomValue: 0x7f99aa40c02744n, - sampled: true, - threshold: 0x7f99aa40c02744n, - randomValue: 0x7f99aa40c02744n, - testId: 'parent based in consistent mode', - }, - { - sampler: createComposableParentThresholdSampler( - createComposableAlwaysOnSampler() - ), - parentSampled: true, - parentThreshold: undefined, - parentRandomValue: undefined, - sampled: true, - threshold: INVALID_THRESHOLD, - randomValue: INVALID_RANDOM_VALUE, - testId: 'parent based in legacy mode', - }, - { - sampler: createComposableTraceIDRatioBasedSampler(0.5), - parentSampled: true, - parentThreshold: undefined, - parentRandomValue: 0x7fffffffffffffn, - sampled: false, - threshold: INVALID_THRESHOLD, - randomValue: 0x7fffffffffffffn, - testId: 'half threshold not sampled', - }, - { - sampler: createComposableTraceIDRatioBasedSampler(0.5), - parentSampled: false, - parentThreshold: undefined, - parentRandomValue: 0x80000000000000n, - sampled: true, - threshold: 0x80000000000000n, - randomValue: 0x80000000000000n, - testId: 'half threshold sampled', - }, - { - sampler: createComposableTraceIDRatioBasedSampler(1.0), - parentSampled: false, - parentThreshold: 0x80000000000000n, - parentRandomValue: 0x80000000000000n, - sampled: true, - threshold: 0n, - randomValue: 0x80000000000000n, - testId: 'parent inviolating invariant', - }, - ].forEach( - ({ - sampler, - parentSampled, - parentThreshold, - parentRandomValue, - sampled, - threshold, - randomValue, - testId, - }) => { - it(`should sample with ${testId}`, () => { - let parentOtTraceState = INVALID_TRACE_STATE; - if (parentThreshold !== undefined) { - parentOtTraceState = { - ...parentOtTraceState, - threshold: parentThreshold, - }; - } - if (parentRandomValue !== undefined) { - parentOtTraceState = { - ...parentOtTraceState, - randomValue: parentRandomValue, - }; - } - const parentOt = serializeTraceState(parentOtTraceState); - const parentTraceState = parentOt - ? new TraceState().set('ot', parentOt) - : undefined; - const traceFlags = parentSampled ? TraceFlags.SAMPLED : TraceFlags.NONE; - const parentSpanContext: SpanContext = { - traceId, - spanId, - traceFlags, - traceState: parentTraceState, - }; - const parentContext = trace.setSpanContext( - context.active(), - parentSpanContext - ); - - const result = createCompositeSampler(sampler).shouldSample( - parentContext, - traceId, - 'name', - SpanKind.INTERNAL, - {}, - [] - ); - const expectedDecision = sampled - ? SamplingDecision.RECORD_AND_SAMPLED - : SamplingDecision.NOT_RECORD; - const state = parseOtelTraceState(result.traceState); - - assert.strictEqual(result.decision, expectedDecision); - assert.strictEqual(state.threshold, threshold); - assert.strictEqual(state.randomValue, randomValue); - }); - } - ); -}); diff --git a/experimental/packages/sampler-composite/test/traceidratio.test.ts b/experimental/packages/sampler-composite/test/traceidratio.test.ts deleted file mode 100644 index fc9499aa088..00000000000 --- a/experimental/packages/sampler-composite/test/traceidratio.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import * as assert from 'assert'; - -import { context, SpanKind } from '@opentelemetry/api'; -import { SamplingDecision } from '@opentelemetry/sdk-trace-base'; - -import { - createCompositeSampler, - createComposableTraceIDRatioBasedSampler, -} from '../src'; -import { traceIdGenerator } from './util'; -import { parseOtelTraceState } from '../src/tracestate'; -import { INVALID_RANDOM_VALUE } from '../src/util'; - -describe('ComposableTraceIDRatioBasedSampler', () => { - [ - { ratio: 1.0, thresholdStr: '0' }, - { ratio: 0.5, thresholdStr: '8' }, - { ratio: 0.25, thresholdStr: 'c' }, - { ratio: 1e-300, thresholdStr: 'max' }, - { ratio: 0, thresholdStr: 'max' }, - ].forEach(({ ratio, thresholdStr }) => { - it(`should have a description for ratio ${ratio}`, () => { - const sampler = createComposableTraceIDRatioBasedSampler(ratio); - assert.strictEqual( - sampler.toString(), - `ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})` - ); - }); - }); - - [ - { ratio: 1.0, threshold: 0n }, - { ratio: 0.5, threshold: 36028797018963968n }, - { ratio: 0.25, threshold: 54043195528445952n }, - { ratio: 0.125, threshold: 63050394783186944n }, - { ratio: 0.0, threshold: 72057594037927936n }, - { ratio: 0.45, threshold: 39631676720860364n }, - { ratio: 0.2, threshold: 57646075230342348n }, - { ratio: 0.13, threshold: 62690106812997304n }, - { ratio: 0.05, threshold: 68454714336031539n }, - ].forEach(({ ratio, threshold }) => { - it(`should sample spans with ratio ${ratio}`, () => { - const sampler = createCompositeSampler( - createComposableTraceIDRatioBasedSampler(ratio) - ); - - const generator = traceIdGenerator(); - let numSampled = 0; - for (let i = 0; i < 10000; i++) { - const result = sampler.shouldSample( - context.active(), - generator(), - 'span', - SpanKind.SERVER, - {}, - [] - ); - if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) { - numSampled++; - const otTraceState = parseOtelTraceState(result.traceState); - assert.strictEqual(otTraceState?.threshold, threshold); - assert.strictEqual(otTraceState?.randomValue, INVALID_RANDOM_VALUE); - } - } - const expectedNumSampled = 10000 * ratio; - assert.ok( - Math.abs(numSampled - expectedNumSampled) < 50, - `expected ${expectedNumSampled}, have ${numSampled}` - ); - }); - }); -}); diff --git a/experimental/packages/sampler-composite/test/tracestate.test.ts b/experimental/packages/sampler-composite/test/tracestate.test.ts deleted file mode 100644 index 3e439029533..00000000000 --- a/experimental/packages/sampler-composite/test/tracestate.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as assert from 'assert'; -import { serializeTraceState, parseOtelTraceState } from '../src/tracestate'; -import { TraceState } from '@opentelemetry/core'; - -describe('OtelTraceState', () => { - [ - { input: 'a', output: 'a' }, - { input: '#', output: '#' }, - { input: 'rv:1234567890abcd', output: 'rv:1234567890abcd' }, - { input: 'rv:01020304050607', output: 'rv:01020304050607' }, - { input: 'rv:1234567890abcde', output: '' }, - { input: 'th:1234567890abcd', output: 'th:1234567890abcd' }, - { input: 'th:1234567890abcd', output: 'th:1234567890abcd' }, - { input: 'th:10000000000000', output: 'th:1' }, - { input: 'th:1234500000000', output: 'th:12345' }, - { input: 'th:0', output: 'th:0' }, - { input: 'th:100000000000000', output: '' }, - { input: 'th:1234567890abcde', output: '' }, - { - input: `a:${''.padEnd(214, 'X')};rv:1234567890abcd;th:1234567890abcd;x:3`, - output: `th:1234567890abcd;rv:1234567890abcd;a:${''.padEnd(214, 'X')};x:3`, - testId: 'long', - }, - { input: 'th:x', output: '' }, - { input: 'th:100000000000000', output: '' }, - { input: 'th:10000000000000', output: 'th:1' }, - { input: 'th:1000000000000', output: 'th:1' }, - { input: 'th:100000000000', output: 'th:1' }, - { input: 'th:10000000000', output: 'th:1' }, - { input: 'th:1000000000', output: 'th:1' }, - { input: 'th:100000000', output: 'th:1' }, - { input: 'th:10000000', output: 'th:1' }, - { input: 'th:1000000', output: 'th:1' }, - { input: 'th:100000', output: 'th:1' }, - { input: 'th:10000', output: 'th:1' }, - { input: 'th:1000', output: 'th:1' }, - { input: 'th:100', output: 'th:1' }, - { input: 'th:10', output: 'th:1' }, - { input: 'th:1', output: 'th:1' }, - { input: 'th:10000000000001', output: 'th:10000000000001' }, - { input: 'th:10000000000010', output: 'th:1000000000001' }, - { input: 'rv:x', output: '' }, - { input: 'rv:100000000000000', output: '' }, - { input: 'rv:10000000000000', output: 'rv:10000000000000' }, - { input: 'rv:1000000000000', output: '' }, - ].forEach(({ input, output, testId }) => { - it(`should round trip ${testId || `from ${input} to ${output}`}`, () => { - const result = serializeTraceState( - parseOtelTraceState(new TraceState().set('ot', input)) - ); - assert.strictEqual(result, output); - }); - }); -}); diff --git a/experimental/packages/sampler-composite/test/util.ts b/experimental/packages/sampler-composite/test/util.ts deleted file mode 100644 index a4b393aa5d4..00000000000 --- a/experimental/packages/sampler-composite/test/util.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Use a fixed seed simple but reasonable random number generator for consistent tests. -// Unlike many languages, there isn't a way to set the seed of the built-in random. - -function splitmix32(a: number) { - return function () { - a |= 0; - a = (a + 0x9e3779b9) | 0; - let t = a ^ (a >>> 16); - t = Math.imul(t, 0x21f0aaad); - t = t ^ (t >>> 15); - t = Math.imul(t, 0x735a2d97); - return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296; - }; -} - -export function traceIdGenerator(): () => string { - const seed = 0xdeadbeef; - const random = splitmix32(seed); - // Pre-mix the state. - for (let i = 0; i < 15; i++) { - random(); - } - return () => { - const parts: string[] = []; - // 32-bit randoms, concatenate 4 of them - for (let i = 0; i < 4; i++) { - const val = Math.round(random() * 0xffffffff); - parts.push(val.toString(16).padStart(8, '0')); - } - return parts.join(''); - }; -} diff --git a/experimental/packages/sampler-composite/tsconfig.esm.json b/experimental/packages/sampler-composite/tsconfig.esm.json deleted file mode 100644 index 5fe96d554ba..00000000000 --- a/experimental/packages/sampler-composite/tsconfig.esm.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "extends": "../../../tsconfig.base.esm.json", - "compilerOptions": { - "allowJs": true, - "outDir": "build/esm", - "rootDir": "src", - "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" - }, - "include": [ - "src/**/*.ts" - ], - "references": [ - { - "path": "../../../api" - }, - { - "path": "../../../packages/opentelemetry-core" - }, - { - "path": "../../../packages/opentelemetry-sdk-trace-base" - } - ] -} diff --git a/experimental/packages/sampler-composite/tsconfig.esnext.json b/experimental/packages/sampler-composite/tsconfig.esnext.json deleted file mode 100644 index 17ed0461704..00000000000 --- a/experimental/packages/sampler-composite/tsconfig.esnext.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "extends": "../../../tsconfig.base.esnext.json", - "compilerOptions": { - "allowJs": true, - "outDir": "build/esnext", - "rootDir": "src", - "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo" - }, - "include": [ - "src/**/*.ts" - ], - "references": [ - { - "path": "../../../api" - }, - { - "path": "../../../packages/opentelemetry-core" - }, - { - "path": "../../../packages/opentelemetry-sdk-trace-base" - } - ] -} diff --git a/experimental/packages/sampler-composite/tsconfig.json b/experimental/packages/sampler-composite/tsconfig.json deleted file mode 100644 index eb6f0a3a273..00000000000 --- a/experimental/packages/sampler-composite/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "allowJs": true, - "outDir": "build", - "rootDir": "." - }, - "files": [], - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ], - "references": [ - { - "path": "../../../api" - }, - { - "path": "../../../packages/opentelemetry-core" - }, - { - "path": "../../../packages/opentelemetry-sdk-trace-base" - } - ] -} diff --git a/package-lock.json b/package-lock.json index e4c17675ee5..45cf14f0b5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1449,257 +1449,6 @@ "@opentelemetry/api": "^1.3.0" } }, - "experimental/packages/sampler-composite": { - "name": "@opentelemetry/sampler-composite", - "version": "0.205.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "devDependencies": { - "@opentelemetry/api": "1.9.0", - "@types/mocha": "10.0.10", - "@types/node": "18.6.5", - "lerna": "6.6.2", - "mocha": "11.1.0", - "nyc": "17.1.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "experimental/packages/sampler-composite/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "experimental/packages/sampler-composite/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "experimental/packages/sampler-composite/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "experimental/packages/sampler-composite/node_modules/@types/node": { - "version": "18.6.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", - "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", - "dev": true, - "license": "MIT" - }, - "experimental/packages/sampler-composite/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "experimental/packages/sampler-composite/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "experimental/packages/sampler-composite/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "experimental/packages/sampler-composite/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "experimental/packages/sampler-composite/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "experimental/packages/sampler-composite/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "experimental/packages/sampler-composite/node_modules/mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "experimental/packages/sampler-composite/node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "experimental/packages/sampler-composite/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "experimental/packages/sampler-composite/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "experimental/packages/sampler-composite/node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "experimental/packages/sampler-composite/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "experimental/packages/sampler-jaeger-remote": { "name": "@opentelemetry/sampler-jaeger-remote", "version": "0.205.0", @@ -6214,10 +5963,6 @@ "resolved": "packages/opentelemetry-resources", "link": true }, - "node_modules/@opentelemetry/sampler-composite": { - "resolved": "experimental/packages/sampler-composite", - "link": true - }, "node_modules/@opentelemetry/sampler-jaeger-remote": { "resolved": "experimental/packages/sampler-jaeger-remote", "link": true @@ -31296,175 +31041,6 @@ } } }, - "@opentelemetry/sampler-composite": { - "version": "file:experimental/packages/sampler-composite", - "requires": { - "@opentelemetry/api": "1.9.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "@types/mocha": "10.0.10", - "@types/node": "18.6.5", - "lerna": "6.6.2", - "mocha": "11.1.0", - "nyc": "17.1.0" - }, - "dependencies": { - "@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "requires": { - "@opentelemetry/semantic-conventions": "^1.29.0" - } - }, - "@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "requires": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - } - }, - "@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "requires": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - } - }, - "@types/node": { - "version": "18.6.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz", - "integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true - }, - "glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - } - }, - "jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "dependencies": { - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "requires": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, "@opentelemetry/sampler-jaeger-remote": { "version": "file:experimental/packages/sampler-jaeger-remote", "requires": { diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 711743009ba..2bb983f4064 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -44,9 +44,6 @@ { "path": "experimental/packages/otlp-transformer/tsconfig.esm.json" }, - { - "path": "experimental/packages/sampler-composite/tsconfig.esm.json" - }, { "path": "experimental/packages/sdk-logs/tsconfig.esm.json" }, diff --git a/tsconfig.esnext.json b/tsconfig.esnext.json index cfc96b3bda9..ac540a88b2d 100644 --- a/tsconfig.esnext.json +++ b/tsconfig.esnext.json @@ -44,9 +44,6 @@ { "path": "experimental/packages/otlp-transformer/tsconfig.esnext.json" }, - { - "path": "experimental/packages/sampler-composite/tsconfig.esnext.json" - }, { "path": "experimental/packages/sdk-logs/tsconfig.esnext.json" }, diff --git a/tsconfig.json b/tsconfig.json index 58f4ff7e340..ee5c10de7b4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,6 @@ "experimental/packages/otlp-exporter-base", "experimental/packages/otlp-grpc-exporter-base", "experimental/packages/otlp-transformer", - "experimental/packages/sampler-composite", "experimental/packages/sampler-jaeger-remote", "experimental/packages/sdk-logs", "experimental/packages/shim-opencensus", @@ -127,9 +126,6 @@ { "path": "experimental/packages/otlp-transformer" }, - { - "path": "experimental/packages/sampler-composite" - }, { "path": "experimental/packages/sampler-jaeger-remote" }, From ba49203571702a685b24c8c08793f234c998c259 Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 22 Sep 2025 16:34:47 -0400 Subject: [PATCH 13/15] use correct type --- .../opentelemetry-configuration/src/FileConfigProvider.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index 7f6204061d6..aa10c9801de 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -16,6 +16,7 @@ import { diagLogLevelFromString, getStringFromEnv } from '@opentelemetry/core'; import { + ConfigAttributes, ConfigurationModel, initializeDefaultConfiguration, } from './configModel'; @@ -101,14 +102,13 @@ function parseConfigFile(config: ConfigurationModel) { } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function setResourceAttributes(config: ConfigurationModel, attributes: any[]) { +function setResourceAttributes(config: ConfigurationModel, attributes: ConfigAttributes[]) { if (attributes) { config.resource.attributes = []; for (let i = 0; i < attributes.length; i++) { const att = attributes[i]; config.resource.attributes.push({ - name: att['name'], + name: getStringFromConfigFile(att['name']) ?? '', value: att['value'], type: att['type'] ?? 'string', }); From 7524d757cbce0c2e6060cecf40bb6ba07e1fb601 Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 22 Sep 2025 16:54:40 -0400 Subject: [PATCH 14/15] update test --- .../test/ConfigProvider.test.ts | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts index 9e8086963db..7b45b604602 100644 --- a/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts +++ b/experimental/packages/opentelemetry-configuration/test/ConfigProvider.test.ts @@ -162,6 +162,87 @@ const configFromFile: Configuration = { }, ], }, + attribute_limits: { + attribute_count_limit: 128, + }, + propagator: { + composite: ['tracecontext', 'baggage'], + composite_list: 'tracecontext,baggage', + }, + tracer_provider: { + processors: [ + { + batch: { + schedule_delay: 5000, + export_timeout: 30000, + max_queue_size: 2048, + max_export_batch_size: 512, + exporter: { + otlp_http: { + endpoint: 'http://localhost:4318/v1/traces', + timeout: 10000, + }, + }, + }, + }, + ], + limits: { + attribute_count_limit: 128, + event_count_limit: 128, + link_count_limit: 128, + event_attribute_count_limit: 128, + link_attribute_count_limit: 128, + }, + sampler: { + parent_based: { + root: 'always_on', + remote_parent_sampled: 'always_on', + remote_parent_not_sampled: 'always_off', + local_parent_sampled: 'always_on', + local_parent_not_sampled: 'always_off', + }, + }, + }, + meter_provider: { + readers: [ + { + periodic: { + interval: 60000, + timeout: 30000, + exporter: { + otlp_http: { + endpoint: 'http://localhost:4318/v1/metrics', + timeout: 10000, + temporality_preference: 'cumulative', + default_histogram_aggregation: 'explicit_bucket_histogram', + }, + }, + }, + }, + ], + exemplar_filter: 'trace_based', + }, + logger_provider: { + processors: [ + { + batch: { + schedule_delay: 1000, + export_timeout: 30000, + max_queue_size: 2048, + max_export_batch_size: 512, + exporter: { + otlp_http: { + endpoint: 'http://localhost:4318/v1/logs', + timeout: 10000, + }, + }, + }, + }, + ], + limits: { + attribute_count_limit: 128, + }, + }, }; describe('ConfigProvider', function () { From d695c913488842a729482167cda375eb8689a4c0 Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 22 Sep 2025 16:59:16 -0400 Subject: [PATCH 15/15] fix lint --- .../opentelemetry-configuration/src/FileConfigProvider.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts index aa10c9801de..ebcd47436a9 100644 --- a/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts +++ b/experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts @@ -102,7 +102,10 @@ function parseConfigFile(config: ConfigurationModel) { } } -function setResourceAttributes(config: ConfigurationModel, attributes: ConfigAttributes[]) { +function setResourceAttributes( + config: ConfigurationModel, + attributes: ConfigAttributes[] +) { if (attributes) { config.resource.attributes = []; for (let i = 0; i < attributes.length; i++) {