Logging in spring 3.0 under glassfish? - spring

I'm trying to debug why certain handlers in one of my controllers is not invoked by Spring's AnnotationMethodHandlerAdapter. I don't get any errors in Netbeans, just a 404 in the browser. I tried placing a breakpoint in one of my working controllers/handlers then walking up the chain to place a breakpoint in the dispatcher.
Netbeans shows me some funny method bodies:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
//compiled code
throw new RuntimeException("Compiled Code");
}
which I suspect is caused by the AOP magiq. Undeterred, I tried to configure log4j to trace the calls and display any messages logged at debug level from the org.springframework.web.servlet.mvc.annotation package, but just by creating a log4j.properties file and putting in the classpath I get nothing more than the default "INFO:" level messages. Adding the context-param and listener in web.xml fails because the container can't find the log4j classes, even though they are there and even though I can add them again to the project.
So, the question is -- what do I need to do to get method traces (this could be done through AOP) and enhanced debugging (this definitely needs log4j) under Spring 3.0?

If I'm not mistaken Spring 3.X uses SLF4J for logging. Usually you would need to add SLF4J binding for your logging framework of choice - for example, for log4, slf4j-log4j12 jar should be present in classpath as well as log4j.jar and they better be proper versions - I found SLF4J to be picky about that. See more details here. Also don't forget log4j.xml config.

Related

3rd party logging not picked up by SLF4jBridgeHandler which is attached to root logger but then removed

Our app has 3rd party code that uses JUL to log. Our app has the jul-to-slf4j.jar on the classpath. I see the SLF4JBridgeHandler.install() method gets called (several times) as for whatever reason spring cleans up logging config a few times on based on certain ApplicationEvents. I created an event listener on ApplicationStartedEvent to again make sure the handler is installed as late as possible. I verify by checking the SLF4JBridgeHandler.isInstalled() method. Yet the 3rd party logs keep flowing to standard out. If i breakpoint the 3rd party logging class in IntelliJ and call SLF4JBridgeHandler.isInstalled() it returns false. If I then execute the below code the logs get picked up by slf4j and everyone is happy.
SLF4JBridgeHandler.install();
LogManager.getLogManager().getLogger("com.3rdparty").setUseParentHandlers(false);
Why does SLF4J keep getting uninstalled? How do I keep it installed? Are the 3rd party loggers getting created before we install slf4j and then not getting updated by the install() call?
Why does SLF4J keep getting uninstalled?
Most common reason is there is code calling LogManager.reset(). You can find the source by using a security manager.
If you user a logging.properties file then just add the bridge as a handler. That way reset is actually installing the bridge handler.
handlers= java.util.logging.ConsoleHandler, org.slf4j.bridge.SLF4JBridgeHandler
The only downside is that the bridge handler has to be visible to the system classloader. A very hacky trick you can try is to subclass SLF4JBridgeHandler and override equals to return false. LogManager.reset won't be able to remove this handler.
Logger.getLogger("").addHandler(new SLF4JBridgeHandler() {
public boolean equals(Object o) { return false;}
});
Are the 3rd party loggers getting created before we install slf4j and then not getting updated by the install() call?
You'll have to do some work to find out that answer. Use JConsole Mbeans or the system out debugging to walk the logger tree while debugging your application. The security manager tracing is your best bet for finding the exact stacktrace for who is responsible for removing the handler.
Can there be two root loggers somehow?
That can't happen under the standard LogManager. Tomcat has an implementation that is sensitive to the context classloader. That LogManager may return different instances of the same logger name based on context class loader. The only other way the handlers can be removed without going through the security manager is if the root logger was garbage collected. You could try to hold a strong reference to the root logger but that really shouldn't be needed. You should print the identity hash code of the root logger when the handler was known to be added and the identity hash code of the root logger after the handler was dropped. If the values are different the logger was garbage collected.

How to debug transactions in spring?

