Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

package io.opentelemetry.api.incubator.config;

import static java.util.Collections.emptyList;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -18,6 +22,10 @@
*/
public class InstrumentationConfigUtil {

private static final List<String> DEFAULT_SENSITIVE_QUERY_PARAMETERS =
Collections.unmodifiableList(
Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));

/**
* Return a map representation of the peer service map entries in {@code
* .instrumentation.general.peer.service_mapping}, or null if none is configured.
Expand Down Expand Up @@ -52,67 +60,80 @@ public static Map<String, String> peerServiceMapping(ConfigProvider configProvid
}

/**
* Return {@code .instrumentation.general.http.client.request_captured_headers}, or null if none
* is configured.
* Return {@code .instrumentation.general.http.client.request_captured_headers}, or empty list if
* none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"client");
return configProvider
.getInstrumentationConfig()
.get("general")
.get("http")
.get("client")
.getScalarList("request_captured_headers", String.class, emptyList());
}

/**
* Return {@code .instrumentation.general.http.client.response_captured_headers}, or null if none
* is configured.
* Return {@code .instrumentation.general.http.client.response_captured_headers}, or empty list if
* none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"client");
return configProvider
.getInstrumentationConfig()
.get("general")
.get("http")
.get("client")
.getScalarList("response_captured_headers", String.class, emptyList());
}

/**
* Return {@code .instrumentation.general.http.server.request_captured_headers}, or null if none
* is configured.
* Return {@code .instrumentation.general.http.server.request_captured_headers}, or empty list if
* none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpServerRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"server");
return configProvider
.getInstrumentationConfig()
.get("general")
.get("http")
.get("server")
.getScalarList("request_captured_headers", String.class, emptyList());
}

/**
* Return {@code .instrumentation.general.http.server.response_captured_headers}, or null if none
* is configured.
* Return {@code .instrumentation.general.http.server.response_captured_headers}, or empty list if
* none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpServerResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"server");
return configProvider
.getInstrumentationConfig()
.get("general")
.get("http")
.get("server")
.getScalarList("response_captured_headers", String.class, emptyList());
}

/**
* Return {@code .instrumentation.general.sanitization.url.sensitive_query_parameters}, or the
* default list (currently {@code AWSAccessKeyId}, {@code Signature}, {@code sig}, {@code
* X-Goog-Signature}) if none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
public static List<String> sensitiveQueryParameters(ConfigProvider configProvider) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you like these helper functions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good question, I guess not really 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought is that they would be helpful for instrumentation conform to these general config options. All the instrumentation in opentelemetry-java-instrumentation can leverage shared utils in that repo to do this type of thing, so its really only native instrumentation that would stand to benefit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like the explicitness of seeing the yaml path in the code.

But can see them being useful.

What's your thought about these methods handling default values (and never returning null)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's your thought about these methods handling default values (and never returning null)?

I support. Their value proposition decreases if the caller still has to be aware of the default semantics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I didn't realize that the defaults would be defined per applicable semantic convention: https://github.com/open-telemetry/opentelemetry-configuration/pull/531/changes#diff-d77a4fdd93a40cc4f4e39de58670cb50a8f0cfed9d012f4960d773a9f50642d6R165

Does this suggest that the sensitive_query_parameters property is better suited under .instrumentation/development.general.http instead of .instrumentation/development.general.sanitization.url?

Or the helper function needs to be renamed to reflect that this is sensitive query parameters for HTTP instrumentation.

return configProvider
.getInstrumentationConfig()
.get("general")
.get("sanitization")
.get("url")
.getScalarList(
"sensitive_query_parameters", String.class, DEFAULT_SENSITIVE_QUERY_PARAMETERS);
}

/**
Expand All @@ -133,7 +154,10 @@ public static DeclarativeConfigProperties javaInstrumentationConfig(
* {@code segments}, or if {@code accessor} returns null.
*
* <p>See other methods in {@link InstrumentationConfigUtil} for usage examples.
*
* @deprecated Use {@link DeclarativeConfigProperties#get(String)} to walk segments.
*/
@Deprecated
@Nullable
public static <T> T getOrNull(
ConfigProvider configProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class InstrumentationConfigUtilTest {
+ " response_captured_headers:\n"
+ " - server-response-header1\n"
+ " - server-response-header2\n"
+ " sanitization:\n"
+ " url:\n"
+ " sensitive_query_parameters:\n"
+ " - AWSAccessKeyId\n"
+ " - Signature\n"
+ " - sig\n"
+ " - X-Goog-Signature\n"
+ " java:\n"
+ " example:\n"
+ " property: \"value\"";
Expand All @@ -58,6 +65,8 @@ class InstrumentationConfigUtilTest {
toConfigProvider("instrumentation/development:\n general:\n");
private static final ConfigProvider emptyHttpConfigProvider =
toConfigProvider("instrumentation/development:\n general:\n http:\n");
private static final ConfigProvider emptySanitizationConfigProvider =
toConfigProvider("instrumentation/development:\n general:\n sanitization:\n");

private static ConfigProvider toConfigProvider(String configYaml) {
return SdkConfigProvider.create(
Expand All @@ -84,12 +93,12 @@ void httpClientRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
.isEmpty();
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
.isEmpty();
assertThat(InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
.isEmpty();
}

@Test
Expand All @@ -100,12 +109,12 @@ void httpClientResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
.isEmpty();
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
.isEmpty();
assertThat(InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
.isEmpty();
}

@Test
Expand All @@ -116,12 +125,12 @@ void httpServerRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
.isEmpty();
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
.isEmpty();
assertThat(InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
.isEmpty();
}

@Test
Expand All @@ -132,12 +141,25 @@ void httpServerResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpServerResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
.isEmpty();
assertThat(
InstrumentationConfigUtil.httpServerResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
.isEmpty();
assertThat(InstrumentationConfigUtil.httpServerResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
.isEmpty();
}

@Test
void sensitiveQueryParameters() {
assertThat(InstrumentationConfigUtil.sensitiveQueryParameters(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));
assertThat(
InstrumentationConfigUtil.sensitiveQueryParameters(emptyInstrumentationConfigProvider))
.isEqualTo(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));
assertThat(InstrumentationConfigUtil.sensitiveQueryParameters(emptyGeneralConfigProvider))
.isEqualTo(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));
assertThat(InstrumentationConfigUtil.sensitiveQueryParameters(emptySanitizationConfigProvider))
.isEqualTo(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));
}

@Test
Expand Down
Loading