logging-capabilities
logging-capabilities copied to clipboard
= Logging Capabilities Gradle Plugin
:tip-caption: :bulb: :note-caption: :information_source: :important-caption: :heavy_exclamation_mark: :caution-caption: :fire: :warning-caption: :warning:
WARNING: This plugin has been merged with the GradleX https://github.com/gradlex-org/jvm-dependency-conflict-resolution[jvm-dependency-conflict-resolution] plugin. Please update to that other plugin and report issues there. I will follow up on the existing issues here and move the relevant ones to the new plugin.
Ever seen this infamous Slf4J warning?
[source]
SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:.../slf4j-log4j12-1.7.29.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:.../logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
Ever wondered how to make sure all your dependencies' logging ends up in your Log4J 2 configuration?
Then this plugin is for you!
It is built on the https://docs.gradle.org/6.0.1/userguide/component_capabilities.html[Gradle capabilities feature], to detect and optionally select a Java logger implementation so that it is enforced at build time!
== Plugin application and compatibility
[source,kotlin]
plugins { id("dev.jacomet.logging-capabilities") version "0.11.0" }
Have a look at https://plugins.gradle.org/plugin/dev.jacomet.logging-capabilities[the documentation on the plugin portal] for alternate or DSL specific syntax.
|=== | Gradle version | Available feature
| Gradle 5.0+ | The detection part is available
| Gradle 6.0+ | The configuration part is available
| Gradle 8.0+ | All features available, requires version 0.11.0 or above of the plugin
|===
== Detection of invalid logging configurations
Upon application, this plugin defines a set of https://docs.gradle.org/6.0.1/userguide/component_metadata_rules.html#basics_of_writing_a_component_metadata_rule[component metadata rules] that add capabilities to relevant logging related dependencies. The added capabilities and impacted modules can be found in the table below:
|=== | Capability | Impacted modules | Comment
| slf4j-impl
| org.slf4j:slf4j-simple
, org.slf4j:slf4j-log4j12
, org.slf4j:slf4j-jcl
, org.slf4j:slf4j-jdk14
, ch.qos.logback:logback-classic
, org.apache.logging.log4j:log4j-slf4j-impl
, org.apache.logging.log4j:log4j-slf4j2-impl
| Represents an Slf4J binding
| log4j2-impl
| org.apache.logging.log4j:log4j-slf4j-impl
, org.apache.logging.log4j:log4j-slf4j2-impl
, org.apache.logging.log4j:log4j-core
| Represents the native Log4J 2 implementation or delegation to Slf4J
| log4j2-vs-slf4j
| org.apache.logging.log4j:log4j-slf4j-impl
, org.apache.logging.log4j:log4j-to-slf4j
| Represents the Slf4J / Log4J 2 relationship: which one delegates to the other
| slf4j-vs-log4j
| org.slf4j:log4j-over-slf4j
, org.slf4j:slf4j-log4j12
| Represents the Slf4J / Log4J 1.2 relationship: either Slf4J intercepts or binds to Log4J
| slf4j-vs-log4j2-log4j
| org.slf4j:log4j-over-slf4j
, org.apache.logging.log4j:log4j-1.2-api
, log4j:log4j
| Represents the available Log4J implementation: native, with Slf4J or with Log4J 2
| slf4j-vs-jul
| org.slf4j:jul-to-slf4j
, org.slf4j:slf4j-jdk14
| Represents the Slf4J / java.util.logging
relationship: either Slf4 intercepts or binds to JUL
| slf4j-vs-log4j2-jul
| org.slf4j:jul-to-slf4j
, org.apache.logging.log4j:log4j-jul
| Represents JUL replacement: either with Slf4J or with Log4J 2
| commons-logging-impl
| commons-logging:commons-logging
, org.slf4j:jcl-over-slf4j
, org.springframework:spring-jcl
| Represents Apache Commons Logging implementation: native or Slf4J
| slf4j-vs-jcl
| org.slf4j:jcl-over-slf4j
, org.slf4j:slf4j-jcl
| Represents the Slf4J / Apache Commons Logging relationship: either Slf4J intercepts or binds to commons-logging
| slf4j-vs-log4j2-jcl
| org.slf4j:jcl-over-slf4j
, org.apache.logging.log4j:log4j-jcl
| Represents the Slf4J or Log4J 2 interception of commons-logging
|===
TIP: All capabilities are in the group dev.jacomet.logging
With the set of capabilities defined above, all configuration resolutions in Gradle will fail if conflicting modules are found in the graph.
== Alignment of logging libraries
In addition to the capability setting and conflict detection, the plugin also registers https://docs.gradle.org/6.0.1/userguide/dependency_version_alignment.html#sec:align-versions-virtual[alignment rules] for Slf4J and Log4J 2 modules.
Due to a bug in Gradle versions [5.2, 6.2[
, alignment is disabled by default for these versions.
Users with Gradle [6.0, 6.2[
can opt back in with loggingCapabilities.enableAlignment()
.
Note that enabling alignment for these versions may cause some capabilities conflict to remain undetected.
See https://github.com/ljacomet/logging-capabilities/issues/4[this issue] for details.
== Expressing preference over a logging solution
The plugin also contributes a project extension that allows to configure which logging solution to use in a declarative fashion. This solution is https://docs.gradle.org/6.0.1/userguide/dependency_capability_conflict.html#sub:selecting-between-candidates[based on APIs] introduced in Gradle 6.0.
The extension is accessed as follows:
[source,kotlin]
// Assuming the plugin has been applied loggingCapabilities { // Configuration goes here }
TIP: The different configuration options documented below do not add dependencies. Make sure to have the expected dependency in your graph, either as a direct or transitive one.
The plugin first provides a number of high-level, one stop solutions, for selecting a logging solution:
|=== | Method | Documentation | Required dependency
| enforceLogback()
+
enforceLogback(String configurationName)
| This will configure all capabilities to resolve in favour of http://logback.qos.ch/[LOGBack] and route all alternative logging solutions through Slf4J.
| ch.qos.logback:logback-classic
| enforceLog4J2()
+
enforceLog4J2(String configurationName)
| This will configure all capabilities to resolve in favour of http://logging.apache.org/log4j/2.x/[Log4J 2] and route all alternative logging solutions through Log4J 2.
| org.apache.logging.log4j:log4j-slf4j-impl
| enforceSlf4JSimple()
+
enforceSlf4JSimple(String configurationName)
| This will configure all capabilities to resolve in favour of Slf4J simple and route all alternative logging solutions through Slf4J.
| org.slf4j:slf4j-simple
|===
TIP: The method without parameter will apply the setup to all dependency configuration, while the other one will limit the setup to the specified dependency configuration.
If you want a finer grained control, the plugin provides lower level entry points for solving the different logging capability conflicts: |=== | Method | Accepted parameter values | Documentation
| selectSlf4JBinding(Object notation)
| Value must be an Slf4J binding implementation known by the plugin: org.slf4j:slf4j-simple
, org.slf4j:slf4j-log4j12
, org.slf4j:slf4j-jcl
, org.slf4j:slf4j-jdk14
, ch.qos.logback:logback-classic
or org.apache.logging.log4j:log4j-slf4j-impl
| Configures the provided Slf4J binding for selection, configuring related capabilities if needed
| selectSlf4JBinding(String configurationName, Object notation)
| A dependency configuration name, that canBeResolved=true
+
A notation as above
| Configures the provided Slf4J binding for selection, configuring related capabilities if needed, only for the provided dependency configuration
| selectLog4J12Implementation(Object notation)
| Value must be a Log4J 1.2 implementation known by the plugin: org.slf4j:log4j-over-slf4j
, org.apache.logging.log4j:log4j-1.2-api
, log4:log4j
or org.slf4j:slf4j-log4j12
| Configures the provided Log4J 1.2 implementation for selection, configuring related capabilities if needed
| selectLog4J12Implementation(String configurationName, Object notation)
| A dependency configuration name, that canBeResolved=true
+
A notation as above
| Configures the provided Log4J 1.2 implementation for selection, configuring related capabilities if needed, only for the provided dependency configuration
| selectJulDelegation(Object notation)
| Value must be a java.util.logging
interceptor or binding known by the plugin: org.slf4j:jul-to-slf4j
, org.slf4j:slf4j-jdk14
or org.apache.logging.log4j:log4j-jul
| Configures the provided JUL integration of binding for selection, configuring related capabilities if needed
| selectJulDelegation(String configurationName, Object notation)
| A dependency configuration name, that canBeResolved=true
+
A notation as above
| Configures the provided JUL integration for selection, configuring related capabilities if needed, only for the provided dependency configuration
| selectJCLImplementation(Object notation)
| Value must be a Apache Commons Logging interceptor or binding known by the plugin: org.slf4j:jcl-over-slf4j
, commons-logging:commons-logging
, org.slf4j:slf4j-jcl
or org.apache.logging.log4j:log4j-jcl
| Configures the provided commons logging interceptor or binding for selection, configuring related capabilities if needed
| selectJCLImplementation(String configurationName, Object notation)
| A dependency configuration name, that canBeResolved=true
+
A notation as above
| Configures the provided commons logging interceptor or binding for selection, configuring related capabilities if needed, only for the provided dependency configuration
| selectSlf4JLog4J2Interaction(Object notation)
| Value must be a Log4J 2 module for Slf4J interaction known by the plugin: org.apache.logging.log4j:log4j-to-slf4j
or org.apache.logging.log4j:log4j-slf4j-impl
| Configures the Log4J 2 / Slf4J integration, configuring related capabilities if needed
| selectSlf4JLog4J2Interaction(Sting configurationName, Object notation)
| A dependency configuration name, that canBeResolved=true
+
A notation as above
| Configures the Log4J 2 / Slf4J integration, configuring related capabilities if needed, only for the provided dependency configuration
|===
TIP: Notations above are those accepted by https://docs.gradle.org/6.0.1/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html#org.gradle.api.artifacts.dsl.DependencyHandler:create(java.lang.Object)[DependencyHandler.create(notation)
] in Gradle that resolves to an ExternalDependency
.
Most often this is a group:name:version
String
.
== Building and reporting issues
You will need a JDK 8+ to build this project.
WARNING: This build is configured to publish build scans always.
Use the GitHub issue tracker for reporting bugs and feature requests.