How can I debug the transactions in my spring boot application ?
Is there a way to see how method calls get grouped in a transaction context or another ?
You have asked 2 broad questions here.
1. How to debug a transaction (assuming from your post title, you are looking for logging)
The simplest way to achieve is to use the bundled java.util.logging.Logger in SpringBoot.
Below code snippet should tell you how:
public class EmojiController {
private final static Logger logger = Logger
.getLogger(EmojiController.class.getName());
public ModelAndView getEmoji() {
logger.info("emoji: " + emojiId + " lookup initiated");
---do something---
}
By default, If you use the ‘Starters’, Logback will be used for logging. Appropriate Logback routing is also included to ensure that dependent libraries that use Java Util Logging, Commons Logging, Log4J or SLF4J will all work correctly.
2. Grouping the method calls related to one transaction:
This is a very wide topic and has even wider application when asked in the context of distributed application architecture like, micro-services. The point is, how do you relate various log entries with each other to group them for a wholistic view.
The solution for that lies in the concept called Distributed Tracing. You can read in detail about that in this wonderful post from Josh Long.
More detailed documentation on the discussed technologies can be found here -
Sleuth - http://cloud.spring.io/spring-cloud-sleuth/spring-cloud-sleuth.html
ZipKin - http://zipkin.io/
It should help you achieve what you want but in case you have more questions on their usage, please raise another question.
--- EDIT ---
There's a section about Logging in the Spring Reference.
It shows how to configure different logging frameworks, among them log4j
In your case the last line of the config would be:
log4j.logger.org.springframework.transaction=DEBUG

Spring Security 4 sessionRegistry doesn't populate Principal list

I am trying to implement a function where a admin user can terminate another user's session. I followed the official Spring Security documentation here: http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#list-authenticated-principals and started with getting all currently logged in users through sessionRegistry.getAllPrincipals(), but it always returned an empty list.
I set a breakpoint in SessionRegistryImpl.registerNewSession() and could see it did indeed get invoked and it did add the UserDetails (my own implementation with both equals() and hashCode() implemented) to the hashmap principals. But when I access sessionRegistry bean from a Spring MVC controller, the list is always empty.
My configuration looks pretty much the same as the documentation.
How to fix this? Did anyone successfully get SessionRegistry to work with Spring Security 4? I remember I made it work with Spring Security 3 by following these intructions(enter link description here)
OK, so I fixed the issue by cleaning up the Spring configuration files, as suggested by the comments. Someone messed up with the web.xml - he added a reference to the context XML that is already referenced by the Spring's DispatcherServlet, causing it to be loaded twice. He didn't know it, because Spring references the file implicitly.
P.S.
I learned my lessons, but 2 things the Spring folks could do better (maybe in Spring 5?):
There shouldn't be implicit context file loading. Currently, the framework will try to load the application context from a file named [servlet-name]-servlet.xml located in the application's WebContent/WEB-INF directory. Convention over configuration fails in this case.
There should be warning when a bean is loaded twice, if someone need to override a bean definition, he must declare explicitly. Otherwise it would take a lot of time to debug the kind of error this mistake will cause.

Changing application context path leads to using different (unknown) logging configuration

Setup:
Tomcat 6.0.16
Struts 2.1.6
Apache Commons Logging 1.0.4
Log4J 1.2.17
What I did:
Change in server.xml:
<Context path="/" .../></Context>
to
<Context path="/shop" .../></Context>
The issues:
Everything in the application is working fine (on the first glance). All links are correct and working etc.
Now I discovered that the Loggers using Commons Logging (with Log4J) (usually the Loggers in Spring, Struts and OGNL) are using a different logger configuration than the default used before. Loggers using Log4J directly in the application are working fine with this configuration.
For debugging purpose I have a JSP listing all the loggers with:
Logger.getRootLogger().getLoggerRepository( ).getCurrentLoggers()
But the "commons logging logger" are not listed anymore, although I could verify that they exist if I debug the code.
The question:
How do I find the other configuration/root logger?
Do I have to change anything in the struts configuration (or somewhere else) in relation to the context path change?
Any ideas what the issue might be here?
Edit: I'm getting closer:
The platform I am using is loading a minimal logging at start up. Before changing the context the advanced logging was loaded right afterwards and everything was fine. For some reason the listener of the web.xml (Spring initialization, etc.) is now running before the advanced logging is loaded. These classes are using the apache commons logging api and get loggers assigned basing on the simple root logger. Right afterwards the root logger is replace by the platform but the commons loggers are not updated with the new configuration.
New question:
As I stated below, changing anything in the platform is no option. So why did the listener run earlier when I change the context and how can I prevent this.
For the sake of the moment Apache Tomcat uses JDK logging. If you didn't place commons-logging.properties file to your source dir the default logger using commons logging will be log4j. Anyway the Tomcat will not use that logging because it needs a special configuration to tell it to use log4j.
The root logger is what you use in the log4j configuration. For example
log4j.rootLogger=ERROR,Console
Changing context path is nothing related to the logging used by application.
I didn't see any issue with logging rather that in recent releases regarding implementation priority.
The logging creates a dependency between multiple tomcat web application and due this fact requires a specific order of loading this modules. Renaming the context to "/shop" leads to an other order as StandardContext.filterDefs is a simple HashMap and does not preserve the order of the server.xml.
I could fix my issues in running the required steps in a listener.
web.xml
<listener>
<listener-class>com.[...].InitListener</listener-class>
</listener>
InitListener.java
package com.[...];
public class InitListener
{
static
{
// init Log4J, etc.
}
}
{code}
(Btw. Listener order should be identical to the web.xml)

Spring: "SimpleLogger does not seem to be location aware" exception

I'm getting an exception in a Spring app on my first line of code:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
I have commons-logging-1.1.1.jar configured as a project library.
Here is the stack trace:
java.lang.UnsupportedOperationException: The logger [org.slf4j.impl.SimpleLogger(org.springframework.context.support.ClassPathXmlApplicationContext)] does not seem to be location aware.
at org.apache.log4j.Category.log(Category.java:347)
at org.apache.commons.logging.impl.Log4JLogger.info(Log4JLogger.java:199)
at org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:456)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:394)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
Looks like you are using multiple logging frameworks at the same time. This error seems to be a symptom of a clash between your SLF4J and Log4J configurations.
Take a look at this post:
http://www.qos.ch/pipermail/slf4j-user/2010-February/000892.html
which states,
The code log(String FQCN, Priority p,
Object msg, Throwable t) method throws
an exception because the caller
expects location aware logging but the
actual logger implementation is not
capable of delivering "location
awareness".
Without more information, my best guess is that you have a reference to an slf4j jar like slf4j-nop-1.6.1.jar or something else that's turning off logging by pointing to Non-Operational implementation of the Logger class.
Find the culprit and delete it (or replace it with the slf4j-log4j version).
Are you using Maven?
If so, open the dependency graph of your pom file and search for all dependencies with slf4j in their name. Delete the one that looks like a NOOP jar.

Resources