Skip to content

Commit c2e3fed

Browse files
committed
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
1 parent 91eb2be commit c2e3fed

File tree

5 files changed

+36
-35
lines changed

5 files changed

+36
-35
lines changed

framework-docs/modules/ROOT/pages/integration/observability.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ By default, the following `KeyValues` are created:
101101
[cols="a,a"]
102102
|===
103103
|Name | Description
104+
|`code.function` _(required)_|Name of Java `Method` that is scheduled for execution.
105+
|`code.namespace` _(required)_|Canonical name of the class of the bean instance that holds the scheduled method.
104106
|`exception` _(required)_|Name of the exception thrown during the execution, or `KeyValue#NONE_VALUE`} if no exception happened.
105-
|`method.name` _(required)_|Name of Java `Method` that is scheduled for execution.
106107
|`outcome` _(required)_|Outcome of the method execution. Can be `"SUCCESS"`, `"ERROR"` or `"UNKNOWN"` (if for example the operation was cancelled during execution.
107-
|`target.type` _(required)_|Simple class name of the bean instance that holds the scheduled method.
108108
|===
109109

110110

spring-context/src/main/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConvention.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,15 @@ public String getContextualName(ScheduledTaskObservationContext context) {
5353

5454
@Override
5555
public KeyValues getLowCardinalityKeyValues(ScheduledTaskObservationContext context) {
56-
return KeyValues.of(exception(context), methodName(context), outcome(context), targetType(context));
56+
return KeyValues.of(codeFunction(context), codeNamespace(context), exception(context), outcome(context));
57+
}
58+
59+
protected KeyValue codeFunction(ScheduledTaskObservationContext context) {
60+
return KeyValue.of(LowCardinalityKeyNames.CODE_FUNCTION, context.getMethod().getName());
61+
}
62+
63+
protected KeyValue codeNamespace(ScheduledTaskObservationContext context) {
64+
return KeyValue.of(LowCardinalityKeyNames.CODE_NAMESPACE, context.getTargetClass().getCanonicalName());
5765
}
5866

5967
protected KeyValue exception(ScheduledTaskObservationContext context) {
@@ -63,10 +71,6 @@ protected KeyValue exception(ScheduledTaskObservationContext context) {
6371
return EXCEPTION_NONE;
6472
}
6573

66-
protected KeyValue methodName(ScheduledTaskObservationContext context) {
67-
return KeyValue.of(LowCardinalityKeyNames.METHOD_NAME, context.getMethod().getName());
68-
}
69-
7074
protected KeyValue outcome(ScheduledTaskObservationContext context) {
7175
if (context.getError() != null) {
7276
return OUTCOME_ERROR;
@@ -77,8 +81,4 @@ else if (!context.isComplete()) {
7781
return OUTCOME_SUCCESS;
7882
}
7983

80-
protected KeyValue targetType(ScheduledTaskObservationContext context) {
81-
return KeyValue.of(LowCardinalityKeyNames.TARGET_TYPE, context.getTargetClass().getSimpleName());
82-
}
83-
8484
}

spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationDocumentation.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,22 @@ public KeyName[] getHighCardinalityKeyNames() {
5656
public enum LowCardinalityKeyNames implements KeyName {
5757

5858
/**
59-
* {@link Class#getSimpleName() Simple name} of the target type that owns the scheduled method.
59+
* Name of the method that is executed for the scheduled task.
6060
*/
61-
TARGET_TYPE {
61+
CODE_FUNCTION {
6262
@Override
6363
public String asString() {
64-
return "target.type";
64+
return "code.function";
6565
}
6666
},
6767

6868
/**
69-
* Name of the method that is executed for the scheduled task.
69+
* {@link Class#getCanonicalName() Canonical name} of the target type that owns the scheduled method.
7070
*/
71-
METHOD_NAME {
71+
CODE_NAMESPACE {
7272
@Override
7373
public String asString() {
74-
return "method.name";
74+
return "code.namespace";
7575
}
7676
},
7777

spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorObservabilityTests.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ void shouldRecordSuccessObservationsForTasks() throws Exception {
6565
registerScheduledBean(FixedDelayBean.class);
6666
runScheduledTaskAndAwait();
6767
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
68-
.hasLowCardinalityKeyValue("method.name", "fixedDelay")
69-
.hasLowCardinalityKeyValue("target.type", "FixedDelayBean")
68+
.hasLowCardinalityKeyValue("code.function", "fixedDelay")
69+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayBean")
7070
.hasLowCardinalityKeyValue("exception", "none");
7171
}
7272

@@ -75,8 +75,8 @@ void shouldRecordFailureObservationsForTasksThrowing() throws Exception {
7575
registerScheduledBean(FixedDelayErrorBean.class);
7676
runScheduledTaskAndAwait();
7777
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "ERROR")
78-
.hasLowCardinalityKeyValue("method.name", "error")
79-
.hasLowCardinalityKeyValue("target.type", "FixedDelayErrorBean")
78+
.hasLowCardinalityKeyValue("code.function", "error")
79+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayErrorBean")
8080
.hasLowCardinalityKeyValue("exception", "IllegalStateException");
8181
}
8282

@@ -85,8 +85,8 @@ void shouldRecordSuccessObservationsForReactiveTasks() throws Exception {
8585
registerScheduledBean(FixedDelayReactiveBean.class);
8686
runScheduledTaskAndAwait();
8787
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
88-
.hasLowCardinalityKeyValue("method.name", "fixedDelay")
89-
.hasLowCardinalityKeyValue("target.type", "FixedDelayReactiveBean")
88+
.hasLowCardinalityKeyValue("code.function", "fixedDelay")
89+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayReactiveBean")
9090
.hasLowCardinalityKeyValue("exception", "none");
9191
}
9292

@@ -95,8 +95,8 @@ void shouldRecordFailureObservationsForReactiveTasksThrowing() throws Exception
9595
registerScheduledBean(FixedDelayReactiveErrorBean.class);
9696
runScheduledTaskAndAwait();
9797
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "ERROR")
98-
.hasLowCardinalityKeyValue("method.name", "error")
99-
.hasLowCardinalityKeyValue("target.type", "FixedDelayReactiveErrorBean")
98+
.hasLowCardinalityKeyValue("code.function", "error")
99+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".FixedDelayReactiveErrorBean")
100100
.hasLowCardinalityKeyValue("exception", "IllegalStateException");
101101
}
102102

@@ -108,8 +108,8 @@ void shouldRecordCancelledObservationsForTasks() throws Exception {
108108
context.getBean(TaskTester.class).await();
109109
scheduledTask.cancel();
110110
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN")
111-
.hasLowCardinalityKeyValue("method.name", "cancelled")
112-
.hasLowCardinalityKeyValue("target.type", "CancelledTaskBean")
111+
.hasLowCardinalityKeyValue("code.function", "cancelled")
112+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CancelledTaskBean")
113113
.hasLowCardinalityKeyValue("exception", "none");
114114
}
115115

@@ -121,8 +121,8 @@ void shouldRecordCancelledObservationsForReactiveTasks() throws Exception {
121121
context.getBean(TaskTester.class).await();
122122
scheduledTask.cancel();
123123
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN")
124-
.hasLowCardinalityKeyValue("method.name", "cancelled")
125-
.hasLowCardinalityKeyValue("target.type", "CancelledReactiveTaskBean")
124+
.hasLowCardinalityKeyValue("code.function", "cancelled")
125+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CancelledReactiveTaskBean")
126126
.hasLowCardinalityKeyValue("exception", "none");
127127
}
128128

@@ -131,8 +131,8 @@ void shouldHaveCurrentObservationInScope() throws Exception {
131131
registerScheduledBean(CurrentObservationBean.class);
132132
runScheduledTaskAndAwait();
133133
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
134-
.hasLowCardinalityKeyValue("method.name", "hasCurrentObservation")
135-
.hasLowCardinalityKeyValue("target.type", "CurrentObservationBean")
134+
.hasLowCardinalityKeyValue("code.function", "hasCurrentObservation")
135+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CurrentObservationBean")
136136
.hasLowCardinalityKeyValue("exception", "none");
137137
}
138138

@@ -141,8 +141,8 @@ void shouldHaveCurrentObservationInReactiveScope() throws Exception {
141141
registerScheduledBean(CurrentObservationReactiveBean.class);
142142
runScheduledTaskAndAwait();
143143
assertThatTaskObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
144-
.hasLowCardinalityKeyValue("method.name", "hasCurrentObservation")
145-
.hasLowCardinalityKeyValue("target.type", "CurrentObservationReactiveBean")
144+
.hasLowCardinalityKeyValue("code.function", "hasCurrentObservation")
145+
.hasLowCardinalityKeyValue("code.namespace", getClass().getCanonicalName() + ".CurrentObservationReactiveBean")
146146
.hasLowCardinalityKeyValue("exception", "none");
147147
}
148148

spring-context/src/test/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConventionTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ void observationShouldHaveContextualNameForProxiedClass() {
5858
@Test
5959
void observationShouldHaveTargetType() {
6060
ScheduledTaskObservationContext context = new ScheduledTaskObservationContext(new BeanWithScheduledMethods(), taskMethod);
61-
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("target.type", "BeanWithScheduledMethods"));
61+
assertThat(convention.getLowCardinalityKeyValues(context))
62+
.contains(KeyValue.of("code.namespace", getClass().getCanonicalName() + ".BeanWithScheduledMethods"));
6263
}
6364

6465
@Test
6566
void observationShouldHaveMethodName() {
6667
ScheduledTaskObservationContext context = new ScheduledTaskObservationContext(new BeanWithScheduledMethods(), taskMethod);
67-
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("method.name", "process"));
68+
assertThat(convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("code.function", "process"));
6869
}
6970

7071
@Test

0 commit comments

Comments
 (0)