-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revisit Commons Logging vs java.util.logging vs SLF4J vs Log4j 2 [SPR-14512] #19081
Comments
Marten Deinum commented I really hope Spring won't come up with YALA (Yet Another Logging Abstraction) as there are already many of those (this xkcd comic comes to mind). Also auto-detection of loggers isn't that what made a mess out of Commons Logging in the first place?!. |
Juergen Hoeller commented From my perspective, Commons Logging just has a bad reputation due to its rather naive early versions, but also due to the personal agenda of SLF4J's original creator. Anyway, leaving history aside, Commons Logging actually works quite well in its later incarnations as long as its API as well as the logging provider are shipped with the application. Runtime detection is only an issue if the Commons Logging API itself is shipped in common class loaders (e.g. Tomcat level), with the actual logging provider living in a more specific class loader (e.g. WAR level). That wouldn't work with SLF4J either but nobody even attempted it there so nobody perceived it as a design flaw. In all other respects, Commons Logging is not really different from what many other frameworks do in terms of runtime detection, including us all over the place against so many third-party providers. I mean, take Boot... As for this ticket, it is primarily about improving usage scenarios:
And as a bonus, we'd love a richer logging API available to us internally. Log4J 2's API looks most attractive there among the existing options. A custom So with those goals taken into account, I'm not quite sure what the solution will be. The only friction-free outcome might be a logging arrangement of our own, possibly with variants of the Commons Logging API classes shipped in |
Juergen Hoeller commented A related discussion, including what libraries should be doing: https://www.reddit.com/r/java/comments/5mqkq5/why_you_should_prefer_the_log4j2_api_to_slf4j_in/ |
Phil Webb commented One sensible step in 5.0 might be to make all |
Juergen Hoeller commented We don't accidentally expose protected If we turned all |
Juergen Hoeller commented I've opted for the approach with an embedded This implementation does not support any of Commons Logging's flexible configuration. In that sense, it works as a replacement for the Log4j 2 Commons Logging bridge as well as the JCL-over-SLF4J bridge, both of which become irrelevant for Spring-based setups as a consequence (with no need for manual excludes of the standard Commons Logging API jar anymore either). Furthermore, for simple setups without an external logging provider, Spring does not require any extra jar on the classpath anymore since our embedded log factory automatically switches to The Log4j 2 and SLF4J bridges will still work when on the classpath, with either such an external bridge or our As a side note, our new This arrangement works fine for me locally, so I'll commit it to master tonight. Let's see what the platform integration tests say... |
Phil Webb commented Will this cause classloader issues if an app server provide a version of the commons-logging jar? The problem I can see with this approach is there's now no way to exclude We're also very likely to end up in the situation where two copies of I know the existing |
Phil Webb commented /cc Andy Wilkinson since he's been involved in the Spring Boot |
Juergen Hoeller commented As I was hinting at above, the Log4j 2 and SLF4J bridges will still work when on the classpath: It's then just a matter of classpath order, but since our own bridge and their bridges lead to the same end delegate, the outcome doesn't really matter. And in the end, the whole point is that those bridges shouldn't be on the classpath anymore. Since no libraries bring those bridges onto the classpath themselves, this is something Boot 2.0 can control in its project starter setups. As for application server scenarios, application-local classes always override server-level classes. From our perspective, we always want our delegate to be used, never the application server's. There can't be any cast exceptions either if our local variant is consistently used. It's certainly worse if somebody forgets to declare a Commons Logging dependency and unintentionally ends up using a server-level Commons Logging API with a locally embedded logging provider; that leads to exactly the class-cast pain that Commons Logging is so famous for. As far as I can see, our embedded setup avoids any such potential. That said, let's see what we encounter in integration tests. I'd at least like to try this approach and see how far we get in our CI builds. |
Andy Wilkinson commented As I was reading the description of the changes, the same concern that Phil's described came to mind. I'm not sure that we'll end up with class cast exceptions as the parent class loader's version should be preferred, but it does sound like the new arrangement will be very sensitive to a second copy of the |
Juergen Hoeller commented Talking to Phil on Skype, I'll push this tonight and we can see how it goes, rolling it back if necessary. Andy, I've been spending quite a bit of time looking at third-party projects around us, and as far as I'm aware, as of Spring 5, we do not support any that bring in Commons Logging anymore (e.g. no Velocity anymore). So this shouldn't be a problem in practice, and if it is for some esoteric case, we can work out a solution for those affected. My take is simply that we need to first-class align with Log4J 2 as well as SLF4J out there, and equally well with At least, Log4J 1.x is EOL now, as are other historic Commons Logging backends. We literally only have three logging API targets to deal with in 2017. |
Juergen Hoeller commented A deep-dive brought forward that we technically still got three supported optional dependencies which depend on Commons Logging:
All of them seem to work fine against our embedded variant, but of course all three declare a dependency on Commons Logging in their POM and therefore require an explicit exclude in order to arrive at a clean classpath. That's no different from using them with the regular Log4J 2 Commons Logging adapter or with JCL-over-SLF4J, of course, in which case they require the same exclude. And for |
Andy Wilkinson commented In aligning Spring Boot with this change, it's become apparent that we also need to consider dependencies upon |
Juergen Hoeller commented Oliver Drotbohm, since you've been the original trigger for this change, I suppose dropping |
Andy Wilkinson commented This change has caused an interesting failure in Spring Boot's Maven plugin (it depends upon
As far as I can tell, the Plexus class loader allows
Could the check in |
Oliver Drotbohm commented I am happy to remove the dependency to |
Juergen Hoeller commented
We could differentiate between |
Juergen Hoeller commented I've pushed a revision which differentiates between |
Oliver Drotbohm commented Bringing this up to the team today we've wondered: if our |
Juergen Hoeller commented This only fails if there is some explicit validation for overlapping packages on the classpath in the build process, like with Boot's starters - which is a good thing. In a lenient runtime arrangement, it's simply first-one-wins on the classpath. Since either adapter eventually delegates to SLF4J there, it won't make a difference. |
Andy Wilkinson commented I've identified this change as the cause of a problem in Spring Boot. The root cause is a call to |
Juergen Hoeller commented As per my concurrent comment on the Boot issue, this is aligned in our |
Juergen Hoeller commented I've revisited a simple but noteworthy part of the Commons Logging API: It accepts messages of type This means that callers of our Commons Logging bridge (in particular: our own framework code) can rely on lazy resolution of log message objects now, without extra From that perspective, I see no need for a logging SPI to have native message argument support or |
Juergen Hoeller commented Since WebSphere traditionally ships its own variant of Commons Logging, I've researched the impact of our embedding on Spring-on-WebSphere deployment: In "Parent First" mode, it's always WebSphere's own version of Commons Logging getting picked up. It does not make a difference whether the application contains a variant of Commons Logging itself: an application-level variant is always being ignored. Therefore it doesn't make a difference whether we embed our own variant versus JCL-over-X bridges or the standard Commons Logging jar. In "Parent Last" mode (which we generally recommend for Spring applications on WebSphere), our embedded bridge will be picked up, just like JCL-over-X bridges before. The only option not available anymore is "Parent Last" with no Commons Logging API in the application but this doesn't make much of a difference: Our embedded bridge will delegate to That said, there is one specific feature of WebSphere's Commons Logging variant that we can easily adopt: support for JUL The most important limitation of our embedded bridge is that - like the JCL-over-SLF4J and JCL-over-Log4J bridges - it doesn't support custom
|
Juergen Hoeller commented I've revised our logging chapter in the reference documentation accordingly: including setup instructions for Log4j 2.x, SLF4J with Logback, |
Juergen Hoeller commented On a related note, here's a summary of our optional third-party libraries and their hard logging dependencies: SLF4J (still requiring an extra
Commons Logging (requiring a manual
JBoss Logging (with Log4j and SLF4J detected at runtime plus a fallback to JUL, without extra bridge jars - just like in Spring 5):
It's noticeable that our most relevant companion is actually JBoss Logging now... which we are very nicely aligned with. SLF4J isn't as common as a primary API choice as the community at large seems to believe: For our purposes, it is Logback's API, with a side job as the logging facade for a couple of second-tier libraries. |
Juergen Hoeller commented I'm considering to move our |
Sam Brannen commented I think |
Rob Winch commented Juergen Hoeller I've come up with another use case for spring-jcl. At the moment Spring Session's only required dependency is commons-logging. As I see it, there are two options for it: Have a compile time dependency on commons-logging and require spring-core users to exclude commons-logging. This is probably a majority of our users, so is probably not ideal. Have an optional dependency on commons-logging and require non spring-core users to add commons-logging as a dependency. An even better option might be to have the spring-jcl module which Spring Session could depend on. This would solve both scenarios for users. Thoughts? |
Juergen Hoeller commented Good point, Rob. We'll extract a |
Juergen Hoeller opened SPR-14512 and commented
Following up on recent discussions about the good old Commons Logging vs SLF4J conflict (a manual exclusion needed in the POM etc) and the recent attractiveness of Log4J 2's logging API:
Let's revisit our logging API arrangement. A straight migration to SLF4J doesn't seem to be a worthwhile option from a 2017 perspective, in particular since Log4J 2 actually has a nicer API. However, a straight migration to Log4J 2 isn't ideal either since so many people use SLF4J at the moment. And of course, none of those "simple" migration options addresses the problem of backwards compatibility with Spring extensions which happen to use our exposed protected logger reference... which is a hard Commons Logging reference in pre-compiled binaries.
Beyond a straight migration, we may also introduce our own logging abstraction (sigh). Alternatively, we could ship a variant of the Commons Logging API in our own
spring-core.jar
, controlling the target binding through our own adaptive setup logic: This is essentially what the JCL-over-SLF4J adapter does, and it seems to work fine there. As long as we're able to bind tojava.util.logging
, SLF4J and Log4J 2 without too much hassle (ideally through autodetection in the classpath), it might be a sweet compromise for the backwards compatibility issue.Of course, it would also be nice to have a richer logging API available for our internal purposes. Log4J 2 looks quite attractive there but we might not want to require it at runtime, in particular for SLF4J users or
java.util.logging
users in application server environments. We could also use a facade of our own internally or augment our variant of Commons Logging accordingly.Affects: 5.0 M1
Issue Links:
0 votes, 11 watchers
The text was updated successfully, but these errors were encountered: