Skip to content

Commit 94ac07b

Browse files
authored
add support for sse redirect and http proxy settings (#1718)
* add support for sse redirect, add v2.1/track for aad auth path and v2/track for non aad auth path * use lazyAzureHttpClient in telemetry channel * add logging policy to httppipeline and handle 401,403 in response * add 307 support
1 parent 9219bbf commit 94ac07b

File tree

4 files changed

+125
-11
lines changed

4 files changed

+125
-11
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/AiComponentInstaller.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,14 @@ private static void start(Instrumentation instrumentation) {
123123
validateProcessorConfiguration(config);
124124
config.preview.authentication.validate();
125125
//Inject authentication configuration
126-
Configuration.AadAuthentication authentication = config.preview.authentication;
127-
AadAuthentication.init(authentication.type, authentication.clientId, authentication.keePassDatabasePath,
128-
authentication.tenantId, authentication.clientSecret, authentication.authorityHost);
129-
126+
if(config.preview.authentication.enabled) {
127+
Configuration.AadAuthentication authentication = config.preview.authentication;
128+
AadAuthentication.init(authentication.type, authentication.clientId, authentication.keePassDatabasePath,
129+
authentication.tenantId, authentication.clientSecret, authentication.authorityHost);
130+
} else {
131+
// TODO revisit this, not ideal to initialize when authentication is disabled
132+
AadAuthentication.init(null, null, null, null, null, null);
133+
}
130134
// FIXME do something with config
131135

132136
// FIXME set doNotWeavePrefixes = "com.microsoft.applicationinsights.agent."

core/src/main/java/com/microsoft/applicationinsights/TelemetryChannel.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package com.microsoft.applicationinsights;
22

33
import com.azure.core.http.*;
4+
import com.azure.core.http.policy.HttpLogOptions;
5+
import com.azure.core.http.policy.HttpLoggingPolicy;
46
import com.azure.core.http.policy.HttpPipelinePolicy;
57
import com.azure.core.http.policy.RetryPolicy;
68
import com.azure.core.util.tracing.Tracer;
79
import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem;
810
import com.fasterxml.jackson.annotation.JsonInclude;
911
import com.fasterxml.jackson.databind.ObjectMapper;
1012
import com.microsoft.applicationinsights.internal.authentication.AadAuthentication;
13+
import com.microsoft.applicationinsights.internal.authentication.AzureMonitorRedirectPolicy;
14+
import com.microsoft.applicationinsights.internal.channel.common.LazyAzureHttpClient;
1115
import io.opentelemetry.sdk.common.CompletableResultCode;
16+
import org.apache.http.HttpStatus;
1217
import org.slf4j.Logger;
1318
import org.slf4j.LoggerFactory;
1419
import reactor.core.publisher.Flux;
@@ -39,18 +44,23 @@ class TelemetryChannel {
3944

4045
TelemetryChannel(URL endpoint) {
4146
List<HttpPipelinePolicy> policies = new ArrayList<>();
42-
HttpClient client = HttpClient.createDefault();
43-
HttpPipelineBuilder pipeline = new HttpPipelineBuilder()
47+
HttpClient client = LazyAzureHttpClient.getInstance();
48+
HttpPipelineBuilder pipelineBuilder = new HttpPipelineBuilder()
4449
.httpClient(client);
50+
// Add Azure monitor redirect policy to be able to handle v2.1/track redirects
51+
policies.add(new AzureMonitorRedirectPolicy());
4552
// Retry policy for failed requests
4653
policies.add(new RetryPolicy());
4754
// TODO handle authentication exceptions
4855
HttpPipelinePolicy authenticationPolicy = AadAuthentication.getInstance().getAuthenticationPolicy();
4956
if (authenticationPolicy != null) {
5057
policies.add(authenticationPolicy);
5158
}
52-
pipeline.policies(policies.toArray(new HttpPipelinePolicy[0]));
53-
this.pipeline = pipeline.build();
59+
// Add Logging Policy. Can be enabled using AZURE_LOG_LEVEL.
60+
// TODO set the logging level based on self diagnostic log level set by user
61+
policies.add(new HttpLoggingPolicy(new HttpLogOptions()));
62+
pipelineBuilder.policies(policies.toArray(new HttpPipelinePolicy[0]));
63+
this.pipeline = pipelineBuilder.build();
5464
this.endpoint = endpoint;
5565
}
5666

@@ -115,13 +125,13 @@ private CompletableResultCode internalSend(List<ByteBuffer> byteBuffers) {
115125
.contextWrite(Context.of(Tracer.DISABLE_TRACING_KEY, true))
116126
.subscribe(response -> {
117127
// TODO parse response, looking for throttling, partial successes, etc
118-
// System.out.println("on response: " + response);
128+
if(response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED || response.getStatusCode() == HttpStatus.SC_FORBIDDEN) {
129+
logger.warn("Failed to send telemetry with status code:{} ,please check your credentials", response.getStatusCode());
130+
}
119131
}, error -> {
120-
// System.out.println("on error...");
121132
byteBufferPool.offer(byteBuffers);
122133
result.fail();
123134
}, () -> {
124-
// System.out.println("on complete...");
125135
byteBufferPool.offer(byteBuffers);
126136
result.succeed();
127137
});

core/src/main/java/com/microsoft/applicationinsights/internal/authentication/AadAuthentication.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import com.azure.core.http.HttpPipeline;
55
import com.azure.core.http.HttpPipelineBuilder;
66
import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
7+
import com.azure.core.http.policy.HttpLogOptions;
8+
import com.azure.core.http.policy.HttpLoggingPolicy;
79
import com.azure.core.http.policy.HttpPipelinePolicy;
810
import com.azure.core.http.policy.RetryPolicy;
911
import com.azure.identity.ClientSecretCredentialBuilder;
@@ -121,6 +123,9 @@ public HttpPipeline newHttpPipeLineWithAuthentication() {
121123
if(authenticationPolicy != null) {
122124
policies.add(authenticationPolicy);
123125
}
126+
// Add Logging Policy. Can be enabled using AZURE_LOG_LEVEL.
127+
// TODO set the logging level based on self diagnostic log level set by user
128+
policies.add(new HttpLoggingPolicy(new HttpLogOptions()));
124129
pipelineBuilder.policies(policies.toArray(new HttpPipelinePolicy[0]));
125130
return pipelineBuilder.build();
126131
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* ApplicationInsights-Java
3+
* Copyright (c) Microsoft Corporation
4+
* All rights reserved.
5+
*
6+
* MIT License
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
8+
* software and associated documentation files (the ""Software""), to deal in the Software
9+
* without restriction, including without limitation the rights to use, copy, modify, merge,
10+
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit
11+
* persons to whom the Software is furnished to do so, subject to the following conditions:
12+
* The above copyright notice and this permission notice shall be included in all copies or
13+
* substantial portions of the Software.
14+
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16+
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
17+
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19+
* DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
package com.microsoft.applicationinsights.internal.authentication;
23+
24+
import com.azure.core.http.HttpPipelineCallContext;
25+
import com.azure.core.http.HttpPipelineNextPolicy;
26+
import com.azure.core.http.HttpRequest;
27+
import com.azure.core.http.HttpResponse;
28+
import com.azure.core.http.policy.HttpPipelinePolicy;
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
import reactor.core.publisher.Mono;
32+
33+
import java.net.HttpURLConnection;
34+
35+
// This is a copy from Azure Monitor Open Telemetry Exporter SDK AzureMonitorRedirectPolicy
36+
public final class AzureMonitorRedirectPolicy implements HttpPipelinePolicy {
37+
38+
private static final int PERMANENT_REDIRECT_STATUS_CODE = 308;
39+
private static final int TEMP_REDIRECT_STATUS_CODE = 307;
40+
// Based on Stamp specific redirects design doc
41+
private static final int MAX_REDIRECT_RETRIES = 10;
42+
private static final Logger logger = LoggerFactory.getLogger(AzureMonitorRedirectPolicy.class);
43+
private volatile String redirectedEndpointUrl;
44+
45+
@Override
46+
public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
47+
return attemptRetry(context, next, context.getHttpRequest(), 0);
48+
}
49+
50+
/**
51+
* Function to process through the HTTP Response received in the pipeline
52+
* and retry sending the request with new redirect url.
53+
*/
54+
private Mono<HttpResponse> attemptRetry(final HttpPipelineCallContext context,
55+
final HttpPipelineNextPolicy next,
56+
final HttpRequest originalHttpRequest,
57+
final int retryCount) {
58+
// make sure the context is not modified during retry, except for the URL
59+
context.setHttpRequest(originalHttpRequest.copy());
60+
if (this.redirectedEndpointUrl != null) {
61+
context.getHttpRequest().setUrl(this.redirectedEndpointUrl);
62+
}
63+
return next.clone().process()
64+
.flatMap(httpResponse -> {
65+
if (shouldRetryWithRedirect(httpResponse.getStatusCode(), retryCount)) {
66+
String responseLocation = httpResponse.getHeaderValue("Location");
67+
if (responseLocation != null) {
68+
this.redirectedEndpointUrl = responseLocation;
69+
return attemptRetry(context, next, originalHttpRequest, retryCount + 1);
70+
}
71+
}
72+
return Mono.just(httpResponse);
73+
});
74+
}
75+
76+
/**
77+
* Determines if it's a valid retry scenario based on statusCode and tryCount.
78+
*
79+
* @param statusCode HTTP response status code
80+
* @param tryCount Redirect retries so far
81+
* @return True if statusCode corresponds to HTTP redirect response codes and redirect
82+
* retries is less than {@code MAX_REDIRECT_RETRIES}.
83+
*/
84+
private boolean shouldRetryWithRedirect(int statusCode, int tryCount) {
85+
if (tryCount >= MAX_REDIRECT_RETRIES) {
86+
logger.warn("Max redirect retries limit reached:{}.", MAX_REDIRECT_RETRIES);
87+
return false;
88+
}
89+
return statusCode == HttpURLConnection.HTTP_MOVED_TEMP
90+
|| statusCode == HttpURLConnection.HTTP_MOVED_PERM
91+
|| statusCode == PERMANENT_REDIRECT_STATUS_CODE
92+
|| statusCode == TEMP_REDIRECT_STATUS_CODE;
93+
}
94+
95+
}

0 commit comments

Comments
 (0)