Skip to content

Commit

Permalink
Merge branch 'main' into micrometer-metricsgh-3706
Browse files Browse the repository at this point in the history
# Conflicts:
#	micrometer-core/src/main/java/io/micrometer/core/instrument/binder/httpcomponents/MicrometerHttpRequestExecutor.java
#	micrometer-core/src/main/java/io/micrometer/core/instrument/binder/httpcomponents/hc5/MicrometerHttpRequestExecutor.java
  • Loading branch information
Chintan Radia committed Apr 4, 2023
2 parents fe4b380 + 63cfcbc commit 4f8dfc8
Show file tree
Hide file tree
Showing 57 changed files with 873 additions and 230 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,10 @@ subprojects {
repositories {
mavenCentral()
maven {
// TODO remove before releasing
url "https://repo.spring.io/snapshot/"
// TODO remove before releasing GA
url "https://repo.spring.io/milestone/"
content {
// for context-propagation snapshots
// for context-propagation milestone versions
includeModule 'io.micrometer', 'context-propagation'
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.micrometer.azuremonitor;

import io.micrometer.common.lang.Nullable;
import io.micrometer.core.instrument.config.validate.Validated;
import io.micrometer.core.instrument.step.StepRegistryConfig;

Expand All @@ -36,17 +37,41 @@ default String prefix() {
}

/**
* default implementation to get the instrumentation key from the config
* Instrumentation key to use when sending metrics.
* @return Instrumentation Key
* @deprecated since 1.11.0, use {@link #connectionString()} instead. This method is
* only called as a fallback in the default implementation if a connectionString is
* not configured.
*/
@Nullable
@Deprecated
default String instrumentationKey() {
return getSecret(this, "instrumentationKey").get();
}

/**
* Connection string to use when configuring sending metrics.
* @return Connection String
* @see <a
* href=https://learn.microsoft.com/en-us/azure/azure-monitor/app/sdk-connection-string">Connection
* strings</a>
* @since 1.11.0
*/
@Nullable
default String connectionString() {
return getSecret(this, "connectionString").orElseGet(() -> {
String instrumentationKey = instrumentationKey();
if (instrumentationKey == null) {
return null;
}
return "InstrumentationKey=" + instrumentationKey;
});
}

@Override
default Validated<?> validate() {
return checkAll(this, c -> StepRegistryConfig.validate(c),
check("instrumentationKey", AzureMonitorConfig::instrumentationKey));
check("connectionString", AzureMonitorConfig::connectionString));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ private AzureMonitorMeterRegistry(AzureMonitorConfig config, Clock clock,
super(config, clock);

config().namingConvention(new AzureMonitorNamingConvention());
if (StringUtils.isEmpty(telemetryConfiguration.getInstrumentationKey())) {
checkRequired("instrumentationKey", AzureMonitorConfig::instrumentationKey).apply(config).orThrow();
telemetryConfiguration.setInstrumentationKey(config.instrumentationKey());
if (StringUtils.isEmpty(telemetryConfiguration.getConnectionString())) {
checkRequired("connectionString", AzureMonitorConfig::connectionString).apply(config).orThrow();
telemetryConfiguration.setConnectionString(config.connectionString());
}

client = new TelemetryClient(telemetryConfiguration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,32 @@ class AzureMonitorConfigTest {
private final AzureMonitorConfig config = props::get;

@Test
void valid() {
props.put("azuremonitor.instrumentationKey", "secret");
void validWithInstrumentationKey() {
props.put("azuremonitor.instrumentationKey", "key");

assertThat(config.validate().isValid()).isTrue();
}

@Test
void validWithConnectionString() {
props.put("azuremonitor.connectionString", "secret");

assertThat(config.validate().isValid()).isTrue();
}

@Test
void connectionStringUsesInstrumentationKeyIfUnset() {
props.put("azuremonitor.instrumentationKey", "key");

assertThat(config.connectionString()).isEqualTo("InstrumentationKey=key");
}

@Test
void connectionStringIgnoresInstrumentationKeyIfSet() {
props.put("azuremonitor.instrumentationKey", "key");
props.put("azuremonitor.connectionString", "InstrumentationKey=another");

assertThat(config.connectionString()).isEqualTo("InstrumentationKey=another");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class AzureMonitorMeterRegistryCompatibilityKit extends MeterRegistryCompatibili

private final AzureMonitorConfig config = new AzureMonitorConfig() {
@Override
public String instrumentationKey() {
return "fakeKey";
public String connectionString() {
return "InstrumentationKey=fakeKey";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ public String get(String key) {
return null;
}

@Override
public String connectionString() {
return "InstrumentationKey=connectionStringKey";
}
};

private final AzureMonitorConfig configWithInstrumentationKey = new AzureMonitorConfig() {
@Override
public String get(String key) {
return null;
}

@SuppressWarnings("deprecation")
@Override
public String instrumentationKey() {
return "myInstrumentationKey";
Expand All @@ -54,11 +67,22 @@ public String instrumentationKey() {
private final AzureMonitorMeterRegistry registry = new AzureMonitorMeterRegistry(config, clock);

@Test
void useTelemetryConfigInstrumentationKeyWhenSet() {
void useTelemetryConfigConnectionStringWhenSet() {
TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.createDefault();
telemetryConfiguration.setInstrumentationKey("fake");
telemetryConfiguration.setConnectionString("InstrumentationKey=direct");
AzureMonitorMeterRegistry.builder(config).telemetryConfiguration(telemetryConfiguration).build();
assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("fake");
assertThat(telemetryConfiguration.getConnectionString()).isEqualTo("InstrumentationKey=direct");
assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("direct");
}

@Test
void configInstrumentationKeyStillSetsTelemetryConfigInstrumentationKey() {
TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.createDefault();
AzureMonitorMeterRegistry.builder(configWithInstrumentationKey)
.telemetryConfiguration(telemetryConfiguration)
.build();
assertThat(telemetryConfiguration.getConnectionString()).isEqualTo("InstrumentationKey=myInstrumentationKey");
assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("myInstrumentationKey");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public String asString() {
return "status";
}
},
OUTCOME {
@Override
public String asString() {
return "outcome";
}
},
METHOD {
@Override
public String asString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.micrometer.common.KeyValues;
import io.micrometer.common.lang.Nullable;
import io.micrometer.core.instrument.binder.http.Outcome;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
Expand Down Expand Up @@ -63,13 +64,19 @@ public KeyValues getLowCardinalityKeyValues(ApacheHttpClientContext context) {
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.URI
.withValue(context.getUriMapper().apply(context.getCarrier())),
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.STATUS
.withValue(getStatusValue(context.getResponse(), context.getError())));
.withValue(getStatusValue(context.getResponse(), context.getError())),
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.OUTCOME
.withValue(getStatusOutcome(context.getResponse()).name()));
if (context.shouldExportTagsForRoute()) {
keyValues = keyValues.and(HttpContextUtils.generateTagStringsForRoute(context.getApacheHttpContext()));
}
return keyValues;
}

Outcome getStatusOutcome(@Nullable HttpResponse response) {
return response != null ? Outcome.forStatus(response.getStatusLine().getStatusCode()) : Outcome.UNKNOWN;
}

String getStatusValue(@Nullable HttpResponse response, Throwable error) {
if (error instanceof IOException || error instanceof HttpException || error instanceof RuntimeException) {
return "IO_ERROR";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.http.Outcome;
import io.micrometer.core.instrument.observation.ObservationOrTimerCompatibleInstrumentation;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
Expand Down Expand Up @@ -121,11 +122,13 @@ public HttpResponse execute(HttpRequest request, HttpClientConnection conn, Http
() -> new ApacheHttpClientContext(request, context, uriMapper, exportTagsForRoute), convention,
DefaultApacheHttpClientObservationConvention.INSTANCE);
String statusCodeOrError = "UNKNOWN";
Outcome statusOutcome = Outcome.UNKNOWN;

try {
HttpResponse response = super.execute(request, conn, context);
sample.setResponse(response);
statusCodeOrError = DefaultApacheHttpClientObservationConvention.INSTANCE.getStatusValue(response, null);
statusOutcome = DefaultApacheHttpClientObservationConvention.INSTANCE.getStatusOutcome(response);
return response;
}
catch (IOException | HttpException | RuntimeException e) {
Expand All @@ -135,10 +138,11 @@ public HttpResponse execute(HttpRequest request, HttpClientConnection conn, Http
}
finally {
String status = statusCodeOrError;
String outcome = statusOutcome.name();
sample.stop(this.meterName, "Duration of Apache HttpClient request execution",
() -> Tags
.of("method", DefaultApacheHttpClientObservationConvention.INSTANCE.getMethodString(request),
"uri", uriMapper.apply(request), "status", status)
"uri", uriMapper.apply(request), "status", status, "outcome", outcome)
.and(exportTagsForRoute ? HttpContextUtils.generateTagsForRoute(context) : Tags.empty())
.and(extraTags));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public String asString() {
return "status";
}
},
OUTCOME {
@Override
public String asString() {
return "outcome";
}
},
METHOD {
@Override
public String asString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.micrometer.common.KeyValues;
import io.micrometer.common.lang.Nullable;
import io.micrometer.core.instrument.binder.http.Outcome;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
Expand Down Expand Up @@ -59,13 +60,19 @@ public KeyValues getLowCardinalityKeyValues(ApacheHttpClientContext context) {
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.URI
.withValue(context.getUriMapper().apply(context.getCarrier())),
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.STATUS
.withValue(getStatusValue(context.getResponse(), context.getError())));
.withValue(getStatusValue(context.getResponse(), context.getError())),
ApacheHttpClientObservationDocumentation.ApacheHttpClientKeyNames.OUTCOME
.withValue(getStatusOutcome(context.getResponse()).name()));
if (context.shouldExportTagsForRoute()) {
keyValues = keyValues.and(HttpContextUtils.generateTagStringsForRoute(context.getApacheHttpContext()));
}
return keyValues;
}

Outcome getStatusOutcome(@Nullable HttpResponse response) {
return response != null ? Outcome.forStatus(response.getCode()) : Outcome.UNKNOWN;
}

String getStatusValue(@Nullable HttpResponse response, Throwable error) {
if (error instanceof IOException || error instanceof HttpException || error instanceof RuntimeException) {
return "IO_ERROR";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.http.Outcome;
import io.micrometer.core.instrument.observation.ObservationOrTimerCompatibleInstrumentation;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
Expand Down Expand Up @@ -108,11 +109,13 @@ public ClassicHttpResponse execute(ClassicHttpRequest request, HttpClientConnect
() -> new ApacheHttpClientContext(request, context, uriMapper, exportTagsForRoute), convention,
DefaultApacheHttpClientObservationConvention.INSTANCE);
String statusCodeOrError = "UNKNOWN";
Outcome statusOutcome = Outcome.UNKNOWN;

try {
ClassicHttpResponse response = super.execute(request, conn, context);
sample.setResponse(response);
statusCodeOrError = DefaultApacheHttpClientObservationConvention.INSTANCE.getStatusValue(response, null);
statusOutcome = DefaultApacheHttpClientObservationConvention.INSTANCE.getStatusOutcome(response);
return response;
}
catch (IOException | HttpException | RuntimeException e) {
Expand All @@ -122,10 +125,11 @@ public ClassicHttpResponse execute(ClassicHttpRequest request, HttpClientConnect
}
finally {
String status = statusCodeOrError;
String outcome = statusOutcome.name();
sample.stop(meterName, "Duration of Apache HttpClient request execution",
() -> Tags
.of("method", DefaultApacheHttpClientObservationConvention.INSTANCE.getMethodString(request),
"uri", uriMapper.apply(request), "status", status)
"uri", uriMapper.apply(request), "status", status, "outcome", outcome)
.and(exportTagsForRoute ? HttpContextUtils.generateTagsForRoute(context) : Tags.empty())
.and(extraTags));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.micrometer.common.lang.Nullable;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.http.Outcome;
import okhttp3.Request;
import okhttp3.Response;

Expand Down Expand Up @@ -88,7 +89,8 @@ public KeyValues getLowCardinalityKeyValues(OkHttpContext context) {
KeyValues keyValues = KeyValues
.of(METHOD.withValue(requestAvailable ? request.method() : TAG_VALUE_UNKNOWN),
URI.withValue(getUriTag(urlMapper, state, request)),
STATUS.withValue(getStatusMessage(state.response, state.exception)))
STATUS.withValue(getStatusMessage(state.response, state.exception)),
OUTCOME.withValue(getStatusOutcome(state.response).name()))
.and(extraTags)
.and(stream(contextSpecificTags.spliterator(), false)
.map(contextTag -> contextTag.apply(request, state.response))
Expand All @@ -112,6 +114,14 @@ private String getUriTag(Function<Request, String> urlMapper, OkHttpObservationI
: urlMapper.apply(request);
}

private Outcome getStatusOutcome(@Nullable Response response) {
if (response == null) {
return Outcome.UNKNOWN;
}

return Outcome.forStatus(response.code());
}

private String getStatusMessage(@Nullable Response response, @Nullable IOException exception) {
if (exception != null) {
return "IO_ERROR";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.http.Outcome;
import okhttp3.EventListener;
import okhttp3.*;

Expand Down Expand Up @@ -168,6 +169,7 @@ void time(CallState state) {
Iterable<Tag> tags = Tags
.of("method", requestAvailable ? request.method() : TAG_VALUE_UNKNOWN, "uri", getUriTag(state, request),
"status", getStatusMessage(state.response, state.exception))
.and(getStatusOutcome(state.response).asTag())
.and(extraTags)
.and(stream(contextSpecificTags.spliterator(), false)
.map(contextTag -> contextTag.apply(request, state.response))
Expand Down Expand Up @@ -219,6 +221,14 @@ private Iterable<Tag> getRequestTags(@Nullable Request request) {
return Tags.empty();
}

private Outcome getStatusOutcome(@Nullable Response response) {
if (response == null) {
return Outcome.UNKNOWN;
}

return Outcome.forStatus(response.code());
}

private String getStatusMessage(@Nullable Response response, @Nullable IOException exception) {
if (exception != null) {
return "IO_ERROR";
Expand Down
Loading

0 comments on commit 4f8dfc8

Please sign in to comment.