Skip to content

Commit

Permalink
Align observations of @scheduled with OTel conventions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bclozel committed Jun 27, 2023
1 parent 91eb2be commit c2e3fed
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
|===


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,15 @@ public String getContextualName(ScheduledTaskObservationContext context) {

@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) {
Expand All @@ -63,10 +71,6 @@ protected KeyValue exception(ScheduledTaskObservationContext context) {
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;
Expand All @@ -77,8 +81,4 @@ else if (!context.isComplete()) {
return OUTCOME_SUCCESS;
}

protected KeyValue targetType(ScheduledTaskObservationContext context) {
return KeyValue.of(LowCardinalityKeyNames.TARGET_TYPE, context.getTargetClass().getSimpleName());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,22 @@ public KeyName[] getHighCardinalityKeyNames() {
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";
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ void shouldRecordSuccessObservationsForTasks() throws Exception {
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");
}

Expand All @@ -75,8 +75,8 @@ void shouldRecordFailureObservationsForTasksThrowing() throws Exception {
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");
}

Expand All @@ -85,8 +85,8 @@ void shouldRecordSuccessObservationsForReactiveTasks() throws Exception {
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");
}

Expand All @@ -95,8 +95,8 @@ void shouldRecordFailureObservationsForReactiveTasksThrowing() throws Exception
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");
}

Expand All @@ -108,8 +108,8 @@ void shouldRecordCancelledObservationsForTasks() throws Exception {
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");
}

Expand All @@ -121,8 +121,8 @@ void shouldRecordCancelledObservationsForReactiveTasks() throws Exception {
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");
}

Expand All @@ -131,8 +131,8 @@ void shouldHaveCurrentObservationInScope() throws Exception {
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");
}

Expand All @@ -141,8 +141,8 @@ void shouldHaveCurrentObservationInReactiveScope() throws Exception {
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");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ void observationShouldHaveContextualNameForProxiedClass() {
@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
Expand Down

0 comments on commit c2e3fed

Please sign in to comment.