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:
| Logger | Default |
|---|---|
| Root | INFO |
| Your app package | INFO |
application.yml:
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:
logging:
level:
com.example.demo: DEBUGapplication-prod.yml:
logging:
level:
root: WARN
com.example.demo: INFOActivate 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:
@SpringBootApplication
@EnableScheduling
public class DemoApplication { }Job example:
@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.
| Expression | Meaning |
|---|---|
0 */5 * * * * | Every 5 minutes |
0 0 3 * * * | Daily 3 AM |
fixedRate = 60000 | Every 60s from start |
Fixed delay:
@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:
@EnableAsync
@SpringBootApplication
public class DemoApplication { }@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:
spring:
task:
execution:
pool:
core-size: 4
max-size: 16
queue-capacity: 200Async 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.