Allow vendor distribution to provide default configuration (#1243)

This commit is contained in:
Mateusz Rzeszutek 2020-09-30 00:02:16 +02:00 committed by GitHub
parent f48579a84f
commit 08f34d00b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 29 deletions

View File

@ -0,0 +1,34 @@
/*
* 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
*
* http://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.
*/
package io.opentelemetry.javaagent.spi.config;
import java.util.Map;
/**
* A service provider that allows to override default OTel agent configuration. Properties returned
* by implementations of this interface will be used after the following methods fail to find a
* non-empty property value: system properties, environment variables, properties configuration
* file.
*/
public interface PropertySource {
/**
* @return all properties whose default values are overridden by this property source. Key of the
* map is the propertyName (same as system property name, e.g. {@code otel.exporter}), value
* is the property value.
*/
Map<String, String> getProperties();
}

View File

@ -78,9 +78,13 @@ public final class ConfigBuilder
return configMap;
}
ConfigBuilder readPropertiesFromAllSources(Properties configurationFile) {
ConfigBuilder readPropertiesFromAllSources(
Properties spiConfiguration, Properties configurationFile) {
// ordering from least to most important
return readProperties(configurationFile).readEnvironmentVariables().readSystemProperties();
return readProperties(spiConfiguration)
.readProperties(configurationFile)
.readEnvironmentVariables()
.readSystemProperties();
}
@Override

View File

@ -17,11 +17,14 @@
package io.opentelemetry.javaagent.tooling.config;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.spi.config.PropertySource;
import io.opentelemetry.javaagent.tooling.AgentInstaller;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -33,7 +36,19 @@ public final class ConfigInitializer {
public static void initialize() {
Config.internalInitializeConfig(
new ConfigBuilder().readPropertiesFromAllSources(loadConfigurationFile()).build());
new ConfigBuilder()
.readPropertiesFromAllSources(loadSpiConfiguration(), loadConfigurationFile())
.build());
}
/** Retrieves all default configuration overloads using SPI and initializes Config. */
private static Properties loadSpiConfiguration() {
Properties propertiesFromSpi = new Properties();
for (PropertySource propertySource :
ServiceLoader.load(PropertySource.class, AgentInstaller.class.getClassLoader())) {
propertiesFromSpi.putAll(propertySource.getProperties());
}
return propertiesFromSpi;
}
/**

View File

@ -31,7 +31,7 @@ class ConfigBuilderTest extends AgentSpecification {
def "should use defaults"() {
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(new Properties())
.readPropertiesFromAllSources(new Properties(), new Properties())
.build()
then:
@ -53,66 +53,105 @@ class ConfigBuilderTest extends AgentSpecification {
config.endpointPeerServiceMapping.isEmpty()
}
def "should use configuration file properties (takes precedence over defaults)"() {
def "should use configuration from SPI (takes precedence over defaults)"() {
given:
def configurationFile = new Properties()
configurationFile.put(ConfigBuilder.EXPORTER, "zipkin")
configurationFile.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
configurationFile.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
def spiConfiguration = new Properties()
spiConfiguration.put(ConfigBuilder.EXPORTER, "zipkin")
spiConfiguration.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
spiConfiguration.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
spiConfiguration.put(ConfigBuilder.TRACE_METHODS, "mypackage.MyClass[myMethod]")
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(configurationFile)
.readPropertiesFromAllSources(spiConfiguration, new Properties())
.build()
then:
config.exporter == "zipkin"
config.hystrixTagsEnabled
config.endpointPeerServiceMapping == ["1.2.3.4": "cats", "dogs.com": "dogs"]
config.traceMethods == "mypackage.MyClass[myMethod]"
}
def "should use environment variables (takes precedence over configuration file)"() {
def "should use configuration file properties (takes precedence over SPI)"() {
given:
def configurationFile = new Properties()
configurationFile.put(ConfigBuilder.EXPORTER, "zipkin")
configurationFile.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
configurationFile.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
def spiConfiguration = new Properties()
spiConfiguration.put(ConfigBuilder.EXPORTER, "zipkin")
spiConfiguration.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
spiConfiguration.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
spiConfiguration.put(ConfigBuilder.TRACE_METHODS, "mypackage.MyClass[myMethod]")
environmentVariables.set("OTEL_EXPORTER", "logging")
environmentVariables.set("OTEL_ENDPOINT_PEER_SERVICE_MAPPING", "4.2.4.2=elephants.com")
def configurationFile = new Properties()
configurationFile.put(ConfigBuilder.EXPORTER, "logging")
configurationFile.put(ConfigBuilder.TRACE_METHODS, "mypackage2.MyClass2[myMethod2]")
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(configurationFile)
.readPropertiesFromAllSources(spiConfiguration, configurationFile)
.build()
then:
config.exporter == "logging"
config.hystrixTagsEnabled
config.endpointPeerServiceMapping == ["4.2.4.2": "elephants.com"]
config.endpointPeerServiceMapping == ["1.2.3.4": "cats", "dogs.com": "dogs"]
config.traceMethods == "mypackage2.MyClass2[myMethod2]"
}
def "should use system properties (takes precedence over environment variables)"() {
def "should use environment variables (takes precedence over configuration file)"() {
given:
def spiConfiguration = new Properties()
spiConfiguration.put(ConfigBuilder.EXPORTER, "zipkin")
spiConfiguration.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
spiConfiguration.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
spiConfiguration.put(ConfigBuilder.TRACE_METHODS, "mypackage.MyClass[myMethod]")
def configurationFile = new Properties()
configurationFile.put(ConfigBuilder.EXPORTER, "zipkin")
configurationFile.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
configurationFile.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
configurationFile.put(ConfigBuilder.EXPORTER, "logging")
configurationFile.put(ConfigBuilder.TRACE_METHODS, "mypackage2.MyClass2[myMethod2]")
environmentVariables.set("OTEL_EXPORTER", "logging")
environmentVariables.set("OTEL_EXPORTER", "jaeger")
environmentVariables.set("OTEL_ENDPOINT_PEER_SERVICE_MAPPING", "4.2.4.2=elephants.com")
System.setProperty(ConfigBuilder.EXPORTER, "jaeger")
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(configurationFile)
.readPropertiesFromAllSources(spiConfiguration, configurationFile)
.build()
then:
config.exporter == "jaeger"
config.hystrixTagsEnabled
config.endpointPeerServiceMapping == ["4.2.4.2": "elephants.com"]
config.traceMethods == "mypackage2.MyClass2[myMethod2]"
}
def "should use system properties (takes precedence over environment variables)"() {
given:
def spiConfiguration = new Properties()
spiConfiguration.put(ConfigBuilder.EXPORTER, "zipkin")
spiConfiguration.put(ConfigBuilder.HYSTRIX_TAGS_ENABLED, "true")
spiConfiguration.put(ConfigBuilder.ENDPOINT_PEER_SERVICE_MAPPING, "1.2.3.4=cats,dogs.com=dogs")
spiConfiguration.put(ConfigBuilder.TRACE_METHODS, "mypackage.MyClass[myMethod]")
def configurationFile = new Properties()
configurationFile.put(ConfigBuilder.EXPORTER, "logging")
configurationFile.put(ConfigBuilder.TRACE_METHODS, "mypackage2.MyClass2[myMethod2]")
environmentVariables.set("OTEL_EXPORTER", "jaeger")
environmentVariables.set("OTEL_ENDPOINT_PEER_SERVICE_MAPPING", "4.2.4.2=elephants.com")
System.setProperty(ConfigBuilder.EXPORTER, "otlp")
System.setProperty(ConfigBuilder.TRACE_METHODS, "mypackage3.MyClass3[myMethod3]")
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(spiConfiguration, configurationFile)
.build()
then:
config.exporter == "otlp"
config.hystrixTagsEnabled
config.endpointPeerServiceMapping == ["4.2.4.2": "elephants.com"]
config.traceMethods == "mypackage3.MyClass3[myMethod3]"
}
def "should use defaults in case of parsing failure"() {
@ -121,7 +160,7 @@ class ConfigBuilderTest extends AgentSpecification {
when:
def config = new ConfigBuilder()
.readPropertiesFromAllSources(new Properties())
.readPropertiesFromAllSources(new Properties(), new Properties())
.build()
then:
@ -139,7 +178,7 @@ class ConfigBuilderTest extends AgentSpecification {
System.setProperty("otel.integration.disabled-prop.enabled", "false")
def config = new ConfigBuilder()
.readPropertiesFromAllSources(new Properties())
.readPropertiesFromAllSources(new Properties(), new Properties())
.build()
expect: