Merge tag 'v0.48.0' into dd-merge
This commit is contained in:
commit
d24159c8d2
|
@ -19,18 +19,18 @@ import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ToString(includeFieldNames = true)
|
@ToString(includeFieldNames = true)
|
||||||
public class Config {
|
public class Config {
|
||||||
|
|
||||||
/** Config keys below */
|
/** Config keys below */
|
||||||
private static final String PREFIX = "ota.";
|
private static final String PREFIX = "ota.";
|
||||||
|
|
||||||
|
@ -250,13 +251,14 @@ public class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated This method should only be used internally. Use the instance getter instead {@link
|
|
||||||
* #isIntegrationEnabled(SortedSet, boolean)}.
|
|
||||||
* @param integrationNames
|
* @param integrationNames
|
||||||
* @param defaultEnabled
|
* @param defaultEnabled
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated This method should only be used internally. Use the instance getter instead {@link
|
||||||
|
* #isIntegrationEnabled(SortedSet, boolean)}.
|
||||||
*/
|
*/
|
||||||
public static boolean integrationEnabled(
|
@Deprecated
|
||||||
|
private static boolean integrationEnabled(
|
||||||
final SortedSet<String> integrationNames, final boolean defaultEnabled) {
|
final SortedSet<String> integrationNames, final boolean defaultEnabled) {
|
||||||
// If default is enabled, we want to enable individually,
|
// If default is enabled, we want to enable individually,
|
||||||
// if default is disabled, we want to disable individually.
|
// if default is disabled, we want to disable individually.
|
||||||
|
@ -286,9 +288,10 @@ public class Config {
|
||||||
*/
|
*/
|
||||||
public static String getSettingFromEnvironment(final String name, final String defaultValue) {
|
public static String getSettingFromEnvironment(final String name, final String defaultValue) {
|
||||||
String value;
|
String value;
|
||||||
|
final String systemPropertyName = propertyNameToSystemPropertyName(name);
|
||||||
|
|
||||||
// System properties and properties provided from command line have the highest precedence
|
// System properties and properties provided from command line have the highest precedence
|
||||||
value = System.getProperties().getProperty(propertyNameToSystemPropertyName(name));
|
value = System.getProperties().getProperty(systemPropertyName);
|
||||||
if (null != value) {
|
if (null != value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +303,7 @@ public class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If value is not defined yet, we look at properties optionally defined in a properties file
|
// If value is not defined yet, we look at properties optionally defined in a properties file
|
||||||
value = propertiesFromConfigFile.getProperty(propertyNameToSystemPropertyName(name));
|
value = propertiesFromConfigFile.getProperty(systemPropertyName);
|
||||||
if (null != value) {
|
if (null != value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +317,8 @@ public class Config {
|
||||||
*
|
*
|
||||||
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
||||||
*/
|
*/
|
||||||
public static List<String> getListSettingFromEnvironment(
|
@NonNull
|
||||||
|
private static List<String> getListSettingFromEnvironment(
|
||||||
final String name, final String defaultValue) {
|
final String name, final String defaultValue) {
|
||||||
return parseList(getSettingFromEnvironment(name, defaultValue));
|
return parseList(getSettingFromEnvironment(name, defaultValue));
|
||||||
}
|
}
|
||||||
|
@ -326,8 +330,7 @@ public class Config {
|
||||||
*/
|
*/
|
||||||
public static Boolean getBooleanSettingFromEnvironment(
|
public static Boolean getBooleanSettingFromEnvironment(
|
||||||
final String name, final Boolean defaultValue) {
|
final String name, final Boolean defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
return getSettingFromEnvironmentWithLog(name, Boolean.class, defaultValue);
|
||||||
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -336,13 +339,7 @@ public class Config {
|
||||||
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
||||||
*/
|
*/
|
||||||
public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) {
|
public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
return getSettingFromEnvironmentWithLog(name, Float.class, defaultValue);
|
||||||
try {
|
|
||||||
return value == null ? defaultValue : Float.valueOf(value);
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
log.warn("Invalid configuration for " + name, e);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -350,41 +347,20 @@ public class Config {
|
||||||
*/
|
*/
|
||||||
private static Integer getIntegerSettingFromEnvironment(
|
private static Integer getIntegerSettingFromEnvironment(
|
||||||
final String name, final Integer defaultValue) {
|
final String name, final Integer defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
return getSettingFromEnvironmentWithLog(name, Integer.class, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T getSettingFromEnvironmentWithLog(
|
||||||
|
final String name, final Class<T> tClass, final T defaultValue) {
|
||||||
try {
|
try {
|
||||||
return value == null ? defaultValue : Integer.valueOf(value);
|
return valueOf(getSettingFromEnvironment(name, null), tClass, defaultValue);
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
log.warn("Invalid configuration for " + name, e);
|
log.warn("Invalid configuration for " + name, e);
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static Set<Integer> getIntegerRangeSettingFromEnvironment(
|
||||||
* Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a set of
|
|
||||||
* strings splitting by space or comma.
|
|
||||||
*/
|
|
||||||
private static <T extends Enum<T>> Set<T> getEnumSetSettingFromEnvironment(
|
|
||||||
final String name,
|
|
||||||
final String defaultValue,
|
|
||||||
final Class<T> clazz,
|
|
||||||
final boolean emptyResultMeansUseDefault) {
|
|
||||||
final String value = getSettingFromEnvironment(name, defaultValue);
|
|
||||||
Set<T> result =
|
|
||||||
convertStringSetToEnumSet(
|
|
||||||
parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz);
|
|
||||||
|
|
||||||
if (emptyResultMeansUseDefault && result.isEmpty()) {
|
|
||||||
// Treat empty parsing result as no value and use default instead
|
|
||||||
result =
|
|
||||||
convertStringSetToEnumSet(
|
|
||||||
parseStringIntoSetOfNonEmptyStrings(defaultValue, SPLIT_BY_SPACE_OR_COMMA_REGEX),
|
|
||||||
clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Integer> getIntegerRangeSettingFromEnvironment(
|
|
||||||
final String name, final Set<Integer> defaultValue) {
|
final String name, final Set<Integer> defaultValue) {
|
||||||
final String value = getSettingFromEnvironment(name, null);
|
final String value = getSettingFromEnvironment(name, null);
|
||||||
try {
|
try {
|
||||||
|
@ -402,6 +378,7 @@ public class Config {
|
||||||
* @param setting The setting name, e.g. `trace.enabled`
|
* @param setting The setting name, e.g. `trace.enabled`
|
||||||
* @return The public facing environment variable name
|
* @return The public facing environment variable name
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
private static String propertyNameToEnvironmentVariableName(final String setting) {
|
private static String propertyNameToEnvironmentVariableName(final String setting) {
|
||||||
return ENV_REPLACEMENT
|
return ENV_REPLACEMENT
|
||||||
.matcher(propertyNameToSystemPropertyName(setting).toUpperCase())
|
.matcher(propertyNameToSystemPropertyName(setting).toUpperCase())
|
||||||
|
@ -415,14 +392,39 @@ public class Config {
|
||||||
* @param setting The setting name, e.g. `trace.config`
|
* @param setting The setting name, e.g. `trace.config`
|
||||||
* @return The public facing system property name
|
* @return The public facing system property name
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
private static String propertyNameToSystemPropertyName(final String setting) {
|
private static String propertyNameToSystemPropertyName(final String setting) {
|
||||||
return PREFIX + setting;
|
return PREFIX + setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> getPropertyMapValue(
|
/**
|
||||||
final Properties properties, final String name, final Map<String, String> defaultValue) {
|
* @param value to parse by tClass::valueOf
|
||||||
final String value = properties.getProperty(name);
|
* @param tClass should contain static parsing method "T valueOf(String)"
|
||||||
return value == null || value.trim().isEmpty() ? defaultValue : parseMap(value, name);
|
* @param defaultValue
|
||||||
|
* @param <T>
|
||||||
|
* @return value == null || value.trim().isEmpty() ? defaultValue : tClass.valueOf(value)
|
||||||
|
* @throws NumberFormatException
|
||||||
|
*/
|
||||||
|
private static <T> T valueOf(
|
||||||
|
final String value, @NonNull final Class<T> tClass, final T defaultValue) {
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
log.debug("valueOf: using defaultValue '{}' for '{}' of '{}' ", defaultValue, value, tClass);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (T)
|
||||||
|
MethodHandles.publicLookup()
|
||||||
|
.findStatic(tClass, "valueOf", MethodType.methodType(tClass, String.class))
|
||||||
|
.invoke(value);
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (final NoSuchMethodException | IllegalAccessException e) {
|
||||||
|
log.debug("Can't invoke or access 'valueOf': ", e);
|
||||||
|
throw new NumberFormatException(e.toString());
|
||||||
|
} catch (final Throwable e) {
|
||||||
|
log.debug("Can't parse: ", e);
|
||||||
|
throw new NumberFormatException(e.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> getPropertyListValue(
|
private static List<String> getPropertyListValue(
|
||||||
|
@ -433,32 +435,15 @@ public class Config {
|
||||||
|
|
||||||
private static Boolean getPropertyBooleanValue(
|
private static Boolean getPropertyBooleanValue(
|
||||||
final Properties properties, final String name, final Boolean defaultValue) {
|
final Properties properties, final String name, final Boolean defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
return valueOf(properties.getProperty(name), Boolean.class, defaultValue);
|
||||||
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer getPropertyIntegerValue(
|
private static Integer getPropertyIntegerValue(
|
||||||
final Properties properties, final String name, final Integer defaultValue) {
|
final Properties properties, final String name, final Integer defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
return valueOf(properties.getProperty(name), Integer.class, defaultValue);
|
||||||
return value == null || value.trim().isEmpty() ? defaultValue : Integer.valueOf(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Enum<T>> Set<T> getPropertySetValue(
|
private static Set<Integer> getPropertyIntegerRangeValue(
|
||||||
final Properties properties, final String name, final Class<T> clazz) {
|
|
||||||
final String value = properties.getProperty(name);
|
|
||||||
if (value != null) {
|
|
||||||
final Set<T> result =
|
|
||||||
convertStringSetToEnumSet(
|
|
||||||
parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz);
|
|
||||||
if (!result.isEmpty()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// null means parent value should be used
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Integer> getPropertyIntegerRangeValue(
|
|
||||||
final Properties properties, final String name, final Set<Integer> defaultValue) {
|
final Properties properties, final String name, final Set<Integer> defaultValue) {
|
||||||
final String value = properties.getProperty(name);
|
final String value = properties.getProperty(name);
|
||||||
try {
|
try {
|
||||||
|
@ -469,38 +454,9 @@ public class Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> parseMap(final String str, final String settingName) {
|
@NonNull
|
||||||
// If we ever want to have default values besides an empty map, this will need to change.
|
private static Set<Integer> parseIntegerRangeSet(@NonNull String str, final String settingName)
|
||||||
if (str == null || str.trim().isEmpty()) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
if (!str.matches("(([^,:]+:[^,:]*,)*([^,:]+:[^,:]*),?)?")) {
|
|
||||||
log.warn(
|
|
||||||
"Invalid config for {}: '{}'. Must match 'key1:value1,key2:value2'.", settingName, str);
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String[] tokens = str.split(",", -1);
|
|
||||||
final Map<String, String> map = newHashMap(tokens.length);
|
|
||||||
|
|
||||||
for (final String token : tokens) {
|
|
||||||
final String[] keyValue = token.split(":", -1);
|
|
||||||
if (keyValue.length == 2) {
|
|
||||||
final String key = keyValue[0].trim();
|
|
||||||
final String value = keyValue[1].trim();
|
|
||||||
if (value.length() <= 0) {
|
|
||||||
log.warn("Ignoring empty value for key '{}' in config for {}", key, settingName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
map.put(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Set<Integer> parseIntegerRangeSet(String str, final String settingName)
|
|
||||||
throws NumberFormatException {
|
throws NumberFormatException {
|
||||||
assert str != null;
|
|
||||||
str = str.replaceAll("\\s", "");
|
str = str.replaceAll("\\s", "");
|
||||||
if (!str.matches("\\d{3}(?:-\\d{3})?(?:,\\d{3}(?:-\\d{3})?)*")) {
|
if (!str.matches("\\d{3}(?:-\\d{3})?(?:,\\d{3}(?:-\\d{3})?)*")) {
|
||||||
log.warn(
|
log.warn(
|
||||||
|
@ -530,10 +486,7 @@ public class Config {
|
||||||
return Collections.unmodifiableSet(set);
|
return Collections.unmodifiableSet(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> newHashMap(final int size) {
|
@NonNull
|
||||||
return new HashMap<>(size + 1, 1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> parseList(final String str) {
|
private static List<String> parseList(final String str) {
|
||||||
if (str == null || str.trim().isEmpty()) {
|
if (str == null || str.trim().isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -547,34 +500,6 @@ public class Config {
|
||||||
return Collections.unmodifiableList(Arrays.asList(tokens));
|
return Collections.unmodifiableList(Arrays.asList(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> parseStringIntoSetOfNonEmptyStrings(
|
|
||||||
final String str, final String regex) {
|
|
||||||
// Using LinkedHashSet to preserve original string order
|
|
||||||
final Set<String> result = new LinkedHashSet<>();
|
|
||||||
// Java returns single value when splitting an empty string. We do not need that value, so
|
|
||||||
// we need to throw it out.
|
|
||||||
for (final String value : str.split(regex)) {
|
|
||||||
if (!value.isEmpty()) {
|
|
||||||
result.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <V extends Enum<V>> Set<V> convertStringSetToEnumSet(
|
|
||||||
final Set<String> input, final Class<V> clazz) {
|
|
||||||
// Using LinkedHashSet to preserve original string order
|
|
||||||
final Set<V> result = new LinkedHashSet<>();
|
|
||||||
for (final String value : input) {
|
|
||||||
try {
|
|
||||||
result.add(Enum.valueOf(clazz, value.toUpperCase()));
|
|
||||||
} catch (final IllegalArgumentException e) {
|
|
||||||
log.debug("Cannot recognize config string value: {}, {}", value, clazz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the optional configuration properties file into the global {@link Properties} object.
|
* Loads the optional configuration properties file into the global {@link Properties} object.
|
||||||
*
|
*
|
||||||
|
@ -606,23 +531,13 @@ public class Config {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileReader fileReader = null;
|
try (final FileReader fileReader = new FileReader(configurationFile)) {
|
||||||
try {
|
|
||||||
fileReader = new FileReader(configurationFile);
|
|
||||||
properties.load(fileReader);
|
properties.load(fileReader);
|
||||||
} catch (final FileNotFoundException fnf) {
|
} catch (final FileNotFoundException fnf) {
|
||||||
log.error("Configuration file '{}' not found.", configurationFilePath);
|
log.error("Configuration file '{}' not found.", configurationFilePath);
|
||||||
} catch (final IOException ioe) {
|
} catch (final IOException ioe) {
|
||||||
log.error(
|
log.error(
|
||||||
"Configuration file '{}' cannot be accessed or correctly parsed.", configurationFilePath);
|
"Configuration file '{}' cannot be accessed or correctly parsed.", configurationFilePath);
|
||||||
} finally {
|
|
||||||
if (fileReader != null) {
|
|
||||||
try {
|
|
||||||
fileReader.close();
|
|
||||||
} catch (final IOException ioe) {
|
|
||||||
log.error("Configuration file '{}' was not closed correctly.", configurationFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020, 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.auto.tooling;
|
|
||||||
|
|
||||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
|
||||||
import net.bytebuddy.asm.TypeConstantAdjustment;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
import net.bytebuddy.utility.JavaModule;
|
|
||||||
|
|
||||||
public class AgentTransformers {
|
|
||||||
|
|
||||||
private static final AgentBuilder.Transformer CONSTANT_ADJUSTER =
|
|
||||||
new AgentBuilder.Transformer() {
|
|
||||||
@Override
|
|
||||||
public DynamicType.Builder<?> transform(
|
|
||||||
final DynamicType.Builder<?> builder,
|
|
||||||
final TypeDescription typeDescription,
|
|
||||||
final ClassLoader classLoader,
|
|
||||||
final JavaModule javaModule) {
|
|
||||||
return builder.visit(TypeConstantAdjustment.INSTANCE);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static AgentBuilder.Transformer defaultTransformers() {
|
|
||||||
return CONSTANT_ADJUSTER;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,6 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||||
|
|
||||||
import io.opentelemetry.auto.config.Config;
|
import io.opentelemetry.auto.config.Config;
|
||||||
|
import io.opentelemetry.auto.tooling.bytebuddy.AgentTransformers;
|
||||||
import io.opentelemetry.auto.tooling.bytebuddy.ExceptionHandlers;
|
import io.opentelemetry.auto.tooling.bytebuddy.ExceptionHandlers;
|
||||||
import io.opentelemetry.auto.tooling.context.FieldBackedProvider;
|
import io.opentelemetry.auto.tooling.context.FieldBackedProvider;
|
||||||
import io.opentelemetry.auto.tooling.context.InstrumentationContextProvider;
|
import io.opentelemetry.auto.tooling.context.InstrumentationContextProvider;
|
||||||
|
@ -122,7 +123,7 @@ public interface Instrumenter {
|
||||||
if (helperClassNames.length > 0) {
|
if (helperClassNames.length > 0) {
|
||||||
agentBuilder =
|
agentBuilder =
|
||||||
agentBuilder.transform(
|
agentBuilder.transform(
|
||||||
new HelperInjector(this.getClass().getSimpleName(), helperClassNames));
|
new HelperInjector(getClass().getSimpleName(), helperClassNames));
|
||||||
}
|
}
|
||||||
return agentBuilder;
|
return agentBuilder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.gradle.api.model.ObjectFactory
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.security.SecureClassLoader
|
import java.security.SecureClassLoader
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* muzzle task plugin which runs muzzle validation against a range of dependencies.
|
* muzzle task plugin which runs muzzle validation against a range of dependencies.
|
||||||
|
@ -36,7 +37,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
||||||
private static final AtomicReference<ClassLoader> TOOLING_LOADER = new AtomicReference<>()
|
private static final AtomicReference<ClassLoader> TOOLING_LOADER = new AtomicReference<>()
|
||||||
static {
|
static {
|
||||||
RemoteRepository central = new RemoteRepository.Builder("central", "default", "https://repo1.maven.org/maven2/").build()
|
RemoteRepository central = new RemoteRepository.Builder("central", "default", "https://repo1.maven.org/maven2/").build()
|
||||||
MUZZLE_REPOS = new ArrayList<RemoteRepository>(Arrays.asList(central))
|
RemoteRepository typesafe = new RemoteRepository.Builder("typesafe", "default", "https://repo.typesafe.com/typesafe/releases").build()
|
||||||
|
MUZZLE_REPOS = new ArrayList<RemoteRepository>(Arrays.asList(central, typesafe))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -343,6 +345,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Pattern GIT_SHA_PATTERN = Pattern.compile('^.*-[0-9a-f]{7,}$')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter out snapshot-type builds from versions list.
|
* Filter out snapshot-type builds from versions list.
|
||||||
*/
|
*/
|
||||||
|
@ -357,7 +361,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
||||||
version.contains(".m") ||
|
version.contains(".m") ||
|
||||||
version.contains("-m") ||
|
version.contains("-m") ||
|
||||||
version.contains("-dev") ||
|
version.contains("-dev") ||
|
||||||
version.contains("public_draft")
|
version.contains("public_draft") ||
|
||||||
|
version.matches(GIT_SHA_PATTERN)
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
test-api-key-very-old
|
|
@ -7,6 +7,7 @@ ext {
|
||||||
|
|
||||||
slf4j : "1.7.29",
|
slf4j : "1.7.29",
|
||||||
guava : "20.0", // Last version to support Java 7
|
guava : "20.0", // Last version to support Java 7
|
||||||
|
okhttp : "3.12.8", // 3.12.x is last version to support Java7
|
||||||
|
|
||||||
spock : "1.3-groovy-$spockGroovyVer",
|
spock : "1.3-groovy-$spockGroovyVer",
|
||||||
groovy : groovyVer,
|
groovy : groovyVer,
|
||||||
|
|
|
@ -133,6 +133,9 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
url "https://adoptopenjdk.jfrog.io/adoptopenjdk/jmc-libs-snapshots"
|
url "https://adoptopenjdk.jfrog.io/adoptopenjdk/jmc-libs-snapshots"
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.typesafe.com/typesafe/releases"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,11 @@ import akka.stream.ActorMaterializer
|
||||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator
|
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class AkkaHttpClientInstrumentationTest extends HttpClientTest {
|
class AkkaHttpClientInstrumentationTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -55,6 +57,12 @@ class AkkaHttpClientInstrumentationTest extends HttpClientTest {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// Not sure how to properly set timeouts...
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
def "singleRequest exception trace"() {
|
def "singleRequest exception trace"() {
|
||||||
when:
|
when:
|
||||||
// Passing null causes NPE in singleRequest
|
// Passing null causes NPE in singleRequest
|
||||||
|
|
|
@ -15,19 +15,28 @@
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import org.apache.http.HttpResponse
|
import org.apache.http.HttpResponse
|
||||||
|
import org.apache.http.client.config.RequestConfig
|
||||||
import org.apache.http.concurrent.FutureCallback
|
import org.apache.http.concurrent.FutureCallback
|
||||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||||
import org.apache.http.message.BasicHeader
|
import org.apache.http.message.BasicHeader
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
|
class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||||
|
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||||
|
.build()
|
||||||
|
|
||||||
@AutoCleanup
|
@AutoCleanup
|
||||||
@Shared
|
@Shared
|
||||||
def client = HttpAsyncClients.createDefault()
|
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||||
|
|
||||||
def setupSpec() {
|
def setupSpec() {
|
||||||
client.start()
|
client.start()
|
||||||
|
@ -68,4 +77,9 @@ class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
|
||||||
Integer statusOnRedirectError() {
|
Integer statusOnRedirectError() {
|
||||||
return 302
|
return 302
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
false // otherwise SocketTimeoutException for https requests
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,18 +14,27 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
|
import org.apache.http.client.config.RequestConfig
|
||||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||||
import org.apache.http.message.BasicHeader
|
import org.apache.http.message.BasicHeader
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
|
class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||||
|
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||||
|
.build()
|
||||||
|
|
||||||
@AutoCleanup
|
@AutoCleanup
|
||||||
@Shared
|
@Shared
|
||||||
def client = HttpAsyncClients.createDefault()
|
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||||
|
|
||||||
def setupSpec() {
|
def setupSpec() {
|
||||||
client.start()
|
client.start()
|
||||||
|
@ -53,4 +62,9 @@ class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
|
||||||
Integer statusOnRedirectError() {
|
Integer statusOnRedirectError() {
|
||||||
return 302
|
return 302
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
false // otherwise SocketTimeoutException for https requests
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,19 +15,28 @@
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import org.apache.http.HttpResponse
|
import org.apache.http.HttpResponse
|
||||||
|
import org.apache.http.client.config.RequestConfig
|
||||||
import org.apache.http.concurrent.FutureCallback
|
import org.apache.http.concurrent.FutureCallback
|
||||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||||
import org.apache.http.message.BasicHeader
|
import org.apache.http.message.BasicHeader
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheHttpAsyncClientTest extends HttpClientTest {
|
class ApacheHttpAsyncClientTest extends HttpClientTest {
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||||
|
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||||
|
.build()
|
||||||
|
|
||||||
@AutoCleanup
|
@AutoCleanup
|
||||||
@Shared
|
@Shared
|
||||||
def client = HttpAsyncClients.createDefault()
|
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||||
|
|
||||||
def setupSpec() {
|
def setupSpec() {
|
||||||
client.start()
|
client.start()
|
||||||
|
@ -74,4 +83,9 @@ class ApacheHttpAsyncClientTest extends HttpClientTest {
|
||||||
Integer statusOnRedirectError() {
|
Integer statusOnRedirectError() {
|
||||||
return 302
|
return 302
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
false // otherwise SocketTimeoutException for https requests
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,18 @@ import org.apache.commons.httpclient.methods.PostMethod
|
||||||
import org.apache.commons.httpclient.methods.PutMethod
|
import org.apache.commons.httpclient.methods.PutMethod
|
||||||
import org.apache.commons.httpclient.methods.TraceMethod
|
import org.apache.commons.httpclient.methods.TraceMethod
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class CommonsHttpClientTest extends HttpClientTest {
|
class CommonsHttpClientTest extends HttpClientTest {
|
||||||
@Shared
|
@Shared
|
||||||
HttpClient client = new HttpClient()
|
HttpClient client = new HttpClient()
|
||||||
|
|
||||||
|
def setupSpec() {
|
||||||
|
client.setConnectionTimeout(CONNECT_TIMEOUT_MS)
|
||||||
|
client.setTimeout(READ_TIMEOUT_MS)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
HttpMethod httpMethod
|
HttpMethod httpMethod
|
||||||
|
|
|
@ -18,8 +18,12 @@ import org.apache.http.HttpResponse
|
||||||
import org.apache.http.client.ResponseHandler
|
import org.apache.http.client.ResponseHandler
|
||||||
import org.apache.http.impl.client.DefaultHttpClient
|
import org.apache.http.impl.client.DefaultHttpClient
|
||||||
import org.apache.http.message.BasicHeader
|
import org.apache.http.message.BasicHeader
|
||||||
|
import org.apache.http.params.HttpConnectionParams
|
||||||
|
import org.apache.http.params.HttpParams
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
|
class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -33,6 +37,12 @@ class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def setupSpec() {
|
||||||
|
HttpParams httpParams = client.getParams()
|
||||||
|
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
|
||||||
|
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
def request = new HttpUriRequest(method, uri)
|
def request = new HttpUriRequest(method, uri)
|
||||||
|
|
|
@ -20,13 +20,22 @@ import org.apache.http.HttpResponse
|
||||||
import org.apache.http.impl.client.DefaultHttpClient
|
import org.apache.http.impl.client.DefaultHttpClient
|
||||||
import org.apache.http.message.BasicHeader
|
import org.apache.http.message.BasicHeader
|
||||||
import org.apache.http.message.BasicHttpRequest
|
import org.apache.http.message.BasicHttpRequest
|
||||||
|
import org.apache.http.params.HttpConnectionParams
|
||||||
|
import org.apache.http.params.HttpParams
|
||||||
import org.apache.http.protocol.BasicHttpContext
|
import org.apache.http.protocol.BasicHttpContext
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTest {
|
abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTest {
|
||||||
@Shared
|
@Shared
|
||||||
def client = new DefaultHttpClient()
|
def client = new DefaultHttpClient()
|
||||||
|
|
||||||
|
def setupSpec() {
|
||||||
|
HttpParams httpParams = client.getParams()
|
||||||
|
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
|
||||||
|
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
def request = createRequest(method, uri)
|
def request = createRequest(method, uri)
|
||||||
|
@ -64,6 +73,7 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
|
class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||||
@Override
|
@Override
|
||||||
BasicHttpRequest createRequest(String method, URI uri) {
|
BasicHttpRequest createRequest(String method, URI uri) {
|
||||||
|
@ -74,8 +84,14 @@ class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request)
|
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||||
@Override
|
@Override
|
||||||
BasicHttpRequest createRequest(String method, URI uri) {
|
BasicHttpRequest createRequest(String method, URI uri) {
|
||||||
|
@ -86,8 +102,14 @@ class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpReque
|
||||||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, new BasicHttpContext())
|
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, new BasicHttpContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicHttpRequest> {
|
class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||||
@Override
|
@Override
|
||||||
BasicHttpRequest createRequest(String method, URI uri) {
|
BasicHttpRequest createRequest(String method, URI uri) {
|
||||||
|
@ -98,8 +120,14 @@ class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicH
|
||||||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response })
|
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||||
@Override
|
@Override
|
||||||
BasicHttpRequest createRequest(String method, URI uri) {
|
BasicHttpRequest createRequest(String method, URI uri) {
|
||||||
|
@ -110,8 +138,14 @@ class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest
|
||||||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }, new BasicHttpContext())
|
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }, new BasicHttpContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
|
class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
|
||||||
@Override
|
@Override
|
||||||
HttpUriRequest createRequest(String method, URI uri) {
|
HttpUriRequest createRequest(String method, URI uri) {
|
||||||
|
@ -124,6 +158,7 @@ class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest> {
|
class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest> {
|
||||||
@Override
|
@Override
|
||||||
HttpUriRequest createRequest(String method, URI uri) {
|
HttpUriRequest createRequest(String method, URI uri) {
|
||||||
|
@ -136,6 +171,7 @@ class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUriRequest> {
|
class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUriRequest> {
|
||||||
@Override
|
@Override
|
||||||
HttpUriRequest createRequest(String method, URI uri) {
|
HttpUriRequest createRequest(String method, URI uri) {
|
||||||
|
@ -148,6 +184,7 @@ class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ApacheClientUriRequestResponseHandlerContext extends ApacheHttpClientTest<HttpUriRequest> {
|
class ApacheClientUriRequestResponseHandlerContext extends ApacheHttpClientTest<HttpUriRequest> {
|
||||||
@Override
|
@Override
|
||||||
HttpUriRequest createRequest(String method, URI uri) {
|
HttpUriRequest createRequest(String method, URI uri) {
|
||||||
|
|
|
@ -38,6 +38,8 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest {
|
||||||
GenericUrl genericUrl = new GenericUrl(uri)
|
GenericUrl genericUrl = new GenericUrl(uri)
|
||||||
|
|
||||||
HttpRequest request = requestFactory.buildRequest(method, genericUrl, null)
|
HttpRequest request = requestFactory.buildRequest(method, genericUrl, null)
|
||||||
|
request.connectTimeout = CONNECT_TIMEOUT_MS
|
||||||
|
request.readTimeout = READ_TIMEOUT_MS
|
||||||
request.getHeaders().putAll(headers)
|
request.getHeaders().putAll(headers)
|
||||||
request.setThrowExceptionOnExecuteError(throwExceptionOnError)
|
request.setThrowExceptionOnExecuteError(throwExceptionOnError)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,11 @@
|
||||||
*/
|
*/
|
||||||
import com.google.api.client.http.HttpRequest
|
import com.google.api.client.http.HttpRequest
|
||||||
import com.google.api.client.http.HttpResponse
|
import com.google.api.client.http.HttpResponse
|
||||||
|
import spock.lang.Retry
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Retry(condition = { !invocation.method.name.contains('circular redirects') })
|
||||||
|
@Timeout(5)
|
||||||
class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest {
|
class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest {
|
||||||
@Override
|
@Override
|
||||||
HttpResponse executeRequest(HttpRequest request) {
|
HttpResponse executeRequest(HttpRequest request) {
|
||||||
|
|
|
@ -15,7 +15,11 @@
|
||||||
*/
|
*/
|
||||||
import com.google.api.client.http.HttpRequest
|
import com.google.api.client.http.HttpRequest
|
||||||
import com.google.api.client.http.HttpResponse
|
import com.google.api.client.http.HttpResponse
|
||||||
|
import spock.lang.Retry
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Retry(condition = { !invocation.method.name.contains('circular redirects') })
|
||||||
|
@Timeout(5)
|
||||||
class GoogleHttpClientTest extends AbstractGoogleHttpClientTest {
|
class GoogleHttpClientTest extends AbstractGoogleHttpClientTest {
|
||||||
@Override
|
@Override
|
||||||
HttpResponse executeRequest(HttpRequest request) {
|
HttpResponse executeRequest(HttpRequest request) {
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
|
class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,6 +24,8 @@ class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
|
||||||
HttpURLConnection connection = uri.toURL().openConnection()
|
HttpURLConnection connection = uri.toURL().openConnection()
|
||||||
try {
|
try {
|
||||||
connection.setRequestMethod(method)
|
connection.setRequestMethod(method)
|
||||||
|
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||||
|
connection.readTimeout = READ_TIMEOUT_MS
|
||||||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||||
connection.setRequestProperty("Connection", "close")
|
connection.setRequestProperty("Connection", "close")
|
||||||
return connection.getResponseCode()
|
return connection.getResponseCode()
|
||||||
|
|
|
@ -18,11 +18,13 @@ import io.opentelemetry.auto.instrumentation.api.Tags
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import spock.lang.Ignore
|
import spock.lang.Ignore
|
||||||
import spock.lang.Requires
|
import spock.lang.Requires
|
||||||
|
import spock.lang.Timeout
|
||||||
import sun.net.www.protocol.https.HttpsURLConnectionImpl
|
import sun.net.www.protocol.https.HttpsURLConnectionImpl
|
||||||
|
|
||||||
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class HttpUrlConnectionTest extends HttpClientTest {
|
class HttpUrlConnectionTest extends HttpClientTest {
|
||||||
|
|
||||||
static final RESPONSE = "Hello."
|
static final RESPONSE = "Hello."
|
||||||
|
@ -36,6 +38,8 @@ class HttpUrlConnectionTest extends HttpClientTest {
|
||||||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||||
connection.setRequestProperty("Connection", "close")
|
connection.setRequestProperty("Connection", "close")
|
||||||
connection.useCaches = true
|
connection.useCaches = true
|
||||||
|
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||||
|
connection.readTimeout = READ_TIMEOUT_MS
|
||||||
def parentSpan = TEST_TRACER.getCurrentSpan()
|
def parentSpan = TEST_TRACER.getCurrentSpan()
|
||||||
def stream = connection.inputStream
|
def stream = connection.inputStream
|
||||||
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
|
class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,6 +27,8 @@ class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
|
||||||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||||
connection.setRequestProperty("Connection", "close")
|
connection.setRequestProperty("Connection", "close")
|
||||||
connection.useCaches = false
|
connection.useCaches = false
|
||||||
|
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||||
|
connection.readTimeout = READ_TIMEOUT_MS
|
||||||
def parentSpan = TEST_TRACER.getCurrentSpan()
|
def parentSpan = TEST_TRACER.getCurrentSpan()
|
||||||
def stream = connection.inputStream
|
def stream = connection.inputStream
|
||||||
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
||||||
|
|
|
@ -18,13 +18,24 @@ import org.springframework.http.HttpEntity
|
||||||
import org.springframework.http.HttpHeaders
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.HttpMethod
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.http.client.ClientHttpRequestFactory
|
||||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||||
import org.springframework.web.client.RestTemplate
|
import org.springframework.web.client.RestTemplate
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class SpringRestTemplateTest extends HttpClientTest {
|
class SpringRestTemplateTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
RestTemplate restTemplate = new RestTemplate()
|
ClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory()
|
||||||
|
@Shared
|
||||||
|
RestTemplate restTemplate = new RestTemplate(factory)
|
||||||
|
|
||||||
|
def setupSpec() {
|
||||||
|
factory.connectTimeout = CONNECT_TIMEOUT_MS
|
||||||
|
factory.readTimeout = READ_TIMEOUT_MS
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
|
@ -45,4 +56,10 @@ class SpringRestTemplateTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: exception wrapped in ResourceAccessException
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,17 @@ import com.sun.jersey.api.client.filter.GZIPContentEncodingFilter
|
||||||
import com.sun.jersey.api.client.filter.LoggingFilter
|
import com.sun.jersey.api.client.filter.LoggingFilter
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class JaxRsClientV1Test extends HttpClientTest {
|
class JaxRsClientV1Test extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
Client client = Client.create()
|
Client client = Client.create()
|
||||||
|
|
||||||
def setupSpec() {
|
def setupSpec() {
|
||||||
|
client.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||||
|
client.setReadTimeout(READ_TIMEOUT_MS)
|
||||||
// Add filters to ensure spans aren't duplicated.
|
// Add filters to ensure spans aren't duplicated.
|
||||||
client.addFilter(new LoggingFilter())
|
client.addFilter(new LoggingFilter())
|
||||||
client.addFilter(new GZIPContentEncodingFilter())
|
client.addFilter(new GZIPContentEncodingFilter())
|
||||||
|
|
|
@ -32,7 +32,8 @@ dependencies {
|
||||||
testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
|
testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
|
||||||
|
|
||||||
testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.0'
|
testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.0'
|
||||||
testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.0.Final'
|
testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.5.Final'
|
||||||
|
// ^ This version has timeouts https://issues.redhat.com/browse/RESTEASY-975
|
||||||
testCompile group: 'org.apache.cxf', name: 'cxf-rt-rs-client', version: '3.1.0'
|
testCompile group: 'org.apache.cxf', name: 'cxf-rt-rs-client', version: '3.1.0'
|
||||||
// Doesn't work with CXF 3.0.x because their context is wrong:
|
// Doesn't work with CXF 3.0.x because their context is wrong:
|
||||||
// https://github.com/apache/cxf/commit/335c7bad2436f08d6d54180212df5a52157c9f21
|
// https://github.com/apache/cxf/commit/335c7bad2436f08d6d54180212df5a52157c9f21
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
||||||
|
import org.glassfish.jersey.client.ClientConfig
|
||||||
|
import org.glassfish.jersey.client.ClientProperties
|
||||||
import org.glassfish.jersey.client.JerseyClientBuilder
|
import org.glassfish.jersey.client.JerseyClientBuilder
|
||||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import javax.ws.rs.client.AsyncInvoker
|
import javax.ws.rs.client.AsyncInvoker
|
||||||
import javax.ws.rs.client.Client
|
import javax.ws.rs.client.Client
|
||||||
|
@ -27,6 +30,7 @@ import javax.ws.rs.client.WebTarget
|
||||||
import javax.ws.rs.core.MediaType
|
import javax.ws.rs.core.MediaType
|
||||||
import javax.ws.rs.core.Response
|
import javax.ws.rs.core.Response
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
abstract class JaxRsClientAsyncTest extends HttpClientTest {
|
abstract class JaxRsClientAsyncTest extends HttpClientTest {
|
||||||
|
|
||||||
|
@ -61,11 +65,15 @@ abstract class JaxRsClientAsyncTest extends HttpClientTest {
|
||||||
abstract ClientBuilder builder()
|
abstract ClientBuilder builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
|
class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new JerseyClientBuilder()
|
ClientConfig config = new ClientConfig()
|
||||||
|
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
|
||||||
|
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
|
||||||
|
return new JerseyClientBuilder().withConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testCircularRedirects() {
|
boolean testCircularRedirects() {
|
||||||
|
@ -73,11 +81,14 @@ class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
|
class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new ResteasyClientBuilder()
|
return new ResteasyClientBuilder()
|
||||||
|
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testRedirects() {
|
boolean testRedirects() {
|
||||||
|
@ -85,6 +96,7 @@ class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class CxfClientAsyncTest extends JaxRsClientAsyncTest {
|
class CxfClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,4 +111,9 @@ class CxfClientAsyncTest extends JaxRsClientAsyncTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: span not reported correctly.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
*/
|
*/
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
||||||
|
import org.glassfish.jersey.client.ClientConfig
|
||||||
|
import org.glassfish.jersey.client.ClientProperties
|
||||||
import org.glassfish.jersey.client.JerseyClientBuilder
|
import org.glassfish.jersey.client.JerseyClientBuilder
|
||||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import javax.ws.rs.client.Client
|
import javax.ws.rs.client.Client
|
||||||
import javax.ws.rs.client.ClientBuilder
|
import javax.ws.rs.client.ClientBuilder
|
||||||
|
@ -25,6 +28,7 @@ import javax.ws.rs.client.Invocation
|
||||||
import javax.ws.rs.client.WebTarget
|
import javax.ws.rs.client.WebTarget
|
||||||
import javax.ws.rs.core.MediaType
|
import javax.ws.rs.core.MediaType
|
||||||
import javax.ws.rs.core.Response
|
import javax.ws.rs.core.Response
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
abstract class JaxRsClientTest extends HttpClientTest {
|
abstract class JaxRsClientTest extends HttpClientTest {
|
||||||
|
|
||||||
|
@ -45,11 +49,15 @@ abstract class JaxRsClientTest extends HttpClientTest {
|
||||||
abstract ClientBuilder builder()
|
abstract ClientBuilder builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class JerseyClientTest extends JaxRsClientTest {
|
class JerseyClientTest extends JaxRsClientTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new JerseyClientBuilder()
|
ClientConfig config = new ClientConfig()
|
||||||
|
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
|
||||||
|
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
|
||||||
|
return new JerseyClientBuilder().withConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testCircularRedirects() {
|
boolean testCircularRedirects() {
|
||||||
|
@ -57,24 +65,29 @@ class JerseyClientTest extends JaxRsClientTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class ResteasyClientTest extends JaxRsClientTest {
|
class ResteasyClientTest extends JaxRsClientTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new ResteasyClientBuilder()
|
return new ResteasyClientBuilder()
|
||||||
|
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testRedirects() {
|
boolean testRedirects() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class CxfClientTest extends JaxRsClientTest {
|
class CxfClientTest extends JaxRsClientTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new ClientBuilderImpl()
|
return new ClientBuilderImpl()
|
||||||
|
// .property(ClientImpl.HTTP_CONNECTION_TIMEOUT_PROP, (long) CONNECT_TIMEOUT_MS)
|
||||||
|
// .property(ClientImpl.HTTP_RECEIVE_TIMEOUT_PROP, (long) READ_TIMEOUT_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testRedirects() {
|
boolean testRedirects() {
|
||||||
|
@ -84,4 +97,9 @@ class CxfClientTest extends JaxRsClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: span not reported correctly.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import com.ning.http.client.AsyncCompletionHandler
|
||||||
import com.ning.http.client.AsyncHttpClient
|
import com.ning.http.client.AsyncHttpClient
|
||||||
import com.ning.http.client.AsyncHttpClientConfig
|
import com.ning.http.client.AsyncHttpClientConfig
|
||||||
import com.ning.http.client.Response
|
import com.ning.http.client.Response
|
||||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
@ -65,6 +64,11 @@ class Netty38ClientTest extends HttpClientTest {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
def "connection error (unopened port)"() {
|
def "connection error (unopened port)"() {
|
||||||
given:
|
given:
|
||||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
||||||
|
@ -88,7 +92,6 @@ class Netty38ClientTest extends HttpClientTest {
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored true
|
errored true
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT" "netty"
|
|
||||||
Class errorClass = ConnectException
|
Class errorClass = ConnectException
|
||||||
try {
|
try {
|
||||||
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
||||||
|
|
|
@ -17,9 +17,9 @@ import io.opentelemetry.auto.test.base.HttpServerTest
|
||||||
import org.jboss.netty.bootstrap.ServerBootstrap
|
import org.jboss.netty.bootstrap.ServerBootstrap
|
||||||
import org.jboss.netty.buffer.ChannelBuffer
|
import org.jboss.netty.buffer.ChannelBuffer
|
||||||
import org.jboss.netty.buffer.ChannelBuffers
|
import org.jboss.netty.buffer.ChannelBuffers
|
||||||
import org.jboss.netty.channel.Channel
|
|
||||||
import org.jboss.netty.channel.ChannelHandlerContext
|
import org.jboss.netty.channel.ChannelHandlerContext
|
||||||
import org.jboss.netty.channel.ChannelPipeline
|
import org.jboss.netty.channel.ChannelPipeline
|
||||||
|
import org.jboss.netty.channel.ChannelPipelineFactory
|
||||||
import org.jboss.netty.channel.DefaultChannelPipeline
|
import org.jboss.netty.channel.DefaultChannelPipeline
|
||||||
import org.jboss.netty.channel.DownstreamMessageEvent
|
import org.jboss.netty.channel.DownstreamMessageEvent
|
||||||
import org.jboss.netty.channel.ExceptionEvent
|
import org.jboss.netty.channel.ExceptionEvent
|
||||||
|
@ -35,6 +35,8 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus
|
||||||
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
||||||
import org.jboss.netty.handler.logging.LoggingHandler
|
import org.jboss.netty.handler.logging.LoggingHandler
|
||||||
import org.jboss.netty.logging.InternalLogLevel
|
import org.jboss.netty.logging.InternalLogLevel
|
||||||
|
import org.jboss.netty.logging.InternalLoggerFactory
|
||||||
|
import org.jboss.netty.logging.Slf4JLoggerFactory
|
||||||
import org.jboss.netty.util.CharsetUtil
|
import org.jboss.netty.util.CharsetUtil
|
||||||
|
|
||||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||||
|
@ -49,10 +51,17 @@ import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE
|
||||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
||||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
||||||
|
|
||||||
class Netty38ServerTest extends HttpServerTest<Channel> {
|
class Netty38ServerTest extends HttpServerTest<ServerBootstrap> {
|
||||||
|
|
||||||
|
static final LoggingHandler LOGGING_HANDLER
|
||||||
|
static {
|
||||||
|
InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory())
|
||||||
|
LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, InternalLogLevel.DEBUG, true)
|
||||||
|
}
|
||||||
|
|
||||||
ChannelPipeline channelPipeline() {
|
ChannelPipeline channelPipeline() {
|
||||||
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
||||||
|
channelPipeline.addFirst("logger", LOGGING_HANDLER)
|
||||||
|
|
||||||
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
||||||
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
||||||
|
@ -103,7 +112,8 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
||||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(ex.getCause().getMessage(), CharsetUtil.UTF_8)
|
def message = ex.getCause() == null ? "<no cause> " + ex.message : ex.cause.message == null ? "<null>" : ex.cause.message
|
||||||
|
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(message, CharsetUtil.UTF_8)
|
||||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
||||||
response.setContent(buffer)
|
response.setContent(buffer)
|
||||||
response.headers().set(CONTENT_TYPE, "text/plain")
|
response.headers().set(CONTENT_TYPE, "text/plain")
|
||||||
|
@ -120,17 +130,23 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Channel startServer(int port) {
|
ServerBootstrap startServer(int port) {
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
||||||
bootstrap.setParentHandler(new LoggingHandler(InternalLogLevel.INFO))
|
bootstrap.setParentHandler(LOGGING_HANDLER)
|
||||||
bootstrap.setPipeline(channelPipeline())
|
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||||
|
@Override
|
||||||
|
ChannelPipeline getPipeline() throws Exception {
|
||||||
|
return channelPipeline()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
InetSocketAddress address = new InetSocketAddress(port)
|
InetSocketAddress address = new InetSocketAddress(port)
|
||||||
return bootstrap.bind(address)
|
bootstrap.bind(address)
|
||||||
|
return bootstrap
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void stopServer(Channel server) {
|
void stopServer(ServerBootstrap server) {
|
||||||
server?.disconnect()
|
server?.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||||
import io.opentelemetry.auto.instrumentation.api.Tags;
|
|
||||||
import io.opentelemetry.auto.instrumentation.netty.v3_8.server.NettyHttpServerDecorator;
|
import io.opentelemetry.auto.instrumentation.netty.v3_8.server.NettyHttpServerDecorator;
|
||||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
|
@ -113,11 +112,7 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
|
||||||
final Scope parentScope = NettyHttpServerDecorator.TRACER.withSpan(continuation);
|
final Scope parentScope = NettyHttpServerDecorator.TRACER.withSpan(continuation);
|
||||||
|
|
||||||
final Span errorSpan =
|
final Span errorSpan =
|
||||||
NettyHttpServerDecorator.TRACER
|
NettyHttpServerDecorator.TRACER.spanBuilder("CONNECT").setSpanKind(CLIENT).startSpan();
|
||||||
.spanBuilder("CONNECT")
|
|
||||||
.setSpanKind(CLIENT)
|
|
||||||
.setAttribute(Tags.COMPONENT, "netty")
|
|
||||||
.startSpan();
|
|
||||||
try (final Scope scope = NettyHttpServerDecorator.TRACER.withSpan(errorSpan)) {
|
try (final Scope scope = NettyHttpServerDecorator.TRACER.withSpan(errorSpan)) {
|
||||||
NettyHttpServerDecorator.DECORATE.onError(errorSpan, cause);
|
NettyHttpServerDecorator.DECORATE.onError(errorSpan, cause);
|
||||||
NettyHttpServerDecorator.DECORATE.beforeFinish(errorSpan);
|
NettyHttpServerDecorator.DECORATE.beforeFinish(errorSpan);
|
||||||
|
|
|
@ -17,7 +17,6 @@ import com.ning.http.client.AsyncCompletionHandler
|
||||||
import com.ning.http.client.AsyncHttpClient
|
import com.ning.http.client.AsyncHttpClient
|
||||||
import com.ning.http.client.AsyncHttpClientConfig
|
import com.ning.http.client.AsyncHttpClientConfig
|
||||||
import com.ning.http.client.Response
|
import com.ning.http.client.Response
|
||||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
@ -65,6 +64,11 @@ class Netty38ClientTest extends HttpClientTest {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
def "connection error (unopened port)"() {
|
def "connection error (unopened port)"() {
|
||||||
given:
|
given:
|
||||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
||||||
|
@ -88,7 +92,6 @@ class Netty38ClientTest extends HttpClientTest {
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored true
|
errored true
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT" "netty"
|
|
||||||
Class errorClass = ConnectException
|
Class errorClass = ConnectException
|
||||||
try {
|
try {
|
||||||
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
||||||
|
|
|
@ -17,9 +17,9 @@ import io.opentelemetry.auto.test.base.HttpServerTest
|
||||||
import org.jboss.netty.bootstrap.ServerBootstrap
|
import org.jboss.netty.bootstrap.ServerBootstrap
|
||||||
import org.jboss.netty.buffer.ChannelBuffer
|
import org.jboss.netty.buffer.ChannelBuffer
|
||||||
import org.jboss.netty.buffer.ChannelBuffers
|
import org.jboss.netty.buffer.ChannelBuffers
|
||||||
import org.jboss.netty.channel.Channel
|
|
||||||
import org.jboss.netty.channel.ChannelHandlerContext
|
import org.jboss.netty.channel.ChannelHandlerContext
|
||||||
import org.jboss.netty.channel.ChannelPipeline
|
import org.jboss.netty.channel.ChannelPipeline
|
||||||
|
import org.jboss.netty.channel.ChannelPipelineFactory
|
||||||
import org.jboss.netty.channel.DefaultChannelPipeline
|
import org.jboss.netty.channel.DefaultChannelPipeline
|
||||||
import org.jboss.netty.channel.DownstreamMessageEvent
|
import org.jboss.netty.channel.DownstreamMessageEvent
|
||||||
import org.jboss.netty.channel.ExceptionEvent
|
import org.jboss.netty.channel.ExceptionEvent
|
||||||
|
@ -35,6 +35,8 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus
|
||||||
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
||||||
import org.jboss.netty.handler.logging.LoggingHandler
|
import org.jboss.netty.handler.logging.LoggingHandler
|
||||||
import org.jboss.netty.logging.InternalLogLevel
|
import org.jboss.netty.logging.InternalLogLevel
|
||||||
|
import org.jboss.netty.logging.InternalLoggerFactory
|
||||||
|
import org.jboss.netty.logging.Slf4JLoggerFactory
|
||||||
import org.jboss.netty.util.CharsetUtil
|
import org.jboss.netty.util.CharsetUtil
|
||||||
|
|
||||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||||
|
@ -49,10 +51,17 @@ import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE
|
||||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
||||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
||||||
|
|
||||||
class Netty38ServerTest extends HttpServerTest<Channel> {
|
class Netty38ServerTest extends HttpServerTest<ServerBootstrap> {
|
||||||
|
|
||||||
|
static final LoggingHandler LOGGING_HANDLER
|
||||||
|
static {
|
||||||
|
InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory())
|
||||||
|
LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, InternalLogLevel.DEBUG, true)
|
||||||
|
}
|
||||||
|
|
||||||
ChannelPipeline channelPipeline() {
|
ChannelPipeline channelPipeline() {
|
||||||
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
||||||
|
channelPipeline.addFirst("logger", LOGGING_HANDLER)
|
||||||
|
|
||||||
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
||||||
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
||||||
|
@ -103,7 +112,8 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
||||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(ex.getCause().getMessage(), CharsetUtil.UTF_8)
|
def message = ex.cause == null ? "<no cause> " + ex.message : ex.cause.message == null ? "<null>" : ex.cause.message
|
||||||
|
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(message, CharsetUtil.UTF_8)
|
||||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
||||||
response.setContent(buffer)
|
response.setContent(buffer)
|
||||||
response.headers().set(CONTENT_TYPE, "text/plain")
|
response.headers().set(CONTENT_TYPE, "text/plain")
|
||||||
|
@ -120,17 +130,23 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Channel startServer(int port) {
|
ServerBootstrap startServer(int port) {
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
||||||
bootstrap.setParentHandler(new LoggingHandler(InternalLogLevel.INFO))
|
bootstrap.setParentHandler(LOGGING_HANDLER)
|
||||||
bootstrap.setPipeline(channelPipeline())
|
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||||
|
@Override
|
||||||
|
ChannelPipeline getPipeline() throws Exception {
|
||||||
|
return channelPipeline()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
InetSocketAddress address = new InetSocketAddress(port)
|
InetSocketAddress address = new InetSocketAddress(port)
|
||||||
return bootstrap.bind(address)
|
bootstrap.bind(address)
|
||||||
|
return bootstrap
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void stopServer(Channel server) {
|
void stopServer(ServerBootstrap server) {
|
||||||
server?.disconnect()
|
server?.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
|
||||||
import org.asynchttpclient.Response
|
import org.asynchttpclient.Response
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -29,6 +30,7 @@ import static io.opentelemetry.auto.test.utils.TraceUtils.basicSpan
|
||||||
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||||
import static org.asynchttpclient.Dsl.asyncHttpClient
|
import static org.asynchttpclient.Dsl.asyncHttpClient
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class Netty40ClientTest extends HttpClientTest {
|
class Netty40ClientTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -62,6 +64,11 @@ class Netty40ClientTest extends HttpClientTest {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
def "connection error (unopened port)"() {
|
def "connection error (unopened port)"() {
|
||||||
given:
|
given:
|
||||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/") // Use numeric address to avoid ipv4/ipv6 confusion
|
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/") // Use numeric address to avoid ipv4/ipv6 confusion
|
||||||
|
|
|
@ -48,16 +48,20 @@ import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCC
|
||||||
|
|
||||||
class Netty40ServerTest extends HttpServerTest<EventLoopGroup> {
|
class Netty40ServerTest extends HttpServerTest<EventLoopGroup> {
|
||||||
|
|
||||||
|
static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, LogLevel.DEBUG)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
EventLoopGroup startServer(int port) {
|
EventLoopGroup startServer(int port) {
|
||||||
def eventLoopGroup = new NioEventLoopGroup()
|
def eventLoopGroup = new NioEventLoopGroup()
|
||||||
|
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||||
.group(eventLoopGroup)
|
.group(eventLoopGroup)
|
||||||
.handler(new LoggingHandler(LogLevel.INFO))
|
.handler(LOGGING_HANDLER)
|
||||||
.childHandler([
|
.childHandler([
|
||||||
initChannel: { ch ->
|
initChannel: { ch ->
|
||||||
ChannelPipeline pipeline = ch.pipeline()
|
ChannelPipeline pipeline = ch.pipeline()
|
||||||
|
pipeline.addFirst("logger", LOGGING_HANDLER)
|
||||||
|
|
||||||
def handlers = [new HttpRequestDecoder(), new HttpResponseEncoder()]
|
def handlers = [new HttpRequestDecoder(), new HttpResponseEncoder()]
|
||||||
handlers.each { pipeline.addLast(it) }
|
handlers.each { pipeline.addLast(it) }
|
||||||
pipeline.addLast([
|
pipeline.addLast([
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
|
||||||
import org.asynchttpclient.Response
|
import org.asynchttpclient.Response
|
||||||
import spock.lang.Retry
|
import spock.lang.Retry
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -39,6 +40,7 @@ import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||||
import static org.asynchttpclient.Dsl.asyncHttpClient
|
import static org.asynchttpclient.Dsl.asyncHttpClient
|
||||||
|
|
||||||
@Retry
|
@Retry
|
||||||
|
@Timeout(5)
|
||||||
class Netty41ClientTest extends HttpClientTest {
|
class Netty41ClientTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -71,6 +73,11 @@ class Netty41ClientTest extends HttpClientTest {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
def "connection error (unopened port)"() {
|
def "connection error (unopened port)"() {
|
||||||
given:
|
given:
|
||||||
def uri = new URI("http://localhost:$UNUSABLE_PORT/")
|
def uri = new URI("http://localhost:$UNUSABLE_PORT/")
|
||||||
|
|
|
@ -47,16 +47,20 @@ import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCC
|
||||||
|
|
||||||
class Netty41ServerTest extends HttpServerTest<EventLoopGroup> {
|
class Netty41ServerTest extends HttpServerTest<EventLoopGroup> {
|
||||||
|
|
||||||
|
static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, LogLevel.DEBUG)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
EventLoopGroup startServer(int port) {
|
EventLoopGroup startServer(int port) {
|
||||||
def eventLoopGroup = new NioEventLoopGroup()
|
def eventLoopGroup = new NioEventLoopGroup()
|
||||||
|
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||||
.group(eventLoopGroup)
|
.group(eventLoopGroup)
|
||||||
.handler(new LoggingHandler(LogLevel.INFO))
|
.handler(LOGGING_HANDLER)
|
||||||
.childHandler([
|
.childHandler([
|
||||||
initChannel: { ch ->
|
initChannel: { ch ->
|
||||||
ChannelPipeline pipeline = ch.pipeline()
|
ChannelPipeline pipeline = ch.pipeline()
|
||||||
|
pipeline.addFirst("logger", LOGGING_HANDLER)
|
||||||
|
|
||||||
def handlers = [new HttpServerCodec()]
|
def handlers = [new HttpServerCodec()]
|
||||||
handlers.each { pipeline.addLast(it) }
|
handlers.each { pipeline.addLast(it) }
|
||||||
pipeline.addLast([
|
pipeline.addLast([
|
||||||
|
|
|
@ -20,10 +20,18 @@ import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
import okhttp3.internal.http.HttpMethod
|
import okhttp3.internal.http.HttpMethod
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class OkHttp3Test extends HttpClientTest {
|
class OkHttp3Test extends HttpClientTest {
|
||||||
|
|
||||||
def client = new OkHttpClient()
|
def client = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
.readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
.writeTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
|
|
|
@ -23,9 +23,11 @@ import scala.concurrent.ExecutionContext
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration.Duration
|
import scala.concurrent.duration.Duration
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class PlayJavaWSClientTest extends PlayWSClientTestBase {
|
class PlayJavaWSClientTest extends PlayWSClientTestBase {
|
||||||
@Shared
|
@Shared
|
||||||
StandaloneWSClient wsClient
|
StandaloneWSClient wsClient
|
||||||
|
@ -52,6 +54,7 @@ class PlayJavaWSClientTest extends PlayWSClientTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
|
class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
|
||||||
@Shared
|
@Shared
|
||||||
StandaloneWSClient wsClient
|
StandaloneWSClient wsClient
|
||||||
|
@ -81,6 +84,7 @@ class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class PlayScalaWSClientTest extends PlayWSClientTestBase {
|
class PlayScalaWSClientTest extends PlayWSClientTestBase {
|
||||||
@Shared
|
@Shared
|
||||||
play.api.libs.ws.StandaloneWSClient wsClient
|
play.api.libs.ws.StandaloneWSClient wsClient
|
||||||
|
@ -111,6 +115,7 @@ class PlayScalaWSClientTest extends PlayWSClientTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class PlayScalaStreamedWSClientTest extends PlayWSClientTestBase {
|
class PlayScalaStreamedWSClientTest extends PlayWSClientTestBase {
|
||||||
@Shared
|
@Shared
|
||||||
play.api.libs.ws.StandaloneWSClient wsClient
|
play.api.libs.ws.StandaloneWSClient wsClient
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
logs/
|
|
@ -0,0 +1,57 @@
|
||||||
|
ext {
|
||||||
|
minJavaVersionForTests = JavaVersion.VERSION_1_8
|
||||||
|
// Play doesn't work with Java 9+ until 2.6.12
|
||||||
|
maxJavaVersionForTests = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "${rootDir}/gradle/instrumentation.gradle"
|
||||||
|
apply from: "${rootDir}/gradle/test-with-scala.gradle"
|
||||||
|
apply plugin: 'org.unbroken-dome.test-sets'
|
||||||
|
|
||||||
|
muzzle {
|
||||||
|
pass {
|
||||||
|
group = 'com.typesafe.play'
|
||||||
|
module = 'play_2.11'
|
||||||
|
versions = '[2.3.0,2.4)'
|
||||||
|
assertInverse = true
|
||||||
|
}
|
||||||
|
fail {
|
||||||
|
group = 'com.typesafe.play'
|
||||||
|
module = 'play_2.12'
|
||||||
|
versions = '[,]'
|
||||||
|
}
|
||||||
|
fail {
|
||||||
|
group = 'com.typesafe.play'
|
||||||
|
module = 'play_2.13'
|
||||||
|
versions = '[,]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testSets {
|
||||||
|
latestDepTest {
|
||||||
|
dirName = 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
main_java8Compile group: 'com.typesafe.play', name: 'play_2.11', version: '2.3.0'
|
||||||
|
|
||||||
|
testCompile project(':instrumentation:netty:netty-3.8')
|
||||||
|
|
||||||
|
testCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.0'
|
||||||
|
testCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.0'
|
||||||
|
testCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.0') {
|
||||||
|
exclude group: 'org.eclipse.jetty', module: 'jetty-websocket'
|
||||||
|
}
|
||||||
|
|
||||||
|
latestDepTestCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.+'
|
||||||
|
latestDepTestCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.+'
|
||||||
|
latestDepTestCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.+') {
|
||||||
|
exclude group: 'org.eclipse.jetty', module: 'jetty-websocket'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileLatestDepTestGroovy {
|
||||||
|
classpath = classpath.plus(files(compileLatestDepTestScala.destinationDir))
|
||||||
|
dependsOn compileLatestDepTestScala
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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.auto.instrumentation.play.v2_3;
|
||||||
|
|
||||||
|
import static io.opentelemetry.auto.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||||
|
import static io.opentelemetry.auto.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public final class PlayInstrumentation extends Instrumenter.Default {
|
||||||
|
|
||||||
|
public PlayInstrumentation() {
|
||||||
|
super("play", "play-action");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<ClassLoader> classLoaderMatcher() {
|
||||||
|
// Optimization for expensive typeMatcher.
|
||||||
|
return hasClassesNamed("play.api.mvc.Action");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
return implementsInterface(named("play.api.mvc.Action"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
packageName + ".PlayHttpServerDecorator",
|
||||||
|
packageName + ".RequestCompleteCallback",
|
||||||
|
packageName + ".PlayHeaders",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
|
return singletonMap(
|
||||||
|
named("apply")
|
||||||
|
.and(takesArgument(0, named("play.api.mvc.Request")))
|
||||||
|
.and(returns(named("scala.concurrent.Future"))),
|
||||||
|
packageName + ".PlayAdvice");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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.auto.instrumentation.play.v2_3;
|
||||||
|
|
||||||
|
import static io.opentelemetry.auto.bootstrap.instrumentation.decorator.BaseDecorator.extract;
|
||||||
|
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHeaders.GETTER;
|
||||||
|
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.DECORATE;
|
||||||
|
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.TRACER;
|
||||||
|
import static io.opentelemetry.trace.TracingContextUtils.currentContextWith;
|
||||||
|
|
||||||
|
import io.opentelemetry.auto.instrumentation.api.SpanWithScope;
|
||||||
|
import io.opentelemetry.auto.instrumentation.api.Tags;
|
||||||
|
import io.opentelemetry.trace.Span;
|
||||||
|
import io.opentelemetry.trace.SpanContext;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import play.api.mvc.Action;
|
||||||
|
import play.api.mvc.Request;
|
||||||
|
import play.api.mvc.Result;
|
||||||
|
import scala.concurrent.Future;
|
||||||
|
|
||||||
|
public class PlayAdvice {
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static SpanWithScope onEnter(@Advice.Argument(0) final Request req) {
|
||||||
|
final Span.Builder spanBuilder = TRACER.spanBuilder("play.request");
|
||||||
|
if (!TRACER.getCurrentSpan().getContext().isValid()) {
|
||||||
|
final SpanContext extractedContext = extract(req.headers(), GETTER);
|
||||||
|
if (extractedContext.isValid()) {
|
||||||
|
spanBuilder.setParent(extractedContext);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// An upstream framework (e.g. akka-http, netty) has already started the span.
|
||||||
|
// Do not extract the context.
|
||||||
|
}
|
||||||
|
final Span span = spanBuilder.startSpan();
|
||||||
|
DECORATE.afterStart(span);
|
||||||
|
DECORATE.onConnection(span, req);
|
||||||
|
|
||||||
|
return new SpanWithScope(span, currentContextWith(span));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopTraceOnResponse(
|
||||||
|
@Advice.Enter final SpanWithScope playControllerScope,
|
||||||
|
@Advice.This final Object thisAction,
|
||||||
|
@Advice.Thrown final Throwable throwable,
|
||||||
|
@Advice.Argument(0) final Request req,
|
||||||
|
@Advice.Return(readOnly = false) final Future<Result> responseFuture) {
|
||||||
|
final Span playControllerSpan = playControllerScope.getSpan();
|
||||||
|
|
||||||
|
// Call onRequest on return after tags are populated.
|
||||||
|
DECORATE.onRequest(playControllerSpan, req);
|
||||||
|
|
||||||
|
if (throwable == null) {
|
||||||
|
responseFuture.onComplete(
|
||||||
|
new RequestCompleteCallback(playControllerSpan),
|
||||||
|
((Action) thisAction).executionContext());
|
||||||
|
} else {
|
||||||
|
DECORATE.onError(playControllerSpan, throwable);
|
||||||
|
playControllerSpan.setAttribute(Tags.HTTP_STATUS, 500);
|
||||||
|
DECORATE.beforeFinish(playControllerSpan);
|
||||||
|
playControllerSpan.end();
|
||||||
|
}
|
||||||
|
playControllerScope.closeScope();
|
||||||
|
|
||||||
|
final Span rootSpan = TRACER.getCurrentSpan();
|
||||||
|
// set the resource name on the upstream akka/netty span
|
||||||
|
DECORATE.onRequest(rootSpan, req);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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.auto.instrumentation.play.v2_3;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.propagation.HttpTextFormat;
|
||||||
|
import play.api.mvc.Headers;
|
||||||
|
import scala.Option;
|
||||||
|
|
||||||
|
public class PlayHeaders implements HttpTextFormat.Getter<Headers> {
|
||||||
|
|
||||||
|
public static final PlayHeaders GETTER = new PlayHeaders();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(final Headers headers, final String key) {
|
||||||
|
final Option<String> option = headers.get(key);
|
||||||
|
if (option.isDefined()) {
|
||||||
|
return option.get();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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.auto.instrumentation.play.v2_3;
|
||||||
|
|
||||||
|
import io.opentelemetry.OpenTelemetry;
|
||||||
|
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpServerDecorator;
|
||||||
|
import io.opentelemetry.auto.instrumentation.api.Tags;
|
||||||
|
import io.opentelemetry.trace.Span;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import play.api.mvc.Request;
|
||||||
|
import play.api.mvc.Result;
|
||||||
|
import scala.Option;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class PlayHttpServerDecorator extends HttpServerDecorator<Request, Request, Result> {
|
||||||
|
public static final PlayHttpServerDecorator DECORATE = new PlayHttpServerDecorator();
|
||||||
|
|
||||||
|
public static final Tracer TRACER =
|
||||||
|
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.play-2.4");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getComponentName() {
|
||||||
|
return "play-action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(final Request httpRequest) {
|
||||||
|
return httpRequest.method();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URI url(final Request request) throws URISyntaxException {
|
||||||
|
return new URI((request.secure() ? "https://" : "http://") + request.host() + request.uri());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String peerHostIP(final Request request) {
|
||||||
|
return request.remoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer peerPort(final Request request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer status(final Result httpResponse) {
|
||||||
|
return httpResponse.header().status();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Span onRequest(final Span span, final Request request) {
|
||||||
|
super.onRequest(span, request);
|
||||||
|
if (request != null) {
|
||||||
|
// more about routes here:
|
||||||
|
// https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md#router-tags-are-now-attributes
|
||||||
|
final Option pathOption = request.tags().get("ROUTE_PATTERN");
|
||||||
|
if (!pathOption.isEmpty()) {
|
||||||
|
final String path = (String) pathOption.get();
|
||||||
|
span.updateName(request.method() + " " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Span onError(final Span span, Throwable throwable) {
|
||||||
|
span.setAttribute(Tags.HTTP_STATUS, 500);
|
||||||
|
if (throwable != null
|
||||||
|
// This can be moved to instanceof check when using Java 8.
|
||||||
|
&& throwable.getClass().getName().equals("java.util.concurrent.CompletionException")
|
||||||
|
&& throwable.getCause() != null) {
|
||||||
|
throwable = throwable.getCause();
|
||||||
|
}
|
||||||
|
while ((throwable instanceof InvocationTargetException
|
||||||
|
|| throwable instanceof UndeclaredThrowableException)
|
||||||
|
&& throwable.getCause() != null) {
|
||||||
|
throwable = throwable.getCause();
|
||||||
|
}
|
||||||
|
return super.onError(span, throwable);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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.auto.instrumentation.play.v2_3;
|
||||||
|
|
||||||
|
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.DECORATE;
|
||||||
|
|
||||||
|
import io.opentelemetry.trace.Span;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import play.api.mvc.Result;
|
||||||
|
import scala.util.Try;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class RequestCompleteCallback extends scala.runtime.AbstractFunction1<Try<Result>, Object> {
|
||||||
|
private final Span span;
|
||||||
|
|
||||||
|
public RequestCompleteCallback(final Span span) {
|
||||||
|
this.span = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object apply(final Try<Result> result) {
|
||||||
|
try {
|
||||||
|
if (result.isFailure()) {
|
||||||
|
DECORATE.onError(span, result.failed().get());
|
||||||
|
} else {
|
||||||
|
DECORATE.onResponse(span, result.get());
|
||||||
|
}
|
||||||
|
DECORATE.beforeFinish(span);
|
||||||
|
} catch (final Throwable t) {
|
||||||
|
log.debug("error in play instrumentation", t);
|
||||||
|
} finally {
|
||||||
|
span.end();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 client
|
||||||
|
|
||||||
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
|
import play.GlobalSettings
|
||||||
|
import play.libs.ws.WS
|
||||||
|
import play.test.FakeApplication
|
||||||
|
import play.test.Helpers
|
||||||
|
import spock.lang.Shared
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class PlayWSClientTest extends HttpClientTest {
|
||||||
|
@Shared
|
||||||
|
def application = new FakeApplication(
|
||||||
|
new File("."),
|
||||||
|
FakeApplication.getClassLoader(),
|
||||||
|
[
|
||||||
|
"ws.timeout.connection": CONNECT_TIMEOUT_MS,
|
||||||
|
"ws.timeout.request" : READ_TIMEOUT_MS
|
||||||
|
],
|
||||||
|
Collections.emptyList(),
|
||||||
|
new GlobalSettings()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
def client
|
||||||
|
|
||||||
|
def setupSpec() {
|
||||||
|
Helpers.start(application)
|
||||||
|
client = WS.client()
|
||||||
|
}
|
||||||
|
|
||||||
|
def cleanupSpec() {
|
||||||
|
Helpers.stop(application)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
|
def request = client.url(uri.toString())
|
||||||
|
headers.entrySet().each {
|
||||||
|
request.setHeader(it.key, it.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
def status = request.execute(method).map({
|
||||||
|
callback?.call()
|
||||||
|
it
|
||||||
|
}).map({
|
||||||
|
it.status
|
||||||
|
})
|
||||||
|
return status.get(1, TimeUnit.SECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRedirects() {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testConnectionFailure() {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// On connection failures the operation and resource names end up different from expected.
|
||||||
|
// This would require a lot of changes to the base client test class to support
|
||||||
|
// span.operationName = "netty.connect"
|
||||||
|
// span.resourceName = "netty.connect"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTestAdvice;
|
||||||
|
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||||
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public class NettyServerTestInstrumentation implements Instrumenter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AgentBuilder instrument(final AgentBuilder agentBuilder) {
|
||||||
|
return agentBuilder
|
||||||
|
.type(named("org.jboss.netty.handler.codec.http.HttpRequestDecoder"))
|
||||||
|
.transform(
|
||||||
|
new AgentBuilder.Transformer.ForAdvice()
|
||||||
|
.advice(
|
||||||
|
named("createMessage"),
|
||||||
|
HttpServerTestAdvice.ServerEntryAdvice.class.getName()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import play.api.test.TestServer
|
||||||
|
|
||||||
|
class PlayAsyncServerTest extends PlayServerTest {
|
||||||
|
@Override
|
||||||
|
TestServer startServer(int port) {
|
||||||
|
def server = AsyncServer.server(port)
|
||||||
|
server.start()
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import io.opentelemetry.auto.instrumentation.api.MoreTags
|
||||||
|
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||||
|
import io.opentelemetry.auto.test.asserts.TraceAssert
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||||
|
import io.opentelemetry.sdk.trace.data.SpanData
|
||||||
|
import play.api.test.TestServer
|
||||||
|
|
||||||
|
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||||
|
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
|
||||||
|
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCCESS
|
||||||
|
import static io.opentelemetry.trace.Span.Kind.INTERNAL
|
||||||
|
|
||||||
|
class PlayServerTest extends HttpServerTest<TestServer> {
|
||||||
|
@Override
|
||||||
|
TestServer startServer(int port) {
|
||||||
|
def server = SyncServer.server(port)
|
||||||
|
server.start()
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void stopServer(TestServer server) {
|
||||||
|
server.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't have instrumentation for this version of netty yet
|
||||||
|
@Override
|
||||||
|
boolean hasHandlerSpan() {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint = SUCCESS) {
|
||||||
|
trace.span(index) {
|
||||||
|
operationName "play.request"
|
||||||
|
spanKind INTERNAL
|
||||||
|
errored endpoint == ERROR || endpoint == EXCEPTION
|
||||||
|
childOf((SpanData) parent)
|
||||||
|
tags {
|
||||||
|
"$MoreTags.NET_PEER_IP" { it == null || it == "127.0.0.1" } // Optional
|
||||||
|
"$Tags.HTTP_URL" String
|
||||||
|
"$Tags.HTTP_METHOD" String
|
||||||
|
"$Tags.HTTP_STATUS" Long
|
||||||
|
if (endpoint == EXCEPTION) {
|
||||||
|
errorTags(Exception, EXCEPTION.body)
|
||||||
|
}
|
||||||
|
if (endpoint.query) {
|
||||||
|
"$MoreTags.HTTP_QUERY" endpoint.query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint._
|
||||||
|
import play.api.mvc.{Action, Handler, Results}
|
||||||
|
import play.api.test.{FakeApplication, TestServer}
|
||||||
|
|
||||||
|
import scala.concurrent.Future
|
||||||
|
|
||||||
|
object AsyncServer {
|
||||||
|
val routes: PartialFunction[(String, String), Handler] = {
|
||||||
|
case ("GET", "/success") => Action.async { request => HttpServerTest.controller(SUCCESS, new AsyncControllerClosureAdapter(Future.successful(Results.Status(SUCCESS.getStatus).apply(SUCCESS.getBody)))) }
|
||||||
|
case ("GET", "/redirect") => Action.async { request => HttpServerTest.controller(REDIRECT, new AsyncControllerClosureAdapter(Future.successful(Results.Redirect(REDIRECT.getBody, REDIRECT.getStatus)))) }
|
||||||
|
case ("GET", "/query") => Action.async { result => HttpServerTest.controller(QUERY_PARAM, new AsyncControllerClosureAdapter(Future.successful(Results.Status(QUERY_PARAM.getStatus).apply(QUERY_PARAM.getBody)))) }
|
||||||
|
case ("GET", "/error-status") => Action.async { result => HttpServerTest.controller(ERROR, new AsyncControllerClosureAdapter(Future.successful(Results.Status(ERROR.getStatus).apply(ERROR.getBody)))) }
|
||||||
|
case ("GET", "/exception") => Action.async { result =>
|
||||||
|
HttpServerTest.controller(EXCEPTION, new AsyncBlockClosureAdapter(() => {
|
||||||
|
throw new Exception(EXCEPTION.getBody)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def server(port: Int): TestServer = {
|
||||||
|
TestServer(port, FakeApplication(withGlobal = Some(new Settings()), withRoutes = routes))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import play.api.mvc.Result
|
||||||
|
|
||||||
|
import scala.concurrent.Future
|
||||||
|
|
||||||
|
class ControllerClosureAdapter(response: Result) extends Closure[Result] {
|
||||||
|
override def call(): Result = response
|
||||||
|
}
|
||||||
|
|
||||||
|
class BlockClosureAdapter(block: () => Result) extends Closure[Result] {
|
||||||
|
override def call(): Result = block()
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncControllerClosureAdapter(response: Future[Result]) extends Closure[Future[Result]] {
|
||||||
|
override def call(): Future[Result] = response
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncBlockClosureAdapter(block: () => Future[Result]) extends Closure[Future[Result]] {
|
||||||
|
override def call(): Future[Result] = block()
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import play.api.GlobalSettings
|
||||||
|
import play.api.mvc.{RequestHeader, Result, Results}
|
||||||
|
|
||||||
|
import scala.concurrent.Future
|
||||||
|
|
||||||
|
class Settings extends GlobalSettings {
|
||||||
|
override def onError(request: RequestHeader, ex: Throwable): Future[Result] = {
|
||||||
|
Future.successful(Results.InternalServerError(ex.getCause.getMessage))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, 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 server
|
||||||
|
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||||
|
import io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint._
|
||||||
|
import play.api.mvc.{Action, Handler, Results}
|
||||||
|
import play.api.test.{FakeApplication, TestServer}
|
||||||
|
|
||||||
|
object SyncServer {
|
||||||
|
val routes: PartialFunction[(String, String), Handler] = {
|
||||||
|
case ("GET", "/success") => Action { request =>
|
||||||
|
HttpServerTest.controller(SUCCESS, new ControllerClosureAdapter(Results.Status(SUCCESS.getStatus).apply(SUCCESS.getBody)))
|
||||||
|
}
|
||||||
|
case ("GET", "/redirect") => Action { request =>
|
||||||
|
HttpServerTest.controller(REDIRECT, new ControllerClosureAdapter(Results.Redirect(REDIRECT.getBody, REDIRECT.getStatus)))
|
||||||
|
}
|
||||||
|
case ("GET", "/query") => Action { request =>
|
||||||
|
HttpServerTest.controller(QUERY_PARAM, new ControllerClosureAdapter(Results.Status(QUERY_PARAM.getStatus).apply(QUERY_PARAM.getBody)))
|
||||||
|
}
|
||||||
|
case ("GET", "/error-status") => Action { request =>
|
||||||
|
HttpServerTest.controller(ERROR, new ControllerClosureAdapter(Results.Status(ERROR.getStatus).apply(ERROR.getBody)))
|
||||||
|
}
|
||||||
|
case ("GET", "/exception") => Action { request =>
|
||||||
|
HttpServerTest.controller(EXCEPTION, new BlockClosureAdapter(() => {
|
||||||
|
throw new Exception(EXCEPTION.getBody)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def server(port: Int): TestServer = {
|
||||||
|
TestServer(port, FakeApplication(withGlobal = Some(new Settings()), withRoutes = routes))
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,9 +20,11 @@ import play.libs.ws.WS
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
import spock.lang.Subject
|
import spock.lang.Subject
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
// Play 2.6+ uses a separately versioned client that shades the underlying dependency
|
// Play 2.6+ uses a separately versioned client that shades the underlying dependency
|
||||||
// This means our built in instrumentation won't work.
|
// This means our built in instrumentation won't work.
|
||||||
|
@Timeout(5)
|
||||||
class PlayWSClientTest extends HttpClientTest {
|
class PlayWSClientTest extends HttpClientTest {
|
||||||
@Subject
|
@Subject
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -54,4 +56,9 @@ class PlayWSClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,11 @@ import ratpack.http.client.HttpClient
|
||||||
import ratpack.test.exec.ExecHarness
|
import ratpack.test.exec.ExecHarness
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
@Timeout(5)
|
||||||
class RatpackHttpClientTest extends HttpClientTest {
|
class RatpackHttpClientTest extends HttpClientTest {
|
||||||
|
|
||||||
@AutoCleanup
|
@AutoCleanup
|
||||||
|
@ -29,12 +33,16 @@ class RatpackHttpClientTest extends HttpClientTest {
|
||||||
ExecHarness exec = ExecHarness.harness()
|
ExecHarness exec = ExecHarness.harness()
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
def client = HttpClient.of {}
|
def client = HttpClient.of {
|
||||||
|
it.readTimeout(Duration.ofSeconds(2))
|
||||||
|
// Connect timeout added in 1.5
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
ExecResult<Integer> result = exec.yield {
|
ExecResult<Integer> result = exec.yield {
|
||||||
def resp = client.request(uri) { spec ->
|
def resp = client.request(uri) { spec ->
|
||||||
|
spec.connectTimeout(Duration.ofSeconds(2))
|
||||||
spec.method(method)
|
spec.method(method)
|
||||||
spec.headers { headersSpec ->
|
spec.headers { headersSpec ->
|
||||||
headers.entrySet().each {
|
headers.entrySet().each {
|
||||||
|
@ -59,4 +67,9 @@ class RatpackHttpClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,14 @@ import org.springframework.web.reactive.function.client.ClientResponse
|
||||||
import org.springframework.web.reactive.function.client.WebClient
|
import org.springframework.web.reactive.function.client.WebClient
|
||||||
import spock.lang.Ignore
|
import spock.lang.Ignore
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
import spock.lang.Timeout
|
||||||
|
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||||
|
|
||||||
// FIXME this instrumentation is not currently reliable and so is currently disabled
|
// FIXME this instrumentation is not currently reliable and so is currently disabled
|
||||||
// see DefaultWebClientInstrumentation and DefaultWebClientAdvice
|
// see DefaultWebClientInstrumentation and DefaultWebClientAdvice
|
||||||
@Ignore
|
@Ignore
|
||||||
|
@Timeout(5)
|
||||||
class SpringWebfluxHttpClientTest extends HttpClientTest {
|
class SpringWebfluxHttpClientTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -93,4 +95,9 @@ class SpringWebfluxHttpClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: figure out how to configure timeouts.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package client
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import io.vertx.core.Vertx
|
import io.vertx.core.Vertx
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
import io.vertx.core.http.HttpClient
|
import io.vertx.core.http.HttpClientOptions
|
||||||
import io.vertx.core.http.HttpClientResponse
|
import io.vertx.core.http.HttpClientResponse
|
||||||
import io.vertx.core.http.HttpMethod
|
import io.vertx.core.http.HttpMethod
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
@ -30,9 +30,11 @@ import java.util.concurrent.CompletableFuture
|
||||||
class VertxHttpClientTest extends HttpClientTest {
|
class VertxHttpClientTest extends HttpClientTest {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
def vertx = Vertx.vertx(new VertxOptions())
|
||||||
@Shared
|
@Shared
|
||||||
HttpClient httpClient = vertx.createHttpClient()
|
def clientOptions = new HttpClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||||
|
@Shared
|
||||||
|
def httpClient = vertx.createHttpClient(clientOptions)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
|
@ -57,4 +59,9 @@ class VertxHttpClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: figure out how to configure timeouts.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import io.vertx.circuitbreaker.CircuitBreakerOptions
|
import io.vertx.circuitbreaker.CircuitBreakerOptions
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
import io.vertx.core.http.HttpMethod
|
import io.vertx.core.http.HttpMethod
|
||||||
|
import io.vertx.ext.web.client.WebClientOptions
|
||||||
import io.vertx.reactivex.circuitbreaker.CircuitBreaker
|
import io.vertx.reactivex.circuitbreaker.CircuitBreaker
|
||||||
import io.vertx.reactivex.core.Vertx
|
import io.vertx.reactivex.core.Vertx
|
||||||
import io.vertx.reactivex.ext.web.client.WebClient
|
import io.vertx.reactivex.ext.web.client.WebClient
|
||||||
|
@ -33,7 +34,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
|
||||||
@Shared
|
@Shared
|
||||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
Vertx vertx = Vertx.vertx(new VertxOptions())
|
||||||
@Shared
|
@Shared
|
||||||
WebClient client = WebClient.create(vertx)
|
def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||||
|
@Shared
|
||||||
|
WebClient client = WebClient.create(vertx, clientOptions)
|
||||||
@Shared
|
@Shared
|
||||||
CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx,
|
CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx,
|
||||||
new CircuitBreakerOptions()
|
new CircuitBreakerOptions()
|
||||||
|
@ -73,4 +76,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: figure out how to configure timeouts.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package client
|
||||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
import io.vertx.core.http.HttpMethod
|
import io.vertx.core.http.HttpMethod
|
||||||
|
import io.vertx.ext.web.client.WebClientOptions
|
||||||
import io.vertx.reactivex.core.Vertx
|
import io.vertx.reactivex.core.Vertx
|
||||||
import io.vertx.reactivex.ext.web.client.WebClient
|
import io.vertx.reactivex.ext.web.client.WebClient
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
@ -29,7 +30,9 @@ class VertxRxWebClientTest extends HttpClientTest {
|
||||||
@Shared
|
@Shared
|
||||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
Vertx vertx = Vertx.vertx(new VertxOptions())
|
||||||
@Shared
|
@Shared
|
||||||
WebClient client = WebClient.create(vertx)
|
def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||||
|
@Shared
|
||||||
|
WebClient client = WebClient.create(vertx, clientOptions)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||||
|
@ -52,4 +55,9 @@ class VertxRxWebClientTest extends HttpClientTest {
|
||||||
boolean testConnectionFailure() {
|
boolean testConnectionFailure() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
// FIXME: figure out how to configure timeouts.
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ include ':instrumentation:netty:netty-4.0'
|
||||||
include ':instrumentation:netty:netty-4.1'
|
include ':instrumentation:netty:netty-4.1'
|
||||||
include ':instrumentation:okhttp-3.0'
|
include ':instrumentation:okhttp-3.0'
|
||||||
include ':instrumentation:opentelemetry-api-0.3'
|
include ':instrumentation:opentelemetry-api-0.3'
|
||||||
|
include ':instrumentation:play:play-2.3'
|
||||||
include ':instrumentation:play:play-2.4'
|
include ':instrumentation:play:play-2.4'
|
||||||
include ':instrumentation:play:play-2.6'
|
include ':instrumentation:play:play-2.6'
|
||||||
include ':instrumentation:play-ws:play-ws-1.0'
|
include ':instrumentation:play-ws:play-ws-1.0'
|
||||||
|
|
|
@ -21,7 +21,7 @@ import spock.lang.Specification
|
||||||
|
|
||||||
abstract class AbstractSmokeTest extends Specification {
|
abstract class AbstractSmokeTest extends Specification {
|
||||||
|
|
||||||
public static final PROFILING_API_KEY = "org2_api_key"
|
public static final API_KEY = "some-api-key"
|
||||||
public static final PROFILING_START_DELAY_SECONDS = 1
|
public static final PROFILING_START_DELAY_SECONDS = 1
|
||||||
public static final int PROFILING_RECORDING_UPLOAD_PERIOD_SECONDS = 5
|
public static final int PROFILING_RECORDING_UPLOAD_PERIOD_SECONDS = 5
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ abstract class AbstractSmokeTest extends Specification {
|
||||||
ProcessBuilder processBuilder = createProcessBuilder()
|
ProcessBuilder processBuilder = createProcessBuilder()
|
||||||
|
|
||||||
processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home"))
|
processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home"))
|
||||||
processBuilder.environment().put("DD_PROFILING_APIKEY", PROFILING_API_KEY)
|
processBuilder.environment().put("DD_API_KEY", API_KEY)
|
||||||
|
|
||||||
processBuilder.redirectErrorStream(true)
|
processBuilder.redirectErrorStream(true)
|
||||||
logfile = new File("${buildDirectory}/reports/testProcess.${this.getClass().getName()}.log")
|
logfile = new File("${buildDirectory}/reports/testProcess.${this.getClass().getName()}.log")
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.opentelemetry.auto.test.AgentTestRunner
|
||||||
import io.opentelemetry.auto.test.asserts.TraceAssert
|
import io.opentelemetry.auto.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
import io.opentelemetry.sdk.trace.data.SpanData
|
||||||
import spock.lang.AutoCleanup
|
import spock.lang.AutoCleanup
|
||||||
|
import spock.lang.Requires
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
|
@ -40,6 +41,8 @@ import static org.junit.Assume.assumeTrue
|
||||||
@Unroll
|
@Unroll
|
||||||
abstract class HttpClientTest extends AgentTestRunner {
|
abstract class HttpClientTest extends AgentTestRunner {
|
||||||
protected static final BODY_METHODS = ["POST", "PUT"]
|
protected static final BODY_METHODS = ["POST", "PUT"]
|
||||||
|
protected static final CONNECT_TIMEOUT_MS = 1000
|
||||||
|
protected static final READ_TIMEOUT_MS = 2000
|
||||||
|
|
||||||
@AutoCleanup
|
@AutoCleanup
|
||||||
@Shared
|
@Shared
|
||||||
|
@ -250,8 +253,7 @@ abstract class HttpClientTest extends AgentTestRunner {
|
||||||
|
|
||||||
def "basic #method request with circular redirects"() {
|
def "basic #method request with circular redirects"() {
|
||||||
given:
|
given:
|
||||||
assumeTrue(testRedirects())
|
assumeTrue(testRedirects() && testCircularRedirects())
|
||||||
assumeTrue(testCircularRedirects())
|
|
||||||
def uri = server.address.resolve("/circular-redirect")
|
def uri = server.address.resolve("/circular-redirect")
|
||||||
|
|
||||||
when:
|
when:
|
||||||
|
@ -300,6 +302,77 @@ abstract class HttpClientTest extends AgentTestRunner {
|
||||||
method = "GET"
|
method = "GET"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "connection error dropped request"() {
|
||||||
|
given:
|
||||||
|
assumeTrue(testRemoteConnection())
|
||||||
|
// https://stackoverflow.com/a/100859
|
||||||
|
def uri = new URI("http://www.google.com:81/")
|
||||||
|
|
||||||
|
when:
|
||||||
|
runUnderTrace("parent") {
|
||||||
|
doRequest(method, uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
then:
|
||||||
|
def ex = thrown(Exception)
|
||||||
|
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2 + extraClientSpans()) {
|
||||||
|
basicSpan(it, 0, "parent", null, thrownException)
|
||||||
|
clientSpan(it, 1, span(0), method, false, uri, null, thrownException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
where:
|
||||||
|
method = "HEAD"
|
||||||
|
}
|
||||||
|
|
||||||
|
def "connection error non routable address"() {
|
||||||
|
given:
|
||||||
|
assumeTrue(testRemoteConnection())
|
||||||
|
def uri = new URI("https://192.0.2.1/")
|
||||||
|
|
||||||
|
when:
|
||||||
|
runUnderTrace("parent") {
|
||||||
|
doRequest(method, uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
then:
|
||||||
|
def ex = thrown(Exception)
|
||||||
|
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2 + extraClientSpans()) {
|
||||||
|
basicSpan(it, 0, "parent", null, thrownException)
|
||||||
|
clientSpan(it, 1, span(0), method, false, uri, null, thrownException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
where:
|
||||||
|
method = "HEAD"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IBM JVM has different protocol support for TLS
|
||||||
|
@Requires({ !System.getProperty("java.vm.name").contains("IBM J9 VM") })
|
||||||
|
def "test https request"() {
|
||||||
|
given:
|
||||||
|
assumeTrue(testRemoteConnection())
|
||||||
|
def uri = new URI("https://www.google.com/")
|
||||||
|
|
||||||
|
when:
|
||||||
|
def status = doRequest(method, uri)
|
||||||
|
|
||||||
|
then:
|
||||||
|
status == 200
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 1 + extraClientSpans()) {
|
||||||
|
clientSpan(it, 0, null, method, false, uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
where:
|
||||||
|
method = "HEAD"
|
||||||
|
}
|
||||||
|
|
||||||
// parent span must be cast otherwise it breaks debugging classloading (junit loads it early)
|
// parent span must be cast otherwise it breaks debugging classloading (junit loads it early)
|
||||||
void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) {
|
void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) {
|
||||||
trace.span(index) {
|
trace.span(index) {
|
||||||
|
@ -312,9 +385,9 @@ abstract class HttpClientTest extends AgentTestRunner {
|
||||||
spanKind CLIENT
|
spanKind CLIENT
|
||||||
errored exception != null
|
errored exception != null
|
||||||
tags {
|
tags {
|
||||||
"$MoreTags.NET_PEER_NAME" "localhost"
|
"$MoreTags.NET_PEER_NAME" uri.host
|
||||||
"$MoreTags.NET_PEER_IP" { it == null || it == "127.0.0.1" } // Optional
|
"$MoreTags.NET_PEER_IP" { it == null || it == "127.0.0.1" } // Optional
|
||||||
"$MoreTags.NET_PEER_PORT" uri.port
|
"$MoreTags.NET_PEER_PORT" uri.port > 0 ? uri.port : { it == null || it == 443 } // Optional
|
||||||
"$Tags.HTTP_URL" { it == "${uri}" || it == "${removeFragment(uri)}" }
|
"$Tags.HTTP_URL" { it == "${uri}" || it == "${removeFragment(uri)}" }
|
||||||
"$Tags.HTTP_METHOD" method
|
"$Tags.HTTP_METHOD" method
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -366,6 +439,10 @@ abstract class HttpClientTest extends AgentTestRunner {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean testRemoteConnection() {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
boolean testCallbackWithParent() {
|
boolean testCallbackWithParent() {
|
||||||
// FIXME: this hack is here because callback with parent is broken in play-ws when the stream()
|
// FIXME: this hack is here because callback with parent is broken in play-ws when the stream()
|
||||||
// function is used. There is no way to stop a test from a derived class hence the flag
|
// function is used. There is no way to stop a test from a derived class hence the flag
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package io.opentelemetry.auto.test.base
|
package io.opentelemetry.auto.test.base
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level
|
||||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpServerDecorator
|
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpServerDecorator
|
||||||
import io.opentelemetry.auto.instrumentation.api.MoreTags
|
import io.opentelemetry.auto.instrumentation.api.MoreTags
|
||||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||||
|
@ -28,6 +29,8 @@ import okhttp3.HttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
import spock.lang.Unroll
|
import spock.lang.Unroll
|
||||||
|
|
||||||
|
@ -48,6 +51,11 @@ import static org.junit.Assume.assumeTrue
|
||||||
@Unroll
|
@Unroll
|
||||||
abstract class HttpServerTest<SERVER> extends AgentTestRunner {
|
abstract class HttpServerTest<SERVER> extends AgentTestRunner {
|
||||||
|
|
||||||
|
public static final Logger SERVER_LOGGER = LoggerFactory.getLogger("http-server")
|
||||||
|
static {
|
||||||
|
((ch.qos.logback.classic.Logger) SERVER_LOGGER).setLevel(Level.DEBUG)
|
||||||
|
}
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
SERVER server
|
SERVER server
|
||||||
@Shared
|
@Shared
|
||||||
|
|
|
@ -41,17 +41,14 @@ class TestHttpServer implements AutoCloseable {
|
||||||
|
|
||||||
private static final Tracer TRACER = OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto")
|
private static final Tracer TRACER = OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto")
|
||||||
|
|
||||||
static TestHttpServer httpServer(boolean start = true,
|
static TestHttpServer httpServer(@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
|
||||||
@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
|
|
||||||
|
|
||||||
def server = new TestHttpServer()
|
def server = new TestHttpServer()
|
||||||
def clone = (Closure) spec.clone()
|
def clone = (Closure) spec.clone()
|
||||||
clone.delegate = server
|
clone.delegate = server
|
||||||
clone.resolveStrategy = Closure.DELEGATE_FIRST
|
clone.resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
clone(server)
|
clone(server)
|
||||||
if (start) {
|
|
||||||
server.start()
|
server.start()
|
||||||
}
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@ package io.opentelemetry.auto.test.utils;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class was moved from groovy to java because groovy kept trying to introspect on the
|
* This class was moved from groovy to java because groovy kept trying to introspect on the
|
||||||
|
@ -24,9 +28,29 @@ import okhttp3.OkHttpClient;
|
||||||
*/
|
*/
|
||||||
public class OkHttpUtils {
|
public class OkHttpUtils {
|
||||||
|
|
||||||
|
private static final Logger CLIENT_LOGGER = LoggerFactory.getLogger("http-client");
|
||||||
|
|
||||||
|
static {
|
||||||
|
((ch.qos.logback.classic.Logger) CLIENT_LOGGER).setLevel(ch.qos.logback.classic.Level.DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final HttpLoggingInterceptor LOGGING_INTERCEPTOR =
|
||||||
|
new HttpLoggingInterceptor(
|
||||||
|
new HttpLoggingInterceptor.Logger() {
|
||||||
|
@Override
|
||||||
|
public void log(final String message) {
|
||||||
|
CLIENT_LOGGER.debug(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static {
|
||||||
|
LOGGING_INTERCEPTOR.setLevel(Level.BASIC);
|
||||||
|
}
|
||||||
|
|
||||||
static OkHttpClient.Builder clientBuilder() {
|
static OkHttpClient.Builder clientBuilder() {
|
||||||
final TimeUnit unit = TimeUnit.MINUTES;
|
final TimeUnit unit = TimeUnit.MINUTES;
|
||||||
return new OkHttpClient.Builder()
|
return new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(LOGGING_INTERCEPTOR)
|
||||||
.connectTimeout(1, unit)
|
.connectTimeout(1, unit)
|
||||||
.writeTimeout(1, unit)
|
.writeTimeout(1, unit)
|
||||||
.readTimeout(1, unit);
|
.readTimeout(1, unit);
|
||||||
|
|
|
@ -31,12 +31,12 @@ class ServerTest extends AgentTestRunner {
|
||||||
|
|
||||||
def "test server lifecycle"() {
|
def "test server lifecycle"() {
|
||||||
setup:
|
setup:
|
||||||
def server = httpServer(startAutomatically) {
|
def server = httpServer {
|
||||||
handlers {}
|
handlers {}
|
||||||
}
|
}
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
server.internalServer.isRunning() == startAutomatically
|
server.internalServer.isRunning()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
server.start()
|
server.start()
|
||||||
|
@ -57,16 +57,13 @@ class ServerTest extends AgentTestRunner {
|
||||||
server.internalServer.isRunning()
|
server.internalServer.isRunning()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
server.stop()
|
server.close()
|
||||||
|
|
||||||
then:
|
then:
|
||||||
!server.internalServer.isRunning()
|
!server.internalServer.isRunning()
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
server.stop()
|
server.close()
|
||||||
|
|
||||||
where:
|
|
||||||
startAutomatically << [true, false]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def "server 404's with no handlers"() {
|
def "server 404's with no handlers"() {
|
||||||
|
|
|
@ -26,6 +26,7 @@ dependencies {
|
||||||
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.11.0' // Last version to support Java7
|
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.11.0' // Last version to support Java7
|
||||||
|
|
||||||
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '8.0.0.v20110901'
|
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '8.0.0.v20110901'
|
||||||
|
compile group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: versions.okhttp
|
||||||
|
|
||||||
compile(project(':auto-tooling')) {
|
compile(project(':auto-tooling')) {
|
||||||
// including :opentelemetry-sdk-shaded-for-testing above instead
|
// including :opentelemetry-sdk-shaded-for-testing above instead
|
||||||
|
|
Loading…
Reference in New Issue