From b7bf3e7f68583fe33c15add8bcacde473d156e61 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 26 Jul 2019 11:09:23 +0200 Subject: [PATCH 1/5] Add config_file_location option closes #701 --- CHANGELOG.md | 1 + .../configuration/CoreConfiguration.java | 38 +++++++++++ .../agent/impl/ElasticApmTracerBuilder.java | 11 ++-- .../agent/logging/LoggingConfiguration.java | 2 +- .../impl/ElasticApmTracerBuilderTest.java | 63 +++++++++++++++++++ docs/configuration.asciidoc | 34 ++++++++++ pom.xml | 2 +- 7 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d04634b7e9..4dfc73061d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Add support for Spring's JMS flavor - instrumenting `org.springframework.jms.listener.SessionAwareMessageListener` * Add support to legacy ApacheHttpClient APIs (which adds support to Axis2 configured to use ApacheHttpClient) * Added support for setting `server_urls` dynamically via properties file [#723](https://github.com/elastic/apm-agent-java/issues/723) + * Add [`config_file_location`](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-config-file-location) option ## Bug Fixes * Some JMS Consumers and Producers are filtered due to class name filtering in instrumentation matching diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 4677d7d008..5d3c90e6e9 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -24,6 +24,7 @@ */ package co.elastic.apm.agent.configuration; +import co.elastic.apm.agent.bci.ElasticApmAgent; import co.elastic.apm.agent.bci.methodmatching.MethodMatcher; import co.elastic.apm.agent.bci.methodmatching.configuration.MethodMatcherValueConverter; import co.elastic.apm.agent.configuration.converter.TimeDuration; @@ -36,6 +37,7 @@ import org.stagemonitor.configuration.converter.ListValueConverter; import org.stagemonitor.configuration.converter.MapValueConverter; import org.stagemonitor.configuration.converter.StringValueConverter; +import org.stagemonitor.configuration.source.ConfigurationSource; import javax.annotation.Nullable; import java.util.Arrays; @@ -45,6 +47,7 @@ import java.util.Map; import static co.elastic.apm.agent.configuration.validation.RangeValidator.isInRange; +import static co.elastic.apm.agent.logging.LoggingConfiguration.AGENT_HOME_PLACEHOLDER; public class CoreConfiguration extends ConfigurationOptionProvider { @@ -53,6 +56,8 @@ public class CoreConfiguration extends ConfigurationOptionProvider { public static final String SERVICE_NAME = "service_name"; public static final String SAMPLE_RATE = "transaction_sample_rate"; private static final String CORE_CATEGORY = "Core"; + public static final String DEFAULT_CONFIG_FILE_LOCATION = "_AGENT_HOME_/elasticapm.properties"; + public static final String CONFIG_FILE_LOCATION = "config_file_location"; private final ConfigurationOption active = ConfigurationOption.booleanOption() .key(ACTIVE) .configurationCategory(CORE_CATEGORY) @@ -360,6 +365,14 @@ public class CoreConfiguration extends ConfigurationOptionProvider { .description("Disables the collection of breakdown metrics (`span.self_time`)") .buildWithDefault(true); + private final ConfigurationOption configFileLocation = ConfigurationOption.stringOption() + .key(CONFIG_FILE_LOCATION) + .configurationCategory(CORE_CATEGORY) + .description("Sets the path of the agent config file.\n" + + "The special value `_AGENT_HOME_` is a placeholder for the folder the elastic-apm-agent.jar is in.\n" + + "The location can either be in the classpath of the application or on the file system.") + .buildWithDefault(DEFAULT_CONFIG_FILE_LOCATION); + public boolean isActive() { return active.get(); } @@ -450,4 +463,29 @@ public Map getGlobalLabels() { public boolean isBreakdownMetricsEnabled() { return breakdownMetrics.get(); } + + /* + * Makes sure to not initialize ConfigurationOption, which would initialize the logger + */ + @Nullable + public static String getConfigFileLocation(List configurationSources) { + String configFileLocation = DEFAULT_CONFIG_FILE_LOCATION; + for (ConfigurationSource configurationSource : configurationSources) { + String valueFromSource = configurationSource.getValue(CONFIG_FILE_LOCATION); + if (valueFromSource != null) { + configFileLocation = valueFromSource; + break; + } + } + if (configFileLocation.contains(AGENT_HOME_PLACEHOLDER)) { + String agentHome = ElasticApmAgent.getAgentHome(); + if (agentHome != null) { + return configFileLocation.replace(AGENT_HOME_PLACEHOLDER, agentHome); + } else { + return null; + } + } else { + return configFileLocation; + } + } } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilder.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilder.java index 6871839c0f..2081274460 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilder.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilder.java @@ -24,7 +24,6 @@ */ package co.elastic.apm.agent.impl; -import co.elastic.apm.agent.bci.ElasticApmAgent; import co.elastic.apm.agent.configuration.AgentArgumentsConfigurationSource; import co.elastic.apm.agent.configuration.ApmServerConfigurationSource; import co.elastic.apm.agent.configuration.CoreConfiguration; @@ -35,7 +34,6 @@ import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration; import co.elastic.apm.agent.logging.LoggingConfiguration; import co.elastic.apm.agent.report.ApmServerClient; -import co.elastic.apm.agent.report.ApmServerHealthChecker; import co.elastic.apm.agent.report.Reporter; import co.elastic.apm.agent.report.ReporterConfiguration; import co.elastic.apm.agent.report.ReporterFactory; @@ -149,6 +147,9 @@ private ConfigurationRegistry getDefaultConfigurationRegistry(List getConfigSources(@Nullable String agentArguments) { List result = new ArrayList<>(); if (agentArguments != null && !agentArguments.isEmpty()) { @@ -167,9 +168,9 @@ public String getName() { return "Inline configuration"; } }); - String agentHome = ElasticApmAgent.getAgentHome(); - if (agentHome != null && PropertyFileConfigurationSource.isPresent(agentHome + "/elasticapm.properties")) { - result.add(new PropertyFileConfigurationSource(agentHome + "/elasticapm.properties")); + String configFileLocation = CoreConfiguration.getConfigFileLocation(result); + if (configFileLocation != null && PropertyFileConfigurationSource.isPresent(configFileLocation)) { + result.add(new PropertyFileConfigurationSource(configFileLocation)); } // looks if we can find a elasticapm.properties on the classpath // mainly useful for unit tests diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/logging/LoggingConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/logging/LoggingConfiguration.java index f0ae02c2fa..1bbd5935c1 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/logging/LoggingConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/logging/LoggingConfiguration.java @@ -59,7 +59,7 @@ public class LoggingConfiguration extends ConfigurationOptionProvider { private static final String DEFAULT_LOG_FILE = SYSTEM_OUT; private static final String LOGGING_CATEGORY = "Logging"; - private static final String AGENT_HOME_PLACEHOLDER = "_AGENT_HOME_"; + public static final String AGENT_HOME_PLACEHOLDER = "_AGENT_HOME_"; private static final String DEPRECATED_LOG_LEVEL_KEY = "logging.log_level"; private static final String DEPRECATED_LOG_FILE_KEY = "logging.log_file"; diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java new file mode 100644 index 0000000000..7323a977cf --- /dev/null +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java @@ -0,0 +1,63 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + * #L% + */ +package co.elastic.apm.agent.impl; + +import co.elastic.apm.agent.configuration.CoreConfiguration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.stagemonitor.configuration.ConfigurationRegistry; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ElasticApmTracerBuilderTest { + + private static final String CONFIG_FILE_LOCATION_PROPERTY = "elastic.apm.config_file_location"; + + @AfterEach + void tearDown() { + System.clearProperty(CONFIG_FILE_LOCATION_PROPERTY); + } + + @Test + void testConfigFileLocation(@TempDir Path tempDir) throws IOException { + Path file = Files.createFile(tempDir.resolve("elastic-apm-test.properties")); + Files.write(file, List.of("instrument=false")); + System.setProperty(CONFIG_FILE_LOCATION_PROPERTY, file.toString()); + + ConfigurationRegistry configurationRegistry = new ElasticApmTracerBuilder().build().getConfigurationRegistry(); + CoreConfiguration config = configurationRegistry.getConfig(CoreConfiguration.class); + + // tests that changing non-dynamic properties also works + assertThat(config.isInstrument()).isFalse(); + configurationRegistry.getString("config_file_location"); + assertThat(configurationRegistry.getString("config_file_location")).isEqualTo(file.toString()); + } +} diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 33c120fcf9..cebae755c6 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -18,6 +18,7 @@ The first configuration sources override the configuration values of over the la . `elasticapm.properties` file + You can place a `elasticapm.properties` in the same directory the agent jar resides in. No prefix is required for the configuration keys. + To customize the location of the properties file, set the <> option. Configuration options marked with Dynamic true can be changed at runtime via configuration sources which support dynamic reloading. The `elasticapm.properties` file is @@ -74,6 +75,7 @@ Click on a key to get more information. ** <> ** <> ** <> +** <> * <> ** <> ** <> @@ -535,6 +537,28 @@ Disables the collection of breakdown metrics (`span.self_time`) | `elastic.apm.breakdown_metrics` | `breakdown_metrics` | `ELASTIC_APM_BREAKDOWN_METRICS` |============ +[float] +[[config-config-file-location]] +==== `config_file_location` + +Sets the path of the agent config file. +The special value `_AGENT_HOME_` is a placeholder for the folder the elastic-apm-agent.jar is in. +The location can either be in the classpath of the application or on the file system. + + +[options="header"] +|============ +| Default | Type | Dynamic +| `_AGENT_HOME_/elasticapm.properties` | String | false +|============ + + +[options="header"] +|============ +| Java System Properties | Property file | Environment +| `elastic.apm.config_file_location` | `config_file_location` | `ELASTIC_APM_CONFIG_FILE_LOCATION` +|============ + [[config-http]] === HTTP configuration options [float] @@ -1446,6 +1470,16 @@ The default unit for this option is `ms` # # breakdown_metrics=true +# Sets the path of the agent config file. +# The special value `_AGENT_HOME_` is a placeholder for the folder the elastic-apm-agent.jar is in. +# The location can either be in the classpath of the application or on the file system. +# +# This setting can not be changed at runtime. Changes require a restart of the application. +# Type: String +# Default value: _AGENT_HOME_/elasticapm.properties +# +# config_file_location=_AGENT_HOME_/elasticapm.properties + ############################################ # HTTP # ############################################ diff --git a/pom.xml b/pom.xml index 591ec8905e..e09aeefdce 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 2.2.0 1.4.196 2.9.9 - 5.3.2 + 5.5.1 4.12 1.2.3 3.9.1 From 079131f89af3068e10a1ceada0218d678c436bbc Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 26 Jul 2019 12:55:12 +0200 Subject: [PATCH 2/5] Add generated config docs --- docs/configuration.asciidoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index cebae755c6..e58e8b3e37 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -18,7 +18,6 @@ The first configuration sources override the configuration values of over the la . `elasticapm.properties` file + You can place a `elasticapm.properties` in the same directory the agent jar resides in. No prefix is required for the configuration keys. - To customize the location of the properties file, set the <> option. Configuration options marked with Dynamic true can be changed at runtime via configuration sources which support dynamic reloading. The `elasticapm.properties` file is From 36f2e4e7870aee97e9d6d93ce3aa7e4f6f330794 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 26 Jul 2019 13:54:39 +0200 Subject: [PATCH 3/5] Rename option to config_file to conform to the Node.js agent --- .../apm/agent/configuration/CoreConfiguration.java | 12 ++++++------ .../apm/agent/impl/ElasticApmTracerBuilderTest.java | 9 ++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 5d3c90e6e9..0cd59e1101 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -56,8 +56,8 @@ public class CoreConfiguration extends ConfigurationOptionProvider { public static final String SERVICE_NAME = "service_name"; public static final String SAMPLE_RATE = "transaction_sample_rate"; private static final String CORE_CATEGORY = "Core"; - public static final String DEFAULT_CONFIG_FILE_LOCATION = "_AGENT_HOME_/elasticapm.properties"; - public static final String CONFIG_FILE_LOCATION = "config_file_location"; + public static final String DEFAULT_CONFIG_FILE = "_AGENT_HOME_/elasticapm.properties"; + public static final String CONFIG_FILE = "config_file"; private final ConfigurationOption active = ConfigurationOption.booleanOption() .key(ACTIVE) .configurationCategory(CORE_CATEGORY) @@ -366,12 +366,12 @@ public class CoreConfiguration extends ConfigurationOptionProvider { .buildWithDefault(true); private final ConfigurationOption configFileLocation = ConfigurationOption.stringOption() - .key(CONFIG_FILE_LOCATION) + .key(CONFIG_FILE) .configurationCategory(CORE_CATEGORY) .description("Sets the path of the agent config file.\n" + "The special value `_AGENT_HOME_` is a placeholder for the folder the elastic-apm-agent.jar is in.\n" + "The location can either be in the classpath of the application or on the file system.") - .buildWithDefault(DEFAULT_CONFIG_FILE_LOCATION); + .buildWithDefault(DEFAULT_CONFIG_FILE); public boolean isActive() { return active.get(); @@ -469,9 +469,9 @@ public boolean isBreakdownMetricsEnabled() { */ @Nullable public static String getConfigFileLocation(List configurationSources) { - String configFileLocation = DEFAULT_CONFIG_FILE_LOCATION; + String configFileLocation = DEFAULT_CONFIG_FILE; for (ConfigurationSource configurationSource : configurationSources) { - String valueFromSource = configurationSource.getValue(CONFIG_FILE_LOCATION); + String valueFromSource = configurationSource.getValue(CONFIG_FILE); if (valueFromSource != null) { configFileLocation = valueFromSource; break; diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java index 7323a977cf..9cd8211cf2 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerBuilderTest.java @@ -39,25 +39,24 @@ class ElasticApmTracerBuilderTest { - private static final String CONFIG_FILE_LOCATION_PROPERTY = "elastic.apm.config_file_location"; @AfterEach void tearDown() { - System.clearProperty(CONFIG_FILE_LOCATION_PROPERTY); + System.clearProperty("elastic.apm." + CoreConfiguration.CONFIG_FILE); } @Test void testConfigFileLocation(@TempDir Path tempDir) throws IOException { Path file = Files.createFile(tempDir.resolve("elastic-apm-test.properties")); Files.write(file, List.of("instrument=false")); - System.setProperty(CONFIG_FILE_LOCATION_PROPERTY, file.toString()); + System.setProperty("elastic.apm." + CoreConfiguration.CONFIG_FILE, file.toString()); ConfigurationRegistry configurationRegistry = new ElasticApmTracerBuilder().build().getConfigurationRegistry(); CoreConfiguration config = configurationRegistry.getConfig(CoreConfiguration.class); // tests that changing non-dynamic properties also works assertThat(config.isInstrument()).isFalse(); - configurationRegistry.getString("config_file_location"); - assertThat(configurationRegistry.getString("config_file_location")).isEqualTo(file.toString()); + configurationRegistry.getString(CoreConfiguration.CONFIG_FILE); + assertThat(configurationRegistry.getString(CoreConfiguration.CONFIG_FILE)).isEqualTo(file.toString()); } } From 2e495ff83993d7cb917814e62da36f022135f600 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 26 Jul 2019 13:55:32 +0200 Subject: [PATCH 4/5] Apply suggestions from code review --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfc73061d..9737217043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Add support for Spring's JMS flavor - instrumenting `org.springframework.jms.listener.SessionAwareMessageListener` * Add support to legacy ApacheHttpClient APIs (which adds support to Axis2 configured to use ApacheHttpClient) * Added support for setting `server_urls` dynamically via properties file [#723](https://github.com/elastic/apm-agent-java/issues/723) - * Add [`config_file_location`](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-config-file-location) option + * Add [`config_file`](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-config-file) option ## Bug Fixes * Some JMS Consumers and Producers are filtered due to class name filtering in instrumentation matching From 56901d4998ae5f129a182604ee4b735ced46944f Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 29 Jul 2019 14:06:45 +0200 Subject: [PATCH 5/5] Use AGENT_HOME_PLACEHOLDER constant in DEFAULT_CONFIG_FILE Co-Authored-By: eyalkoren <41850454+eyalkoren@users.noreply.github.com> --- .../co/elastic/apm/agent/configuration/CoreConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 0cd59e1101..9ee301d357 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -56,7 +56,7 @@ public class CoreConfiguration extends ConfigurationOptionProvider { public static final String SERVICE_NAME = "service_name"; public static final String SAMPLE_RATE = "transaction_sample_rate"; private static final String CORE_CATEGORY = "Core"; - public static final String DEFAULT_CONFIG_FILE = "_AGENT_HOME_/elasticapm.properties"; + public static final String DEFAULT_CONFIG_FILE = AGENT_HOME_PLACEHOLDER + "/elasticapm.properties"; public static final String CONFIG_FILE = "config_file"; private final ConfigurationOption active = ConfigurationOption.booleanOption() .key(ACTIVE)