Skip to content

Use Implementation-Version as default service version if it is available #1922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d28f376
Use Implementation-Version as default service version if it is available
tobiasstadler Jul 16, 2021
4ac6672
Added #1922 to the changelog
tobiasstadler Jul 16, 2021
577277c
Merge branch 'master' into implementation-version
tobiasstadler Jul 23, 2021
0cf4b0a
Merge branch 'master' into implementation-version
tobiasstadler Aug 4, 2021
826abc5
Merge branch 'master' into implementation-version
tobiasstadler Aug 23, 2021
b94aa9c
Merge branch 'master' into implementation-version
tobiasstadler Aug 25, 2021
34f39b3
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Sep 20, 2021
8c8e750
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Sep 21, 2021
7cfadb9
Merge branch 'master' into implementation-version
tobiasstadler Oct 1, 2021
48385eb
Merge branch 'master' into implementation-version
tobiasstadler Oct 6, 2021
5d2e2c8
Merge branch 'master' into implementation-version
tobiasstadler Oct 13, 2021
e559b72
Merge branch 'master' into implementation-version
tobiasstadler Oct 27, 2021
5567635
Merge branch 'master' into implementation-version
tobiasstadler Nov 2, 2021
4491976
Merge branch 'master' into implementation-version
tobiasstadler Nov 8, 2021
db8429f
Merge branch 'master' into implementation-version
tobiasstadler Nov 9, 2021
f6ac490
Merge branch 'master' into implementation-version
tobiasstadler Nov 10, 2021
8a7f097
Merge branch 'master' into implementation-version
tobiasstadler Nov 11, 2021
7bab0b5
Merge branch 'master' into implementation-version
tobiasstadler Nov 12, 2021
a56497a
Merge branch 'master' into implementation-version
tobiasstadler Nov 14, 2021
49ef474
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Nov 15, 2021
18cc633
Merge branch 'master' into implementation-version
tobiasstadler Nov 17, 2021
7b4c7c4
Merge branch 'master' into implementation-version
tobiasstadler Nov 24, 2021
e462aa4
Fixed merge
tobiasstadler Nov 24, 2021
5cf806c
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Nov 30, 2021
4ee3678
Merge branch 'master' into implementation-version
tobiasstadler Dec 1, 2021
35ab3d5
Merge branch 'master' into implementation-version
tobiasstadler Dec 2, 2021
de857a2
Updated configuration.asciidoc
tobiasstadler Dec 2, 2021
782020c
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Dec 7, 2021
3c3857e
Merge branch 'master' into implementation-version
tobiasstadler Dec 9, 2021
365d422
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Dec 10, 2021
b47dfde
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Dec 16, 2021
ecfd0c9
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Dec 22, 2021
d951a3e
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Dec 31, 2021
99c869f
Merge branch 'master' into implementation-version
tobiasstadler Jan 14, 2022
4e2c726
Merge branch 'master' into implementation-version
tobiasstadler Jan 14, 2022
73e2af4
Merge branch 'master' into implementation-version
tobiasstadler Jan 17, 2022
72120a8
Merge branch 'master' into implementation-version
tobiasstadler Jan 18, 2022
797d8df
Merge remote-tracking branch 'upstream/master' into implementation-ve…
tobiasstadler Jan 20, 2022
1b9f4b1
Merge branch 'main' into implementation-version
tobiasstadler Jan 26, 2022
c25ffbd
Merged ServiceNameUtil and ServiceVersionUtil as suggested by @feliyb…
tobiasstadler Jan 26, 2022
8ac3a70
Polishing
felixbarny Jan 26, 2022
141e256
Fixed test
tobiasstadler Jan 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ endif::[]
* Adding agent logging capabilities to our SDK, making it available for external plugins - {pull}2390[#2390]
* When the `MANIFEST.MF` of the main jar contains the `Implementation-Title` attribute, it is used as the default service name - {pull}1921[#1921]
Note: this may change your service names if you relied on the auto-discovery that uses the name of the jar file. If that jar file also contains an `Implementation-Title` attribute in the `MANIFEST.MF` file, the latter will take precedence.
* When the MANIFEST.MF of the main jar contains the Implementation-Version attribute, it is used as the default service version (except for application servers) - {pull}1922[#1922]

[float]
===== Bug fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public class CoreConfiguration extends ConfigurationOptionProvider {
"NOTE: Service name auto discovery mechanisms require APM Server 7.0+.")
.addValidator(RegexValidator.of("^[a-zA-Z0-9 _-]+$", "Your service name \"{0}\" must only contain characters " +
"from the ASCII alphabet, numbers, dashes, underscores and spaces"))
.buildWithDefault(ServiceNameUtil.getDefaultServiceName());
.buildWithDefault(ServiceInfo.autoDetected().getServiceName());

private final ConfigurationOption<String> serviceNodeName = ConfigurationOption.stringOption()
.key(SERVICE_NODE_NAME)
Expand Down Expand Up @@ -145,6 +145,7 @@ public class CoreConfiguration extends ConfigurationOptionProvider {
.description("A version string for the currently deployed version of the service. If you don’t version your deployments, " +
"the recommended value for this field is the commit identifier of the deployed revision, " +
"e.g. the output of git rev-parse HEAD.")
.defaultValue(ServiceInfo.autoDetected().getServiceVersion())
.build();

private final ConfigurationOption<String> hostname = ConfigurationOption.stringOption()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,79 @@
*/
package co.elastic.apm.agent.configuration;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

public class ServiceNameUtil {
public class ServiceInfo {

private static final String JAR_VERSION_SUFFIX = "-(\\d+\\.)+(\\d+)(.*)?$";
private static final String DEFAULT_SERVICE_NAME = "unknown-java-service";
private static final ServiceInfo AUTO_DETECTED = autoDetect(System.getProperties());

public static String getDefaultServiceName() {
String lambdaFunctionName = System.getenv("AWS_LAMBDA_FUNCTION_NAME");
if (null != lambdaFunctionName) {
return lambdaFunctionName;
private final String serviceName;
@Nullable
private final String serviceVersion;

public ServiceInfo(@Nullable String serviceName) {
this(serviceName, null);
}

public ServiceInfo(@Nullable String serviceName, @Nullable String serviceVersion) {
if (serviceName == null || serviceName.trim().isEmpty()) {
this.serviceName = DEFAULT_SERVICE_NAME;
} else {
return getDefaultServiceName(System.getProperty("sun.java.command"));
this.serviceName = replaceDisallowedServiceNameChars(serviceName).trim();
}
this.serviceVersion = serviceVersion;
}

static String getDefaultServiceName(@Nullable String sunJavaCommand) {
String serviceName = parseSunJavaCommand(sunJavaCommand);
if (serviceName != null) {
serviceName = replaceDisallowedChars(serviceName);
serviceName = serviceName.trim();
}
if (serviceName == null || serviceName.isEmpty()) {
serviceName = "unknown-java-service";
}
public String getServiceName() {
return serviceName;
}

@Nullable
private static String parseSunJavaCommand(@Nullable String command) {
public String getServiceVersion() {
return serviceVersion;
}

public static String replaceDisallowedServiceNameChars(String serviceName) {
return serviceName.replaceAll("[^a-zA-Z0-9 _-]", "-");
}

public static ServiceInfo autoDetected() {
return AUTO_DETECTED;
}

public static ServiceInfo autoDetect(Properties properties) {
String lambdaFunctionName = System.getenv("AWS_LAMBDA_FUNCTION_NAME");
if (lambdaFunctionName != null) {
return new ServiceInfo(lambdaFunctionName, null);
} else {
ServiceInfo serviceInfo = createFromSunJavaCommand(properties.getProperty("sun.java.command"));
if (serviceInfo != null) {
return serviceInfo;
}
return new ServiceInfo(null);
}
}

@Nullable
private static ServiceInfo createFromSunJavaCommand(@Nullable String command) {
if (command == null) {
return null;
}
command = command.trim();
String serviceName = getContainerServiceName(command);
if (serviceName != null) {
return serviceName;
return new ServiceInfo(serviceName);
}
if (command.contains(".jar")) {
serviceName = parseJarCommand(command);
return parseJarCommand(command);
} else {
serviceName = parseMainClass(command);
return parseMainClass(command);
}
return serviceName;
}

@Nullable
Expand All @@ -83,31 +111,28 @@ private static String getContainerServiceName(String command) {
return null;
}

public static String replaceDisallowedChars(String serviceName) {
return serviceName.replaceAll("[^a-zA-Z0-9 _-]", "-");
}

@Nullable
private static String parseJarCommand(String command) {
private static ServiceInfo parseJarCommand(String command) {
final String[] commandParts = command.split(" ");
String result = null;
String serviceName = null;
String serviceVersion = null;
for (String commandPart : commandParts) {
if (commandPart.endsWith(".jar")) {
try (JarFile jarFile = new JarFile(commandPart)) {
result = jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_TITLE);
Attributes mainAttributes = jarFile.getManifest().getMainAttributes();
serviceName = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
serviceVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
} catch (Exception ignored) {
}

if (result == null || result.isEmpty()) {
result = removeVersionFromJar(removePath(removeJarExtension(commandPart)));
if (serviceName == null || serviceName.isEmpty()) {
serviceName = removeVersionFromJar(removePath(removeJarExtension(commandPart)));
}
break;
}
}
return result;
return new ServiceInfo(serviceName, serviceVersion);
}

@Nonnull
private static String removeJarExtension(String commandPart) {
return commandPart.substring(0, commandPart.indexOf(".jar"));
}
Expand All @@ -120,14 +145,14 @@ private static String removeVersionFromJar(String jarFileName) {
return jarFileName.replaceFirst(JAR_VERSION_SUFFIX, "");
}

private static String parseMainClass(String command) {
private static ServiceInfo parseMainClass(String command) {
final String mainClassName;
int indexOfSpace = command.indexOf(' ');
if (indexOfSpace != -1) {
mainClassName = command.substring(0, indexOfSpace);
} else {
mainClassName = command;
}
return mainClassName.substring(mainClassName.lastIndexOf('.') + 1);
return new ServiceInfo(mainClassName.substring(mainClassName.lastIndexOf('.') + 1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import co.elastic.apm.agent.common.JvmRuntimeInfo;
import co.elastic.apm.agent.configuration.CoreConfiguration;
import co.elastic.apm.agent.configuration.ServiceNameUtil;
import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.context.ClosableLifecycleListenerAdapter;
import co.elastic.apm.agent.context.LifecycleListener;
import co.elastic.apm.agent.impl.error.ErrorCapture;
Expand Down Expand Up @@ -753,7 +753,7 @@ public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader,
return;
}

String sanitizedServiceName = ServiceNameUtil.replaceDisallowedChars(serviceName);
String sanitizedServiceName = ServiceInfo.replaceDisallowedServiceNameChars(serviceName);
logger.debug("Using `{}` as the service name for class loader [{}]", sanitizedServiceName, classLoader);
if (!serviceNameByClassLoader.containsKey(classLoader)) {
serviceNameByClassLoader.putIfAbsent(classLoader, sanitizedServiceName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import co.elastic.apm.agent.bci.ElasticApmAgent;
import co.elastic.apm.agent.configuration.CoreConfiguration;
import co.elastic.apm.agent.configuration.ServiceNameUtil;
import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.configuration.converter.ByteValue;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LoggerContext;
Expand Down Expand Up @@ -176,7 +176,7 @@ private LayoutComponentBuilder createLayout(ConfigurationBuilder<BuiltConfigurat
.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%thread] %-5level %logger{36} - %msg{nolookups}%n");
} else {
String serviceName = getValue(CoreConfiguration.SERVICE_NAME, sources, ServiceNameUtil.getDefaultServiceName());
String serviceName = getValue(CoreConfiguration.SERVICE_NAME, sources, ServiceInfo.autoDetected().getServiceName());
return builder.newLayout("EcsLayout")
.addAttribute("eventDataset", serviceName + ".apm");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,20 @@

import org.junit.jupiter.api.Test;

import static co.elastic.apm.agent.configuration.ServiceNameUtil.getDefaultServiceName;
import java.util.Properties;

import static org.assertj.core.api.SoftAssertions.assertSoftly;

class ServiceNameUtilTest {
class ServiceInfoTest {

private static String getDefaultServiceName(String sunJavaCommand) {
Properties properties = new Properties();
if (sunJavaCommand != null) {
properties.setProperty("sun.java.command", sunJavaCommand);
}

return ServiceInfo.autoDetect(properties).getServiceName();
}

@Test
void serviceNameShouldBeNormalizedOrDefaults() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import co.elastic.apm.agent.MockReporter;
import co.elastic.apm.agent.configuration.CoreConfiguration;
import co.elastic.apm.agent.configuration.ServiceNameUtil;
import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.configuration.SpyConfiguration;
import co.elastic.apm.agent.configuration.source.ConfigSources;
import co.elastic.apm.agent.impl.error.ErrorCapture;
Expand Down Expand Up @@ -471,7 +471,7 @@ void testNotOverrideServiceNameWhenDefaultServiceNameConfigured() {
startTestRootTransaction().end();

CoreConfiguration coreConfig = localConfig.getConfig(CoreConfiguration.class);
assertThat(ServiceNameUtil.getDefaultServiceName()).isEqualTo(coreConfig.getServiceName());
assertThat(ServiceInfo.autoDetect(System.getProperties()).getServiceName()).isEqualTo(coreConfig.getServiceName());
assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isNull();
if (command != null) {
System.setProperty("sun.java.command", command);
Expand Down