Printing thread id in log file using log4j
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
When you are debugging a multi-threaded Java application, knowing which thread produced a particular log line can save you hours of confusion. Apache Log4j (and its successor Log4j2) let you embed thread information directly in every log message through pattern layout placeholders. This article walks you through the relevant conversion characters, XML and properties-file configurations, and the programmatic use of MDC (Mapped Diagnostic Context) to enrich your logs with thread identity.
Thread Placeholders in Log4j2 PatternLayout
Log4j2's PatternLayout supports two thread-related conversion characters:
%t-- prints the thread name (for example,main,pool-1-thread-3).%T-- prints the thread ID, the numeric value returned byThread.currentThread().getId().
You choose one or both depending on what is most useful. Thread names are human-readable, while thread IDs are guaranteed unique within a JVM.
log4j2.xml Configuration
Below is a minimal log4j2.xml that writes to both the console and a rolling file, including the thread name and thread ID in every line:
A sample output line looks like this:
log4j.properties Equivalent
If your project still uses the older Log4j 1.x properties format, the same placeholders work inside ConversionPattern:
Note that %T for the numeric thread ID is available in Log4j2. In Log4j 1.x, only %t (thread name) is natively supported. If you need the numeric ID with 1.x, you should use MDC as described below.
Enriching Logs with MDC
The Mapped Diagnostic Context (MDC) lets you attach arbitrary key-value pairs to the current thread's logging context. This is especially useful when you want to log a request ID, user ID, or any custom identifier alongside the thread info.
Reference the MDC values in your pattern with %X{key}:
This approach is powerful because you can attach business context (order IDs, user names) that pure thread identifiers cannot provide.
Common Pitfalls
- Forgetting to clear MDC in thread pools. Thread pool threads are reused. If you do not call
ThreadContext.clearAll()at the end of a task, the next task on that thread inherits stale context values, producing misleading logs. - Confusing
%twith%T. Using lowercase%tgives you the thread name (a string), while uppercase%Tgives the numeric thread ID. Mixing them up leads to unexpected output or layout errors. - Assuming
%Tworks in Log4j 1.x. The numeric thread ID placeholder%Twas introduced in Log4j2. In Log4j 1.x you must use MDC or a custom pattern converter to log the numeric ID. - Not setting meaningful thread names. The default names (
Thread-0,pool-1-thread-1) are not very descriptive. Usethread.setName("order-worker-3")or configure yourExecutorServicewith a customThreadFactoryso that%toutput is immediately useful. - Over-verbose patterns in high-throughput systems. Including every available placeholder (
%t,%T,%X{...}, full class names) inflates log file sizes. Choose the fields you actually need for debugging and leave the rest out in production configurations.
Summary
- Use
%tin your PatternLayout to print the thread name and%Tto print the numeric thread ID. - Configure these placeholders in
log4j2.xmlorlog4j.propertiesinside thepattern/ConversionPatternattribute. - Use MDC (
ThreadContextin Log4j2) to attach custom per-thread values like request IDs, then reference them with%X{key}. - Always call
ThreadContext.clearAll()when a task finishes, especially in thread-pool environments, to prevent context leakage. - Choose only the thread identifiers you truly need in production to keep log volume manageable.
Related reading
- Problem with dynamic persistent volume in Helm
- Problem with minikube and nginx ingress when reinstalled minikube
- Production ready Python apps on Kubernetes
- Programmatically find the number of cores on a machine
- private final static attribute vs private final attribute
- problem path for truststore inside docker with spring boot and kafka
- Programmatically get the name of the pod that a container belongs to in Kubernetes?
- Programmatically retrieve memory usage on iPhone

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.