Skip to content

Commit 6cca46e

Browse files
authored
fix(configuration): combine resource attributes and attributes list correctly (#6166)
1 parent 1430893 commit 6cca46e

File tree

5 files changed

+245
-78
lines changed

5 files changed

+245
-78
lines changed

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
2828
* fix(instrumentation-grpc): attach correct name to diag message [#6097](https://github.com/open-telemetry/opentelemetry-js/pull/6043) @pichlermarc
2929
* fix(opentelemetry-sdk-node): default to otlp if OTEL_METRICS_EXPORTER is empty [#6092](https://github.com/open-telemetry/opentelemetry-js/pull/6092) @jeengbe
3030
* fix(configuration): merge service name from OTEL_SERVICE_NAME instead of replacing all resource attributes [#6162](https://github.com/open-telemetry/opentelemetry-js/pull/6162) @maryliag
31+
* fix(configuration): combine resource attributes and attributes list correctly [#6166](https://github.com/open-telemetry/opentelemetry-js/pull/6166) @maryliag
3132

3233
### :books: Documentation
3334

experimental/packages/configuration/src/EnvironmentConfigFactory.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,8 @@ export function setResources(config: ConfigurationModel): void {
8787
const resourceAttrList = getStringFromEnv('OTEL_RESOURCE_ATTRIBUTES');
8888
const list = getStringListFromEnv('OTEL_RESOURCE_ATTRIBUTES');
8989
const serviceName = getStringFromEnv('OTEL_SERVICE_NAME');
90-
if (list && list.length > 0) {
91-
config.resource.attributes_list = resourceAttrList;
92-
config.resource.attributes = [];
93-
for (let i = 0; i < list.length; i++) {
94-
const element = list[i].split('=');
95-
config.resource.attributes.push({
96-
name: element[0],
97-
value:
98-
serviceName && element[0] === 'service.name'
99-
? serviceName
100-
: element[1],
101-
type: 'string',
102-
});
103-
}
104-
}
10590

106-
if (serviceName && config.resource.attributes == null) {
91+
if (serviceName) {
10792
config.resource.attributes = [
10893
{
10994
name: 'service.name',
@@ -112,6 +97,26 @@ export function setResources(config: ConfigurationModel): void {
11297
},
11398
];
11499
}
100+
if (list && list.length > 0) {
101+
config.resource.attributes_list = resourceAttrList;
102+
if (config.resource.attributes == null) {
103+
config.resource.attributes = [];
104+
}
105+
106+
for (let i = 0; i < list.length; i++) {
107+
const element = list[i].split('=');
108+
if (
109+
element[0] !== 'service.name' ||
110+
(element[0] === 'service.name' && serviceName === undefined)
111+
) {
112+
config.resource.attributes.push({
113+
name: element[0],
114+
value: element[1],
115+
type: 'string',
116+
});
117+
}
118+
}
119+
}
115120
}
116121

117122
export function setAttributeLimits(config: ConfigurationModel): void {

experimental/packages/configuration/src/FileConfigFactory.ts

Lines changed: 64 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -121,31 +121,6 @@ export function parseConfigFile(config: ConfigurationModel) {
121121
if (config.resource == null) {
122122
config.resource = {};
123123
}
124-
const attrList = getStringFromConfigFile(
125-
parsedContent['resource']?.['attributes_list']
126-
);
127-
if (attrList) {
128-
config.resource.attributes_list = attrList;
129-
const list = getStringListFromConfigFile(
130-
parsedContent['resource']?.['attributes_list']
131-
);
132-
if (
133-
list &&
134-
list.length > 0 &&
135-
parsedContent['resource']?.['attributes'] == null
136-
) {
137-
config.resource.attributes = [];
138-
for (let i = 0; i < list.length; i++) {
139-
const element = list[i].split('=');
140-
config.resource.attributes.push({
141-
name: element[0],
142-
value: element[1],
143-
type: 'string',
144-
});
145-
}
146-
}
147-
}
148-
149124
const schemaUrl = getStringFromConfigFile(
150125
parsedContent['resource']?.['schema_url']
151126
);
@@ -154,7 +129,11 @@ export function parseConfigFile(config: ConfigurationModel) {
154129
}
155130
}
156131

157-
setResourceAttributes(config, parsedContent['resource']?.['attributes']);
132+
setResourceAttributes(
133+
config,
134+
parsedContent['resource']?.['attributes'],
135+
parsedContent['resource']?.['attributes_list']
136+
);
158137
setAttributeLimits(config, parsedContent['attribute_limits']);
159138
setPropagator(config, parsedContent['propagator']);
160139
setTracerProvider(config, parsedContent['tracer_provider']);
@@ -169,44 +148,71 @@ export function parseConfigFile(config: ConfigurationModel) {
169148

170149
export function setResourceAttributes(
171150
config: ConfigurationModel,
172-
attributes: AttributeNameValue[]
151+
attributes: AttributeNameValue[],
152+
attributeList: string
173153
) {
174-
if (attributes) {
154+
if (attributes || attributeList) {
155+
const addedKeys = [];
175156
if (config.resource == null) {
176157
config.resource = {};
177158
}
178-
config.resource.attributes = [];
179-
for (let i = 0; i < attributes.length; i++) {
180-
const att = attributes[i];
181-
let value = att['value'];
182-
switch (att['type']) {
183-
case 'bool':
184-
value = getBooleanFromConfigFile(value);
185-
break;
186-
case 'bool_array':
187-
value = getBooleanListFromConfigFile(value);
188-
break;
189-
case 'int':
190-
case 'double':
191-
value = getNumberFromConfigFile(value);
192-
break;
193-
case 'int_array':
194-
case 'double_array':
195-
value = getNumberListFromConfigFile(value);
196-
break;
197-
case 'string_array':
198-
value = getStringListFromConfigFile(value);
199-
break;
200-
default:
201-
value = getStringFromConfigFile(value);
202-
break;
159+
if (getStringFromConfigFile(attributeList)) {
160+
config.resource.attributes_list = getStringFromConfigFile(attributeList);
161+
}
162+
163+
const list = getStringListFromConfigFile(attributeList);
164+
if ((list && list.length > 0) || (attributes && attributes.length > 0)) {
165+
config.resource.attributes = [];
166+
167+
if (attributes) {
168+
for (let i = 0; i < attributes.length; i++) {
169+
const att = attributes[i];
170+
let value = att['value'];
171+
switch (att['type']) {
172+
case 'bool':
173+
value = getBooleanFromConfigFile(value);
174+
break;
175+
case 'bool_array':
176+
value = getBooleanListFromConfigFile(value);
177+
break;
178+
case 'int':
179+
case 'double':
180+
value = getNumberFromConfigFile(value);
181+
break;
182+
case 'int_array':
183+
case 'double_array':
184+
value = getNumberListFromConfigFile(value);
185+
break;
186+
case 'string_array':
187+
value = getStringListFromConfigFile(value);
188+
break;
189+
default:
190+
value = getStringFromConfigFile(value);
191+
break;
192+
}
193+
194+
const key = getStringFromConfigFile(att['name']) ?? '';
195+
config.resource.attributes.push({
196+
name: key,
197+
value: value,
198+
type: att['type'] ?? 'string',
199+
});
200+
addedKeys.push(key);
201+
}
203202
}
204203

205-
config.resource.attributes.push({
206-
name: getStringFromConfigFile(att['name']) ?? '',
207-
value: value,
208-
type: att['type'] ?? 'string',
209-
});
204+
if (list) {
205+
for (let i = 0; i < list.length; i++) {
206+
const element = list[i].split('=');
207+
if (!addedKeys.includes(element[0])) {
208+
config.resource.attributes.push({
209+
name: element[0],
210+
value: element[1],
211+
type: 'string',
212+
});
213+
}
214+
}
215+
}
210216
}
211217
}
212218
}

experimental/packages/configuration/test/ConfigFactory.test.ts

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,16 @@ const configFromFile: ConfigurationModel = {
129129
value: [1.1, 2.2],
130130
type: 'double_array',
131131
},
132+
{
133+
name: 'service.namespace',
134+
type: 'string',
135+
value: 'my-namespace',
136+
},
137+
{
138+
name: 'service.version',
139+
type: 'string',
140+
value: '1.0.0',
141+
},
132142
],
133143
},
134144
attribute_limits: {
@@ -836,6 +846,32 @@ describe('ConfigFactory', function () {
836846
assert.deepStrictEqual(configFactory.getConfigModel(), expectedConfig);
837847
});
838848

849+
it('should configure service name via OTEL_SERVICE_NAME env var', function () {
850+
process.env.OTEL_SERVICE_NAME = 'name-from-service-name';
851+
process.env.OTEL_RESOURCE_ATTRIBUTES =
852+
'service.instance.id=my-instance-id';
853+
const expectedConfig: ConfigurationModel = {
854+
...defaultConfig,
855+
resource: {
856+
attributes: [
857+
{
858+
name: 'service.name',
859+
value: 'name-from-service-name',
860+
type: 'string',
861+
},
862+
{
863+
name: 'service.instance.id',
864+
value: 'my-instance-id',
865+
type: 'string',
866+
},
867+
],
868+
attributes_list: 'service.instance.id=my-instance-id',
869+
},
870+
};
871+
const configFactory = createConfigFactory();
872+
assert.deepStrictEqual(configFactory.getConfigModel(), expectedConfig);
873+
});
874+
839875
it('should return config with custom attribute_limits', function () {
840876
process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '100';
841877
process.env.OTEL_ATTRIBUTE_COUNT_LIMIT = '200';
@@ -1892,7 +1928,7 @@ describe('ConfigFactory', function () {
18921928
process.env.OTEL_SDK_DISABLED = 'false';
18931929
process.env.OTEL_LOG_LEVEL = 'debug';
18941930
process.env.OTEL_SERVICE_NAME = 'custom-name';
1895-
process.env.OTEL_RESOURCE_ATTRIBUTES = 'attributes';
1931+
process.env.OTEL_RESOURCE_ATTRIBUTES = 'att=1';
18961932
process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = '23';
18971933
process.env.OTEL_ATTRIBUTE_COUNT_LIMIT = '7';
18981934
process.env.OTEL_PROPAGATORS = 'prop';
@@ -1950,13 +1986,18 @@ describe('ConfigFactory', function () {
19501986
const expectedConfig: ConfigurationModel = {
19511987
...defaultConfigFromFileWithEnvVariables,
19521988
resource: {
1953-
attributes_list: 'attributes',
1989+
attributes_list: 'att=1',
19541990
attributes: [
19551991
{
19561992
name: 'service.name',
19571993
value: 'custom-name',
19581994
type: 'string',
19591995
},
1996+
{
1997+
name: 'att',
1998+
value: '1',
1999+
type: 'string',
2000+
},
19602001
],
19612002
},
19622003
attribute_limits: {
@@ -2101,6 +2142,78 @@ describe('ConfigFactory', function () {
21012142
);
21022143
});
21032144

2145+
it('check resources priority', function () {
2146+
process.env.OTEL_EXPERIMENTAL_CONFIG_FILE =
2147+
'test/fixtures/resources.yaml';
2148+
const configFactory = createConfigFactory();
2149+
const expectedConfig: ConfigurationModel = {
2150+
...defaultConfig,
2151+
resource: {
2152+
schema_url: 'https://opentelemetry.io/schemas/1.16.0',
2153+
attributes_list:
2154+
'service.namespace=config-namespace,service.version=1.0.0',
2155+
attributes: [
2156+
{
2157+
name: 'service.name',
2158+
value: 'config-name',
2159+
type: 'string',
2160+
},
2161+
{
2162+
name: 'service.namespace',
2163+
value: 'priority-config-namespace',
2164+
type: 'string',
2165+
},
2166+
{
2167+
name: 'string_key',
2168+
value: 'value',
2169+
type: 'string',
2170+
},
2171+
{
2172+
name: 'bool_key',
2173+
value: true,
2174+
type: 'bool',
2175+
},
2176+
{
2177+
name: 'int_key',
2178+
value: 1,
2179+
type: 'int',
2180+
},
2181+
{
2182+
name: 'double_key',
2183+
value: 1.1,
2184+
type: 'double',
2185+
},
2186+
{
2187+
name: 'string_array_key',
2188+
value: ['value1', 'value2'],
2189+
type: 'string_array',
2190+
},
2191+
{
2192+
name: 'bool_array_key',
2193+
value: [true, false],
2194+
type: 'bool_array',
2195+
},
2196+
{
2197+
name: 'int_array_key',
2198+
value: [1, 2],
2199+
type: 'int_array',
2200+
},
2201+
{
2202+
name: 'double_array_key',
2203+
value: [1.1, 2.2],
2204+
type: 'double_array',
2205+
},
2206+
{
2207+
name: 'service.version',
2208+
value: '1.0.0',
2209+
type: 'string',
2210+
},
2211+
],
2212+
},
2213+
};
2214+
assert.deepStrictEqual(configFactory.getConfigModel(), expectedConfig);
2215+
});
2216+
21042217
it('checks to keep good code coverage', function () {
21052218
process.env.OTEL_EXPERIMENTAL_CONFIG_FILE =
21062219
'test/fixtures/test-for-coverage.yaml';
@@ -2110,8 +2223,8 @@ describe('ConfigFactory', function () {
21102223
assert.deepStrictEqual(config, { resource: {} });
21112224

21122225
config = {};
2113-
setResourceAttributes(config, []);
2114-
assert.deepStrictEqual(config, { resource: { attributes: [] } });
2226+
setResourceAttributes(config, [], '');
2227+
assert.deepStrictEqual(config, { resource: {} });
21152228

21162229
config = {};
21172230
setFileAttributeLimits(config, { attribute_count_limit: 128 });

0 commit comments

Comments
 (0)