Logging, Scheduled, and Async Tasks

Introduction

Production apps need structured logs, cron jobs, and sometimes background work without blocking HTTP threads. Spring Boot defaults to Logback, enables @Scheduled, and supports @Async with configurable thread pools. This chapter configures logging per profile, runs scheduled cleanup, and executes async tasks safely.

Prerequisites

Logging Basics

Spring Boot configures Logback automatically. Default levels:

LoggerDefault
RootINFO
Your app packageINFO

application.yml:

yaml
logging:
  level:
    root: INFO
    com.example.demo: DEBUG
    org.hibernate.SQL: DEBUG
    org.hibernate.orm.jdbc.bind: TRACE
  file:
    name: logs/app.log
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

Code explanation:

  • logging.level.* adjusts verbosity without code changes
  • SQL bind TRACE shows parameter values—dev only

Use SLF4J in code:

Never use System.out.println in services—logs integrate with levels and appenders.

Profile-Specific Logging

application-dev.yml:

yaml
logging:
  level:
    com.example.demo: DEBUG

application-prod.yml:

yaml
logging:
  level:
    root: WARN
    com.example.demo: INFO

Activate profile: spring.profiles.active=prod.

logback-spring.xml (Optional)

src/main/resources/logback-spring.xml for advanced appenders:

Use logback-spring.xml (not logback.xml) so Spring profile tags work.

@Scheduled Tasks

Enable scheduling on main class or config:

java
@SpringBootApplication
@EnableScheduling
public class DemoApplication { }

Job example:

java
@Component
public class SessionCleanupJob {
 
    private static final Logger log = LoggerFactory.getLogger(SessionCleanupJob.class);
 
    @Scheduled(cron = "0 0 3 * * *")
    public void cleanupExpiredSessions() {
        log.info("Starting session cleanup");
        // delete expired rows
    }
}

Cron format (6 fields): second minute hour day month weekday.

ExpressionMeaning
0 */5 * * * *Every 5 minutes
0 0 3 * * *Daily 3
AM
fixedRate = 60000Every 60s from start

Fixed delay:

java
@Scheduled(fixedDelay = 30000)
public void pollQueue() { }

Warning

Scheduled Methods on Single Instance

By default every app instance runs the job—use distributed lock (Redis) or scheduler platform for multi-node clusters.

@Async Tasks

Enable async:

java
@EnableAsync
@SpringBootApplication
public class DemoApplication { }
java
@Service
public class EmailService {
 
    private static final Logger log = LoggerFactory.getLogger(EmailService.class);
 
    @Async
    public void sendWelcomeEmail(String email) {
        log.info("Sending welcome email to {}", email);
        // simulate IO
    }
}

Caller returns immediately; work runs on async executor thread.

Configure pool:

application.yml shortcut:

yaml
spring:
  task:
    execution:
      pool:
        core-size: 4
        max-size: 16
        queue-capacity: 200

Async and Transactions

@Async method runs in new thread—transaction context does not propagate unless you configure TransactionSynchronizationManager. Keep transactional work inside synchronous service, then async side effects (email, webhook).

FAQ

Logs not showing DEBUG?

Check profile, logging.level, and whether logger name matches package.

Scheduled job not running?

Missing @EnableScheduling, wrong cron, or exception swallowed—check logs.

@Async not async?

Must call from another Spring bean—self-invocation inline.

Async exception lost?

Implement AsyncUncaughtExceptionHandler or use CompletableFuture.

Log rotation?

logging.logback.rollingpolicy in Boot 2.4+ or custom logback-spring.xml.

JSON structured logs?

Add Logstash encoder dependency—observability chapter expands.