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.