Skip to content

Commit b11baa1

Browse files
maryliagpichlermarctrentm
authored
feat(opentelemetry-configuration): Parse of Configuration File (#5875)
Co-authored-by: Marc Pichler <[email protected]> Co-authored-by: Trent Mick <[email protected]>
1 parent 0d8f4af commit b11baa1

File tree

12 files changed

+399
-20
lines changed

12 files changed

+399
-20
lines changed

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
1313
* feat(otlp-transformer): add span flags support for isRemote property [#5910](https://github.com/open-telemetry/opentelemetry-js/pull/5910) @nikhilmantri0902
1414
* feat(sampler-composite): Added experimental implementations of draft composite sampling spec [#5839](https://github.com/open-telemetry/opentelemetry-js/pull/5839) @anuraaga
1515
* feat(opentelemetry-configuration): add more attributes to config model [#5826](https://github.com/open-telemetry/opentelemetry-js/pull/5826) @maryliag
16+
* feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag
1617

1718
### :bug: Bug Fixes
1819

experimental/packages/opentelemetry-configuration/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
},
4242
"dependencies": {
4343
"@opentelemetry/api": "^1.9.0",
44-
"@opentelemetry/core": "2.1.0"
44+
"@opentelemetry/core": "2.1.0",
45+
"yaml": "^1.10.2"
4546
},
4647
"devDependencies": {
4748
"@opentelemetry/api": "^1.9.0",

experimental/packages/opentelemetry-configuration/src/EnvironmentConfigProvider.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { DiagLogLevel } from '@opentelemetry/api';
1817
import {
1918
ConfigurationModel,
2019
initializeDefaultConfiguration,
@@ -36,12 +35,11 @@ export class EnvironmentConfigProvider implements ConfigProvider {
3635

3736
constructor() {
3837
this._config = initializeDefaultConfiguration();
39-
this._config.disable = getBooleanFromEnv('OTEL_SDK_DISABLED');
38+
this._config.disabled = getBooleanFromEnv('OTEL_SDK_DISABLED');
4039

41-
const logLevel = getStringFromEnv('OTEL_LOG_LEVEL');
40+
const logLevel = diagLogLevelFromString(getStringFromEnv('OTEL_LOG_LEVEL'));
4241
if (logLevel) {
43-
this._config.log_level =
44-
diagLogLevelFromString(logLevel) ?? DiagLogLevel.INFO;
42+
this._config.log_level = logLevel;
4543
}
4644

4745
const nodeResourceDetectors = getStringListFromEnv(

experimental/packages/opentelemetry-configuration/src/FileConfigProvider.ts

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,27 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { getStringFromEnv } from '@opentelemetry/core';
17+
import { diagLogLevelFromString, getStringFromEnv } from '@opentelemetry/core';
1818
import {
19+
ConfigAttributes,
1920
ConfigurationModel,
2021
initializeDefaultConfiguration,
2122
} from './configModel';
2223
import { ConfigProvider } from './IConfigProvider';
2324
import * as fs from 'fs';
25+
import * as yaml from 'yaml';
26+
import {
27+
getBooleanFromConfigFile,
28+
getNumberFromConfigFile,
29+
getStringFromConfigFile,
30+
} from './utils';
2431

2532
export class FileConfigProvider implements ConfigProvider {
2633
private _config: ConfigurationModel;
2734

2835
constructor() {
2936
this._config = initializeDefaultConfiguration();
37+
parseConfigFile(this._config);
3038
}
3139

3240
getInstrumentationConfig(): ConfigurationModel {
@@ -37,7 +45,10 @@ export class FileConfigProvider implements ConfigProvider {
3745
export function hasValidConfigFile(): boolean {
3846
const configFile = getStringFromEnv('OTEL_EXPERIMENTAL_CONFIG_FILE');
3947
if (configFile) {
40-
if (!configFile.endsWith('.yaml') || !fs.existsSync(configFile)) {
48+
if (
49+
!(configFile.endsWith('.yaml') || configFile.endsWith('.yml')) ||
50+
!fs.existsSync(configFile)
51+
) {
4152
throw new Error(
4253
`Config file ${configFile} set on OTEL_EXPERIMENTAL_CONFIG_FILE is not valid`
4354
);
@@ -46,3 +57,64 @@ export function hasValidConfigFile(): boolean {
4657
}
4758
return false;
4859
}
60+
61+
function parseConfigFile(config: ConfigurationModel) {
62+
const supportedFileVersions = ['1.0-rc.1'];
63+
const configFile = getStringFromEnv('OTEL_EXPERIMENTAL_CONFIG_FILE') || '';
64+
const file = fs.readFileSync(configFile, 'utf8');
65+
const parsedContent = yaml.parse(file);
66+
67+
if (
68+
parsedContent['file_format'] &&
69+
supportedFileVersions.includes(parsedContent['file_format'])
70+
) {
71+
const disabled = getBooleanFromConfigFile(parsedContent['disabled']);
72+
if (disabled || disabled === false) {
73+
config.disabled = disabled;
74+
}
75+
76+
const logLevel = getNumberFromConfigFile(
77+
diagLogLevelFromString(parsedContent['log_level'])
78+
);
79+
if (logLevel) {
80+
config.log_level = logLevel;
81+
}
82+
83+
const attrList = getStringFromConfigFile(
84+
parsedContent['resource']?.['attributes_list']
85+
);
86+
if (attrList) {
87+
config.resource.attributes_list = attrList;
88+
}
89+
90+
const schemaUrl = getStringFromConfigFile(
91+
parsedContent['resource']?.['schema_url']
92+
);
93+
if (schemaUrl) {
94+
config.resource.schema_url = schemaUrl;
95+
}
96+
97+
setResourceAttributes(config, parsedContent['resource']?.['attributes']);
98+
} else {
99+
throw new Error(
100+
`Unsupported File Format: ${parsedContent['file_format']}. It must be one of the following: ${supportedFileVersions}`
101+
);
102+
}
103+
}
104+
105+
function setResourceAttributes(
106+
config: ConfigurationModel,
107+
attributes: ConfigAttributes[]
108+
) {
109+
if (attributes) {
110+
config.resource.attributes = [];
111+
for (let i = 0; i < attributes.length; i++) {
112+
const att = attributes[i];
113+
config.resource.attributes.push({
114+
name: getStringFromConfigFile(att['name']) ?? '',
115+
value: att['value'],
116+
type: att['type'] ?? 'string',
117+
});
118+
}
119+
}
120+
}

experimental/packages/opentelemetry-configuration/src/configModel.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface ConfigurationModel {
2121
* Configure if the SDK is disabled or not.
2222
* If omitted or null, false is used.
2323
*/
24-
disable: boolean;
24+
disabled: boolean;
2525

2626
/**
2727
* Configure the log level of the internal logger used by the SDK.
@@ -70,7 +70,7 @@ export interface ConfigurationModel {
7070

7171
export function initializeDefaultConfiguration(): ConfigurationModel {
7272
const config: ConfigurationModel = {
73-
disable: false,
73+
disabled: false,
7474
log_level: DiagLogLevel.INFO,
7575
node_resource_detectors: ['all'],
7676
resource: {},
@@ -163,7 +163,7 @@ export function initializeDefaultConfiguration(): ConfigurationModel {
163163
export interface ConfigAttributes {
164164
name: string;
165165
value: string | boolean | number | string[] | boolean[] | number[];
166-
type?:
166+
type:
167167
| 'string'
168168
| 'bool'
169169
| 'int'
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { diag } from '@opentelemetry/api';
17+
import { inspect } from 'util';
18+
19+
/**
20+
* Retrieves a boolean value from a configuration file parameter.
21+
* - Trims leading and trailing whitespace and ignores casing.
22+
* - Returns `undefined` if the value is empty, unset, or contains only whitespace.
23+
* - Returns `undefined` and a warning for values that cannot be mapped to a boolean.
24+
*
25+
* @param {unknown} value - The value from the config file.
26+
* @returns {boolean} - The boolean value or `false` if the environment variable is unset empty, unset, or contains only whitespace.
27+
*/
28+
export function getBooleanFromConfigFile(value: unknown): boolean | undefined {
29+
const raw = String(value)?.trim().toLowerCase();
30+
if (raw === 'true') {
31+
return true;
32+
} else if (raw === 'false') {
33+
return false;
34+
} else if (raw == null || raw === '') {
35+
return undefined;
36+
} else {
37+
diag.warn(`Unknown value ${inspect(raw)}, expected 'true' or 'false'`);
38+
return undefined;
39+
}
40+
}
41+
42+
/**
43+
* Retrieves a number from a configuration file parameter.
44+
* - Returns `undefined` if the environment variable is empty, unset, or contains only whitespace.
45+
* - Returns `undefined` and a warning if is not a number.
46+
* - Returns a number in all other cases.
47+
*
48+
* @param {unknown} value - The value from the config file.
49+
* @returns {number | undefined} - The number value or `undefined`.
50+
*/
51+
export function getNumberFromConfigFile(value: unknown): number | undefined {
52+
const raw = String(value)?.trim();
53+
if (raw == null || raw.trim() === '') {
54+
return undefined;
55+
}
56+
57+
const n = Number(raw);
58+
if (isNaN(n)) {
59+
diag.warn(`Unknown value ${inspect(raw)}, expected a number`);
60+
return undefined;
61+
}
62+
63+
return n;
64+
}
65+
66+
/**
67+
* Retrieves a string from a configuration file parameter.
68+
* - Returns `undefined` if the environment variable is empty, unset, or contains only whitespace.
69+
*
70+
* @param {unknown} value - The value from the config file.
71+
* @returns {string | undefined} - The string value or `undefined`.
72+
*/
73+
export function getStringFromConfigFile(value: unknown): string | undefined {
74+
const raw = String(value)?.trim();
75+
if (value == null || raw === '') {
76+
return undefined;
77+
}
78+
return raw;
79+
}

0 commit comments

Comments
 (0)