We are implementing an internal library to collect logs and traces from Spring Batch applications and standalone applications in general.
When running a test application, the TraceId and SpanId are propagated within the application and appear in the logs. However, they are not exported. Exemples:
Logs(logback) have span information:
2024-12-26T09:29:39.567-03:00 INFO 14120 --- [ restartedMain] [97a1e490fdd6cd24754ef56ba28f2d10-5c8c24e1b096eeed] i.o.e.logging.LoggingSpanExporter : 'HikariDataSource.getConnection' : 97a1e490fdd6cd24754ef56ba28f2d10 393da51424bdb952 INTERNAL [tracer: io.opentelemetry.jdbc:2.9.0-alpha] AttributesMap{data={code.function=getConnection, db.system=h2, db.connection_string=h2:mem:, code.namespace=com.zaxxer.hikari.HikariDataSource, db.name=89aa5b4f-2086-427f-8438-8f19e8a73f8a}, capacity=128, totalAddedValues=5}
2024-12-26T09:29:39.568-03:00 INFO 14120 --- [ restartedMain] [97a1e490fdd6cd24754ef56ba28f2d10-5c8c24e1b096eeed] Main : Hello World Batch.
2024-12-26T09:29:39.569-03:00 INFO 14120 --- [ restartedMain] [97a1e490fdd6cd24754ef56ba28f2d10-5c8c24e1b096eeed] i.o.e.logging.LoggingSpanExporter : 'UPDATE 89aa5b4f-2086-427f-8438-8f19e8a73f8a.BATCH_STEP_EXECUTION_CONTEXT' : 97a1e490fdd6cd24754ef56ba28f2d10 d21c67ba9071de9e CLIENT [tracer: io.opentelemetry.jdbc:2.9.0-alpha] AttributesMap{data={db.statement=UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ? , db.system=h2, db.connection_string=h2:mem:, db.name=89aa5b4f-2086-427f-8438-8f19e8a73f8a, db.sql.table=BATCH_STEP_EXECUTION_CONTEXT, db.operation=UPDATE}, capacity=128, totalAddedValues=6}
Logs(SystemOutLogRecordExporter) when exported loose span information:
2024-12-26T12:29:39.567Z INFO ''HikariDataSource.getConnection' : 97a1e490fdd6cd24754ef56ba28f2d10 393da51424bdb952 INTERNAL [tracer: io.opentelemetry.jdbc:2.9.0-alpha] AttributesMap{data={code.function=getConnection, db.system=h2, db.connection_string=h2:mem:, code.namespace=com.zaxxer.hikari.HikariDataSource, db.name=89aa5b4f-2086-427f-8438-8f19e8a73f8a}, capacity=128, totalAddedValues=5}' : 00000000000000000000000000000000 0000000000000000 [scopeInfo: io.opentelemetry.exporter.logging.LoggingSpanExporter:] {}
2024-12-26T12:29:39.568Z INFO 'Hello World Batch.' : 00000000000000000000000000000000 0000000000000000 [scopeInfo: Main:] {}
2024-12-26T12:29:39.569Z INFO ''UPDATE 89aa5b4f-2086-427f-8438-8f19e8a73f8a.BATCH_STEP_EXECUTION_CONTEXT' : 97a1e490fdd6cd24754ef56ba28f2d10 d21c67ba9071de9e CLIENT [tracer: io.opentelemetry.jdbc:2.9.0-alpha] AttributesMap{data={db.statement=UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ? , db.system=h2, db.connection_string=h2:mem:, db.name=89aa5b4f-2086-427f-8438-8f19e8a73f8a, db.sql.table=BATCH_STEP_EXECUTION_CONTEXT, db.operation=UPDATE}, capacity=128, totalAddedValues=6}' : 00000000000000000000000000000000 0000000000000000 [scopeInfo: io.opentelemetry.exporter.logging.LoggingSpanExporter:] {}
We are using opentelemetry with opentelemetry-exporter-logging to test, if we start the same batch from a web context everything works as expected, following is our test application:
Java code:
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.lang.Nullable;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class Main {
public static void main(String[] args) {
System.exit(
SpringApplication.exit(
SpringApplication.run(Main.class, args)
)
);
}
@Bean
public Step step(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
log.info("Teste");
return new StepBuilder("step", jobRepository).tasklet(teste(), transactionManager).build();
}
@Bean
public Job job(JobRepository jobRepository, Step step) {
return new JobBuilder("job", jobRepository).start(step).build();
}
public Tasklet teste() {
return new Tasklet() {
@SuppressWarnings("null")
@Override
@Nullable
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
log.info("Hello World Batch.");
return RepeatStatus.FINISHED;
}
};
}
}
application.yml:
spring:
threads:
virtual:
enabled: true
otel:
logs:
exporter: console
traces:
exporter: console
metrics:
exporter: none
instrumentation:
annotations:
enabled: true
logback-appender:
enabled: true
micrometer:
enabled: true
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.1</version>
</parent>
<groupId>br.com.example</groupId>
<artifactId>example-batch-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>Example Batch Test</name>
<description>
</description>
<properties>
<java.version>21</java.version>
<opentelemetry.instrumentation.version>2.9.0</opentelemetry.instrumentation.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom</artifactId>
<version>${opentelemetry.instrumentation.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</project>
Comment From: bclozel
As noted in our reference documentation, this instrumentation is not supported by the Spring team. Please reach out to the library maintainers.