Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Headers as Attributes for Otel traces #673

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<groupId>org.mule.connectors</groupId>
<artifactId>mule-http-connector</artifactId>
<packaging>mule-extension</packaging>
<version>1.8.0-SNAPSHOT</version>
<version>1.8.1-SNAPSHOT</version>
panizzag marked this conversation as resolved.
Show resolved Hide resolved

<name>HTTP Connector</name>
<description>A Mule extension that provides HTTP server and client functionality</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static org.mule.runtime.api.meta.ExpressionSupport.NOT_SUPPORTED;
import static org.mule.runtime.api.meta.ExpressionSupport.SUPPORTED;
import static org.mule.runtime.api.util.Preconditions.checkArgument;

import org.mule.extension.http.api.listener.headers.HttpHeadersException;
Expand Down Expand Up @@ -66,12 +67,25 @@ public class HttpListenerConfig implements Initialisable {
@Expression(NOT_SUPPORTED)
private boolean rejectInvalidTransferEncoding;

/**
* W-12558102
* Indicates what headers should not be exported as attributes when generating Open Telemetry traces. By default, common headers associated with credentials are skipped.
*
* @since 1.8.0
*/
@Parameter
@Optional(defaultValue = "client_id, client_secret, Authorization")
@Expression(SUPPORTED)
private String skipHeadersOnTracing;

private HttpHeadersValidator httpHeaderValidators;

@Override
public void initialise() throws InitialisationException {
basePath = sanitizePathWithStartSlash(this.basePath);
httpHeaderValidators = new InvalidTransferEncodingValidator(rejectInvalidTransferEncoding);
//W-12558102
skipHeadersOnTracing = this.skipHeadersOnTracing;
panizzag marked this conversation as resolved.
Show resolved Hide resolved
}

public ListenerPath getFullListenerPath(String listenerPath) {
Expand Down Expand Up @@ -99,4 +113,9 @@ public java.util.Optional<HttpListenerInterceptor> getInterceptor() {
public void validateHeaders(MultiMap<String, String> headers) throws HttpHeadersException {
httpHeaderValidators.validateHeaders(headers);
}

//W-12558102
public String getSkipHeadersOnTracing() {
return skipHeadersOnTracing;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ public void handleRequest(HttpRequestContext requestContext, HttpResponseReadyCa
forwardCompatibilityHelper.get().getDistributedTraceContextManager(context);
distributedTraceContextManager.setRemoteTraceContextMap(headers);
getHttpListenerCurrentSpanCustomizer(result.getAttributes().get(), server.getServerAddress().getIp(),
server.getServerAddress().getPort())
server.getServerAddress().getPort(), config.getSkipHeadersOnTracing())
.customizeSpan(distributedTraceContextManager);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
import org.mule.extension.http.api.HttpRequestAttributes;
import org.mule.extension.http.internal.request.profiling.tracing.HttpCurrentSpanCustomizer;
import org.mule.sdk.api.runtime.source.DistributedTraceContextManager;
import org.mule.runtime.api.util.MultiMap;
panizzag marked this conversation as resolved.
Show resolved Hide resolved
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Arrays;

import org.slf4j.Logger;

Expand All @@ -41,16 +46,24 @@ public class HttpListenerCurrentSpanCustomizer extends HttpCurrentSpanCustomizer
private final String host;
private final int port;

private HttpListenerCurrentSpanCustomizer(HttpRequestAttributes attributes, String host, int port) {
//W-12558102
Copy link
Contributor

Choose a reason for hiding this comment

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

I would remove the comment for the feature.

Copy link
Author

Choose a reason for hiding this comment

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

Done. Should I remove all the other similar comments?

private final List<String> skipAttributesList;

private HttpListenerCurrentSpanCustomizer(HttpRequestAttributes attributes, String host, int port, String skipAttributes) {
this.attributes = attributes;
this.host = host;
this.port = port;
//W-12558102
this.skipAttributesList = Arrays.asList(skipAttributes.split(",", -1));
panizzag marked this conversation as resolved.
Show resolved Hide resolved
this.skipAttributesList.replaceAll(String::trim);
}

public static HttpCurrentSpanCustomizer getHttpListenerCurrentSpanCustomizer(HttpRequestAttributes attributes,
String host,
int port) {
return new HttpListenerCurrentSpanCustomizer(attributes, host, port);
int port,
//W-... gp
String skipAttributes) {
return new HttpListenerCurrentSpanCustomizer(attributes, host, port, skipAttributes);
}

@Override
Expand All @@ -62,11 +75,9 @@ public void customizeSpan(DistributedTraceContextManager distributedTraceContext
distributedTraceContextManager.addCurrentSpanAttribute(NET_HOST_NAME, host);
distributedTraceContextManager.addCurrentSpanAttribute(NET_HOST_PORT, valueOf(getURI().getPort()));
distributedTraceContextManager.addCurrentSpanAttribute(HTTP_SCHEME, attributes.getScheme());
String userAgent = attributes.getHeaders().get(USER_AGENT);

if (userAgent != null) {
distributedTraceContextManager.addCurrentSpanAttribute(HTTP_USER_AGENT, userAgent);
}
//W-12558102 - Parsing HTTP headers as Span Attributes
MultiMap<String, String> headers = getHeaders();
headers.keySet().forEach(key -> distributedTraceContextManager.addCurrentSpanAttribute(key, headers.get(key)));

} catch (Throwable e) {
LOGGER.warn("Error on setting listener span attributes.", e);
Expand Down Expand Up @@ -110,4 +121,20 @@ protected String getSpanKind() {
protected String getSpanName() {
return attributes.getListenerPath();
}

/**
* W-12558102
* This provides a transparent way to obtain the definitive list of headers to add in the spans associated with Otel tracing.
* This list will have all headers except those that have been skipped via the skipHeadersOnTracing property.
*/
@Override
public MultiMap<String, String> getHeaders() {
panizzag marked this conversation as resolved.
Show resolved Hide resolved
MultiMap<String, String> modifiedHeaders = new MultiMap<String, String>();
attributes.getHeaders().keySet().forEach(key -> {
if (!skipAttributesList.contains(key)) {
modifiedHeaders.put(key, attributes.getHeaders().get(key));
}
});
return modifiedHeaders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ public void doRequest(HttpExtensionClient client, HttpRequesterConfig config, St
authentication, injectedHeaders, requestCreator,
distributedTraceContextManager);

getHttpRequesterCurrentSpanCustomizer(httpRequester).customizeSpan(distributedTraceContextManager);
getHttpRequesterCurrentSpanCustomizer(httpRequester, config.getSkipHeadersOnTracing())
.customizeSpan(distributedTraceContextManager);

doRequestWithRetry(client, config, uri, method, streamingMode, sendBodyMode, followRedirects, authentication, resolvedTimeout,
responseValidator, transformationService, requestCreator, checkRetry, muleContext, scheduler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public class HttpRequesterConfig implements Initialisable, HttpRequesterCookieCo
@Placement(order = 3)
private ResponseSettings responseSettings;

//W-12558102
@ParameterGroup(name = "Tracing Settings")
@Placement(order = 4)
private TracingSettings tracingSettings;

@Inject
private MuleContext muleContext;
private CookieManager cookieManager;
Expand Down Expand Up @@ -93,6 +98,11 @@ public Integer getResponseTimeout() {
return responseSettings.getResponseTimeout();
}

//W-12558102
public String getSkipHeadersOnTracing() {
return tracingSettings.getSkipHeadersOnTracing();
}

@Override
public boolean isEnableCookies() {
return requestSettings.isEnableCookies();
Expand All @@ -116,6 +126,8 @@ public static class Builder {
private RequestUrlConfiguration urlConfiguration;
private RequestSettings requestSettings;
private ResponseSettings responseSettings;
//W-12558102
private TracingSettings tracingSettings;
private MuleContext muleContext;

private Builder() {}
Expand All @@ -135,6 +147,12 @@ public Builder withResponseSettings(ResponseSettings responseSettings) {
return this;
}

//W-12558102
public Builder withTracingSettings(TracingSettings tracingSettings) {
this.tracingSettings = tracingSettings;
return this;
}

public Builder withMuleContext(MuleContext muleContext) {
this.muleContext = muleContext;
return this;
Expand All @@ -149,6 +167,8 @@ public HttpRequesterConfig build() {
config.urlConfiguration = this.urlConfiguration;
config.requestSettings = this.requestSettings;
config.responseSettings = this.responseSettings;
//W-12558102
config.tracingSettings = this.tracingSettings;
config.muleContext = this.muleContext;
return config;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.extension.http.internal.request;

import static org.mule.runtime.api.meta.ExpressionSupport.SUPPORTED;

import org.mule.runtime.extension.api.annotation.Expression;
import org.mule.runtime.extension.api.annotation.param.Optional;
import org.mule.runtime.extension.api.annotation.param.Parameter;

/**
* Groups parameters which configure how a request is traced
*
* @since 1.0
*/
public final class TracingSettings {

/**
* Indicates what headers should not be exported as attributes when generating Open Telemetry traces. By default, common headers associated with credentials are skipped.
*
* @since 1.8.0
*/
@Parameter
@Optional(defaultValue = "client_id, client_secret, Authorization")
@Expression(SUPPORTED)
private String skipHeadersOnTracing;

public String getSkipHeadersOnTracing() {
return skipHeadersOnTracing;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {

private String skipHeadersOnTracing;

public Builder withFollowRedirects(String skipHeadersOnTracing) {
this.skipHeadersOnTracing = skipHeadersOnTracing;
return this;
}

public TracingSettings build() {
TracingSettings settings = new TracingSettings();
settings.skipHeadersOnTracing = this.skipHeadersOnTracing;
return settings;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.slf4j.LoggerFactory.getLogger;

import org.mule.sdk.api.runtime.source.DistributedTraceContextManager;
import org.mule.runtime.api.util.MultiMap;

import java.net.URI;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -78,4 +79,10 @@ protected String getSpanName() {
* @return the span kind
*/
protected abstract String getSpanKind();

/**
* W-12558102
* @return the headers for the http span.
*/
public abstract MultiMap<String, String> getHeaders();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
import org.mule.runtime.http.api.domain.HttpProtocol;
import org.mule.runtime.http.api.domain.message.request.HttpRequest;
import org.mule.sdk.api.runtime.source.DistributedTraceContextManager;
import org.mule.runtime.api.util.MultiMap;
import org.slf4j.Logger;

import java.net.URI;
import java.util.List;
import java.util.Arrays;

/**
* A customizer for the current span for HTTP Requests
Expand All @@ -38,17 +41,23 @@ public class HttpRequestCurrentSpanCustomizer extends HttpCurrentSpanCustomizer
public static final String PROTOCOL_VERSION_1_0 = "1.0";
public static final String PROTOCOL_VERSION_1_1 = "1.1";

//W-12558102
private final List<String> skipAttributesList;

/**
* @return a new instance of a {@link HttpRequestCurrentSpanCustomizer}.
*/
public static HttpCurrentSpanCustomizer getHttpRequesterCurrentSpanCustomizer(HttpRequest httpRequest) {
return new HttpRequestCurrentSpanCustomizer(httpRequest);
public static HttpCurrentSpanCustomizer getHttpRequesterCurrentSpanCustomizer(HttpRequest httpRequest, String skipAttributes) {
return new HttpRequestCurrentSpanCustomizer(httpRequest, skipAttributes);
}

private HttpRequest httpRequest;

private HttpRequestCurrentSpanCustomizer(HttpRequest httpRequest) {
private HttpRequestCurrentSpanCustomizer(HttpRequest httpRequest, String skipAttributes) {
this.httpRequest = httpRequest;
//W-12558102
this.skipAttributesList = Arrays.asList(skipAttributes.split(",", -1));
this.skipAttributesList.replaceAll(String::trim);
}

@Override
Expand All @@ -59,6 +68,10 @@ public void customizeSpan(DistributedTraceContextManager distributedTraceContext
distributedTraceContextManager.addCurrentSpanAttribute(HTTP_URL, getURI().toString());
distributedTraceContextManager.addCurrentSpanAttribute(NET_PEER_PORT, valueOf(getURI().getPort()));
distributedTraceContextManager.addCurrentSpanAttribute(NET_PEER_NAME, getURI().getHost());
//W-12558102 - Parsing HTTP headers as Span Attributes
MultiMap<String, String> headers = getHeaders();
headers.keySet().forEach(key -> distributedTraceContextManager.addCurrentSpanAttribute(key, headers.get(key)));

} catch (Throwable e) {
LOGGER.warn("Error on setting the request span attributes", e);
}
Expand Down Expand Up @@ -104,4 +117,20 @@ private static String getHttpProtocolVersionFrom(HttpProtocol protocol) {

return PROTOCOL_VERSION_1_1;
}

/**
* W-12558102
* This provides a transparent way to obtain the definitive list of headers to add in the spans associated with Otel tracing.
* This list will have all headers except those that have been skipped via the skipHeadersOnTracing property.
*/
@Override
public MultiMap<String, String> getHeaders() {
MultiMap<String, String> modifiedHeaders = new MultiMap<String, String>();
httpRequest.getHeaders().keySet().forEach(key -> {
if (!skipAttributesList.contains(key)) {
modifiedHeaders.put(key, httpRequest.getHeaders().get(key));
}
});
return modifiedHeaders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class HttpCurrentSpanCustomizerTestCase {
public static final String EXPECTED_PEER_NAME = "www.expectedhost.com";
public static final int TEST_PORT = 8080;
public static final String EXPECTED_SCHEME = HTTPS;
//W-12558102
public static final String SKIP_HEADERS_ATTRIBUTES = "";

@Test
@Description("The listener span customizer informs the distributed trace context manager the correct attributes/name")
Expand All @@ -74,7 +76,8 @@ public void listenerSpan() {
when(headers.get(USER_AGENT)).thenReturn(EXPECTED_USER_AGENT);
when(attributes.getLocalAddress()).thenReturn(LOCAL_ADDRESS);

HttpCurrentSpanCustomizer currentSpanCustomizer = getHttpListenerCurrentSpanCustomizer(attributes, TEST_HOST, TEST_PORT);
HttpCurrentSpanCustomizer currentSpanCustomizer =
getHttpListenerCurrentSpanCustomizer(attributes, TEST_HOST, TEST_PORT, SKIP_HEADERS_ATTRIBUTES);
DistributedTraceContextManager distributedTraceContextManager = mock(DistributedTraceContextManager.class);
currentSpanCustomizer.customizeSpan(distributedTraceContextManager);

Expand All @@ -99,7 +102,8 @@ public void requestSpan() throws Exception {
when(httpRequest.getUri()).thenReturn(uri);
when(httpRequest.getProtocol()).thenReturn(HTTP_1_1);

HttpCurrentSpanCustomizer httpCurrentSpanCustomizer = getHttpRequesterCurrentSpanCustomizer(httpRequest);
HttpCurrentSpanCustomizer httpCurrentSpanCustomizer =
getHttpRequesterCurrentSpanCustomizer(httpRequest, SKIP_HEADERS_ATTRIBUTES);
httpCurrentSpanCustomizer.customizeSpan(distributedTraceContextManager);

verify(distributedTraceContextManager).setCurrentSpanName(EXPECTED_SPAN_NAME);
Expand Down