Apache Log4j 2: the module map tells you more than the README does
Apache Log4j is a versatile, feature-rich, efficient logging API and backend for Java.
At a glance
- What is it?
- Log4j 2 ships an API, an implementation and around thirty optional integration modules. Reading that tree, and the patch releases on the 2.x branch, explains more about the project than its short README does.
- Who is it for?
- Log4j 2 is a reasonable default for a Java service that wants direct control of its logging configuration, and its 2.x branch is still receiving patch releases, with 2.26.1 published on 2026-07-02 and a push on 2026-09-23.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 13 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README is a pointer, the tree is the architecture
Apache Log4j's repository README is unusually short. After the licence header and three build badges it says one substantive sentence: Log4j is an industrial-grade Java logging framework composed of an API, its implementation, and components to assist deployment for various use cases. Everything else is a link to logging.apache.org/log4j/2.x and a note that build instructions, the branching scheme and developer resources live on the website's Development page.
That makes the module list the real documentation, and it is more informative than it first appears. The mandatory core is two directories: log4j-api, which holds the interfaces an application compiles against, and log4j-core, which holds the implementation. Separating them is the standard pattern for a logging library: application code binds to the API so the implementation can be swapped or upgraded without recompiling.
Around those two sit roughly thirty more modules, and reading them is a quick way to understand what the project is for. There are bridges in both directions with other logging ecosystems: log4j-to-slf4j pushes Log4j calls into SLF4J, log4j-slf4j2-impl and log4j-slf4j-impl bind SLF4J onto Log4j, and log4j-to-jul and log4j-jul do the same with java.util.logging. log4j-jcl bridges Apache Commons Logging, and log4j-1.2-api exists specifically to let Log4j 1.x code compile against Log4j 2.
Then come the deployment integrations: log4j-spring-boot, log4j-spring-cloud-config-client, log4j-jdbc-dbcp2, log4j-jpa, log4j-web, log4j-jakarta-web, log4j-jakarta-smtp, log4j-jakarta-jms, log4j-iostreams, log4j-taglib, log4j-jpl, log4j-appserver, log4j-docker, and database appenders for MongoDB, both mongodb and mongodb4, plus Cassandra and CouchDB. The variety is the point: this is not one logging library but a hub that other logging APIs and application servers can be pointed at.
Which modules a deployment actually pulls in
A plain service needs two modules and can ignore the rest. An application server or framework integration needs a specific one, and choosing wrong here is the usual source of trouble, because the bridging modules are mutually exclusive in practice. If your code logs through SLF4J but you want Log4j 2 to do the work, that is log4j-slf4j2-impl. If your code logs through Log4j 2 and you want output to leave through SLF4J, that is log4j-to-slf4j. Wiring both into one classpath is a configuration mistake with a confusing symptom, which is the practical argument for reading the module names carefully before adding dependencies.
The Maven coordinates appear in the README's badge for log4j-api under the group id org.apache.logging.log4j, so the artifact naming is conventional Maven layout rather than anything Log4j specific.
The project also tests itself unusually hard for a logging library. Separate directories exist for integration tests, performance benchmarks and fuzzing: log4j-core-its, log4j-perf-test, log4j-fuzz-test, log4j-core-fuzz-test, log4j-slf4j2-impl-fuzz-test, and layout-specific fuzz tests such as log4j-layout-template-json-fuzz-test, backed by a FUZZING.adoc at the repository root. Fuzzing the pattern layout and the JSON template layout is a sensible thing to do, since both parse text supplied by the application and a crash in a logger takes down the application.
Java 9 support is handled with parallel module directories, log4j-api-java9 and log4j-core-java9, and there are OSGi and modularity tests too, which is what you would expect from a library that ships inside application servers.
The 2.x branch and how its releases are numbered
The default branch is 2.x and the repository is not archived, with the last push on 2026-09-23. Three releases are recent enough to be informative. 2.26.0, published 2026-05-07, is a minor release whose notes say it delivers all the fixes in the 2.25.0 through 2.25.4 range plus new work, which tells you the project runs maintenance on more than one line at a time.
That is visible in the release dates. 2.26.1 was published on 2026-07-02 and 2.25.5 on 2026-07-06, so the higher version number is not the newest artifact. A build pinned to whatever Maven Central resolves as newest will get a patch from the 2.25 line while 2.26.x exists, and a team that tracks release numbers by reading release dates in order will get it wrong.
The 2.26.0 additions are small and specific. `ConfigurationFactory::getConfiguration` gained an overload accepting multiple URIs, so a configuration can be assembled from several locations rather than one. A new exported `NamedInstantPattern` gives programmatic access to the named date and time patterns Pattern Layout supports. `Rfc5424LayoutBuilder` picked up missing setters, which matters because that builder targets the syslog RFC 5424 wire format. The annotation processor gained a `log4j.plugin.processor.minAllowedMessageKind` option so builds running with something like Maven `-Werror` can suppress the informational notes emitted during plugin processing.
One change is a compatibility break in behaviour rather than an API: scripts in the global `Scripts` element must now have explicit names, and an unnamed one throws a `ConfigurationException`. Deprecated withers in builder classes in favour of setters is a smaller signal of the same direction, moving the configuration API toward a JavaBean style.
What the patch releases were fixing
The 2.25.5 and 2.26.1 notes list the same set of fixes, which is what you would expect from two branches of one code base. They are worth reading because most are ordinary correctness work in a component nobody thinks about.
`RollingFileAppender` had a `createOnDemand` behaviour that was not deferring file and directory creation until the first log event, and eager creation when that option was disabled was not preserved either. For an application that starts without writing a log line, or that watches for log directory creation, that difference is observable.
Two fixes are about output correctness. `MapMessage` encoding to JSON mishandled non-finite numbers, and `StructuredDataMessage` encoding to XML mishandled the `MSGID` and `SD-ID` fields. Both are format conformance bugs, the kind a syslog or structured logging consumer downstream would notice before anyone upstream did.
The two that would bite hardest are resource and error handling. `ConfigurationSource` leaked resources when loading configuration via URL failed, so a startup failure left handles open, and `KafkaAppender` reported an error to its error handler even after a retry had succeeded, which produces false alarms during a transient broker outage.
There is also a fix for stack trace rendering when an exception has a broken identity, specifically a colliding `equals()` or `hashCode()`, and improved logging for `LinkageError` scenarios involving the LMAX Disruptor library. Both are the kind of fix that suggests a user report rather than a design review.
How the documentation site is built
One detail in the repository is easy to misread. There is a package.json at the root, which invites the assumption that Log4j 2 is a Node project. It is not. That file is the documentation site toolchain, and its dependencies are Antora and its defaults, Asciidoctor tabs, asciidoctor-kroki for diagram rendering, fast-xml-parser and Handlebars:
"@antora/cli": "^3.2.0-alpha.4",
"@antora/site-generator-default": "^3.2.0-alpha.4",
"@asciidoctor/tabs": "^1.0.0-beta.6"The Antora playbook lives alongside it in antora-playbook.yaml, which is how the manual at logging.apache.org is assembled from AsciiDoc sources. That is a deliberate modern choice for an old project: the documentation you are sent to for configuration syntax is generated from the same tree rather than maintained in a wiki.
The Java build is Maven, with the wrapper committed as mvnw and mvnw.cmd plus a .mvn directory and a .java-version file, so the JDK the project expects is pinned. BUILDING.adoc at the root is the build reference. Two more files show how the foundation runs releases: .cherry_picker.toml for backporting fixes onto maintenance branches, which is exactly the mechanism implied by a 2.25.5 landing days after 2.26.1, and .logging-parent-bom-activator, part of the Logging Services parent build.
There is also an AGENTS.md in the repository root, which is worth a glance before contributing, and separate CODE_OF_CONDUCT.adoc, SECURITY.adoc and NOTICE.txt files, the last of which is the Apache attribution requirement for redistributed code.
What the README does not settle
Two questions a reader arrives with are not answered anywhere in this repository, and both need the project website rather than guessing.
The first is the log level set. The README says nothing about levels, and the configuration syntax that defines them is documented on logging.apache.org. Anyone writing a first log4j2.xml needs that page.
The second is the relationship between Log4j 1.x and Log4j 2. The repository answers it structurally rather than prosaically: the log4j-1.2-api module exists so 1.x code compiles, and the release history shows Log4j 1.x is no longer the development line. What the README does not spell out is a migration procedure, which is a documentation question rather than a code question.
There is also a licensing point that is clean. The project is Apache-2.0, which means permissive use with attribution requirements, no copyleft obligation on your application code, and the usual disclaimer that it comes with no warranty. For a component that ends up inside most Java deployments, that combination of licence and maintenance cadence is the main reason it remains the default choice in many codebases.
Editorial conclusion
Log4j 2 is a reasonable default for a Java service that wants direct control of its logging configuration, and its 2.x branch is still receiving patch releases, with 2.26.1 published on 2026-07-02 and a push on 2026-09-23. The decisions to check before adopting it are narrower than the project's history suggests: which of the roughly thirty integration modules you actually need, since the API and core are the only mandatory pair, and whether your logging facade choice leaves you needing log4j-slf4j2-impl or log4j-to-slf4j. Start with the 2.x branch, add log4j-core beside log4j-api, and read the release notes on the project site, since the README itself defers build instructions and support to logging.apache.org.
Frequently asked questions
What are the key differences between @slf4j and @Log4j2, and which one should I use?
They are annotations from different libraries, and the choice depends on which implementation you want underneath. The Log4j 2 repository contains log4j-slf4j2-impl for binding SLF4J calls onto Log4j 2, and log4j-to-slf4j for the reverse, so an application can keep SLF4J at its API surface while Log4j 2 does the configuration and output.
What is the difference between Log4j and Log4j2?
Log4j 2 is a separate, actively developed implementation and it is the one on the repository's 2.x branch. The repository still carries a log4j-1.2-api module so that existing Log4j 1.x code can compile and run against Log4j 2, which is a migration path rather than a maintained 1.x.
Which Log4j 2 modules does a plain Java service need?
log4j-api and log4j-core are the mandatory pair. Everything else in the tree is an optional integration: bridges such as log4j-slf4j2-impl and log4j-to-slf4j, or appenders and integrations for Spring Boot, JDBC, JPA, MongoDB, Kafka and syslog. Add only the one your application actually uses.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/apache-logging-log4j2)