Align observations of @Scheduled with OTel conventions

This commit updates the `ScheduledTaskObservationDocumentation` to
better align the contributed KeyValues with OpenTelemetry conventions
for observations of code executions.

Instead of a "target.type" key with the bean class simple name, this
is now contributing the canonical class name of the bean under the
"code.namespace" key.
The "method.name" key is renamed to "code.function" and its values
remain unchanged.

Closes gh-30721
This commit is contained in:
Brian Clozel 2023-06-27 22:11:05 +02:00
parent 91eb2be44c
commit c2e3fed8dc
5 changed files with 36 additions and 35 deletions

View File

@ -101,10 +101,10 @@ By default, the following `KeyValues` are created:
[cols="a,a"]
|===
|Name | Description
|`code.function` _(required)_|Name of Java `Method` that is scheduled for execution.
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method.
|`exception` _(required)_|Name of the exception thrown during the execution, or `KeyValue#NONE_VALUE`} if no exception happened.
|`method.name` _(required)_|Name of Java `Method` that is scheduled for execution.
|`outcome` _(required)_|Outcome of the method execution. Can be `"SUCCESS"`, `"ERROR"` or `"UNKNOWN"` (if for example the operation was cancelled during execution.
|`target.type` _(required)_|Simple class name of the bean instance that holds the scheduled method.
|===

View File

@ -53,7 +53,15 @@ public class DefaultScheduledTaskObservationConvention implements ScheduledTaskO
@Override
public KeyValues getLowCardinalityKeyValues(ScheduledTaskObservationContext context) {
return KeyValues.of(exception(context), methodName(context), outcome(context), targetType(context));
return KeyValues.of(codeFunction(context), codeNamespace(context), exception(context), outcome(context));
}
protected KeyValue codeFunction(ScheduledTaskObservationContext context) {
return KeyValue.of(LowCardinalityKeyNames.CODE_FUNCTION, context.getMethod().getName());
}
protected KeyValue codeNamespace(ScheduledTaskObservationContext context) {
return KeyValue.of(LowCardinalityKeyNames.CODE_NAMESPACE, context.getTargetClass().getCanonicalName());
}
protected KeyValue exception(ScheduledTaskObservationContext context) {
@ -63,10 +71,6 @@ public class DefaultScheduledTaskObservationConvention implements ScheduledTaskO
return EXCEPTION_NONE;
}
protected KeyValue methodName(ScheduledTaskObservationContext context) {
return KeyValue.of(LowCardinalityKeyNames.METHOD_NAME, context.getMethod().getName());
}
protected KeyValue outcome(ScheduledTaskObservationContext context) {
if (context.getError() != null) {
return OUTCOME_ERROR;
@ -77,8 +81,4 @@ public class DefaultScheduledTaskObservationConvention implements ScheduledTaskO
return OUTCOME_SUCCESS;
}
protected KeyValue targetType(ScheduledTaskObservationContext context) {
return KeyValue.of(LowCardinalityKeyNames.TARGET_TYPE, context.getTargetClass().getSimpleName());
}
}

View File

@ -56,22 +56,22 @@ public enum ScheduledTaskObservationDocumentation implements ObservationDocument
public enum LowCardinalityKeyNames implements KeyName {
/**
* {@link Class#getSimpleName() Simple name} of the target type that owns the scheduled method.
* Name of the method that is executed for the scheduled task.
*/
TARGET_TYPE {
CODE_FUNCTION {
@Override
public String asString() {
return "target.type";
return "code.function";
}
},
/**
* Name of the method that is executed for the scheduled task.
* {@link Class#getCanonicalName() Canonical name} of the target type that owns the scheduled method.
*/
METHOD_NAME {
CODE_NAMESPACE {
@Override
public String asString() {
return "method.name";
return "code.namespace";
}
},

View File

@ -65,8 +65,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(FixedDelayBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("method.name", "fixedDelay")
.hasLowCardinalityKeyValue("target.type", "FixedDelayBean")
.hasLowCardinalityKeyValue("code.function", "fixedDelay")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayBean")
.hasLowCardinalityKeyValue("exception", "none");
}
@ -75,8 +75,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(FixedDelayErrorBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "ERROR")
.hasLowCardinalityKeyValue("method.name", "error")
.hasLowCardinalityKeyValue("target.type", "FixedDelayErrorBean")
.hasLowCardinalityKeyValue("code.function", "error")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayErrorBean")
.hasLowCardinalityKeyValue("exception", "IllegalStateException");
}
@ -85,8 +85,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(FixedDelayReactiveBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("method.name", "fixedDelay")
.hasLowCardinalityKeyValue("target.type", "FixedDelayReactiveBean")
.hasLowCardinalityKeyValue("code.function", "fixedDelay")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayReactiveBean")
.hasLowCardinalityKeyValue("exception", "none");
}
@ -95,8 +95,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(FixedDelayReactiveErrorBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "ERROR")
.hasLowCardinalityKeyValue("method.name", "error")
.hasLowCardinalityKeyValue("target.type", "FixedDelayReactiveErrorBean")
.hasLowCardinalityKeyValue("code.function", "error")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayReactiveErrorBean")
.hasLowCardinalityKeyValue("exception", "IllegalStateException");
}
@ -108,8 +108,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
context.getBean(TaskTester.class).await();
scheduledTask.cancel();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN")
.hasLowCardinalityKeyValue("method.name", "cancelled")
.hasLowCardinalityKeyValue("target.type", "CancelledTaskBean")
.hasLowCardinalityKeyValue("code.function", "cancelled")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CancelledTaskBean")
.hasLowCardinalityKeyValue("exception", "none");
}
@ -121,8 +121,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
context.getBean(TaskTester.class).await();
scheduledTask.cancel();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN")
.hasLowCardinalityKeyValue("method.name", "cancelled")
.hasLowCardinalityKeyValue("target.type", "CancelledReactiveTaskBean")
.hasLowCardinalityKeyValue("code.function", "cancelled")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CancelledReactiveTaskBean")
.hasLowCardinalityKeyValue("exception", "none");
}
@ -131,8 +131,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(CurrentObservationBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("method.name", "hasCurrentObservation")
.hasLowCardinalityKeyValue("target.type", "CurrentObservationBean")
.hasLowCardinalityKeyValue("code.function", "hasCurrentObservation")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CurrentObservationBean")
.hasLowCardinalityKeyValue("exception", "none");
}
@ -141,8 +141,8 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests {
registerScheduledBean(CurrentObservationReactiveBean.class);
runScheduledTaskAndAwait();
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("method.name", "hasCurrentObservation")
.hasLowCardinalityKeyValue("target.type", "CurrentObservationReactiveBean")
.hasLowCardinalityKeyValue("code.function", "hasCurrentObservation")
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CurrentObservationReactiveBean")
.hasLowCardinalityKeyValue("exception", "none");
}

View File

@ -58,13 +58,14 @@ class DefaultScheduledTaskObservationConventionTests {
@Test
void observationShouldHaveTargetType() {
ScheduledTaskObservationContext context = new ScheduledTaskObservationContext(new BeanWithScheduledMethods(), taskMethod);
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("target.type", "BeanWithScheduledMethods"));
assertThat(convention.getLowCardinalityKeyValues(context))
.contains(KeyValue.of("code.namespace", getClass().getCanonicalName() + ".BeanWithScheduledMethods"));
}
@Test
void observationShouldHaveMethodName() {
ScheduledTaskObservationContext context = new ScheduledTaskObservationContext(new BeanWithScheduledMethods(), taskMethod);
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("method.name", "process"));
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("code.function", "process"));
}
@Test