Alternatives to SLF4J MDC - java

I'm trying to log the user name initiating each request in my JSF application, however apparently MDC on a web app server (thread pool) is risky.
I've already seen MDC leaking out into a new call when using the EJB #Asynchronous call which I wouldn't have expected.
What are the alternatives? I'd rather not have to rely on remembering to put the username on every log call. Do I wrap slf4j?

Clear your MDC put(..) with remove(..) in a try-finally block
MDC.put("system", "fedora");
try {
// your code here
} finally {
MDC.remove("system");
}
so that no state is kept after your code has run.

Related

Can I change the level of a message logged by Spring?

Our Spring-based microservice sometimes fails to connect to its eventing service for a couple of minutes. This is okay from an application point of view, as we have several retries and fallbacks in place that take care of this. Each failed connection attempt results in an ERROR log written by the class org.springframework.jms.listener.DefaultMessageListenerContainer. Is it possible to configure Spring such that this log message would be written with a lower log level, such as WARN?
As #Jens mentioned this is not possible since the level at which a message is logged is given by the actual function call.
So, if Spring (or any other library or even your own code, really) has something like:
public void connect() {
try(establishConnection()) {
// ...
} catch (Exception e) {
log.error("Failed to establish connection");
}
you'll notice that the logging is always done at the error level, since that is what is being invoked.
The only recourse you have in this case is to set the log level of the class to OFF if your given logging implementation supports it (the default, Logback, does). For example:
# application.yml
logging.level:
org.springframework.jms.listener.DefaultMessageListenerContainer: OFF
However, there's really no reason to do this unless you are getting absolutely swamped by these log messages (and even then, just filter them in your Dashboard). Error logs exist for a reason.
Alternatively, I suppose you could also do some hacky trickery using AspectJ to change the level something is logged at if you really, really needed to, but I doubt this applies in this case.
Lastly, you can fork the library and link your own Jar files into your application. But I doubt this maintenance burden is worth it in this case.
This is not possible because the level at which a message is logged is given by the actual function call. .
So, if Spring has something like:
public void connect() {
try(establishConnection()) {
// ...
} catch (Exception e) {
log.error("Failed to establish connection");
}
you'll notice that the logging is always done at the error level, since that is what is being invoked.
What you can do is to set the log level of the class to OFF :
# application.yml
logging.level:
org.springframework.jms.listener.DefaultMessageListenerContainer: OFF

Guice Request Scope for tracing workflow of request

I have a use case where I have 6 steps being performed in one request. The business is requesting that we capture metrics on what the result of each step was in the process. They want us to log to a Kinesis stream.
Architecturally I am looking at the best solution. We have java based services I want to have a request scoped object enriched as the request progresses, then when the endpoint finishes we would make a service call to kinesis asynchronous using a fire and forget pattern. This way the reporting is not holding up the main thread.
I was looking at using the raw ThreadLocal or guice scope. Has anyone ran into to a similar problem that they solved? Im thinking of use guice request scoped components, which will greatly simply the code. Just looking for some opinions. Thanks!
I'm assuming you aren't on a servlet environment because, then, you will just use the built in request scope. Even then you can use the request scope from guice-servlet building the scope yourself.
void processRequest() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
step1();
step2();
step3();
step4();
step5();
step6();
}
}
You can use #RequestScoped and it will be the same object on all your steps. You can, for example, use a provider to get access to it.

getRequestDispatcher() is returning null (Portlet)

I am working on a Java Portlet (extending GenericPortlet), using JBoss 7.02 and LifeRay Portal 6.1.0 GA1. This is one of the bundles that can be downloaded from LifeRay's release archive.
During deployment, when the init() method is called, getRequestDispatcher() returns null. Below is the exact error message:
09:22:15,972 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/my-portlet-name]] (MSC service thread 1-15) Error during mapping: java.lang.NullPointerException
Below is a snippet from my init() method:
PortletConfig config = getPortletConfig();
PortletContext context = getPortletContext();
PortletRequestDispatcher normalView = context.getRequestDispatcher("/portlet.jsp");
As a temporary workaround, I have moved all getRequestDispatcher() calls to doView() where it executes without problem. I do not understand why getRequestDispatcher() can locate portlet.jsp when called during doView, but not when its called during init()
Am I missing a preceding call of some other method that would resolve this? Is this a known issue?
Thanks for any help.
Getting the request dispatcher in the doView is the only place I've seen it done. I would imagine that it returns null during init because there is no actual request to dispatch.
Typically the init method is used for time-expensive operations that you don't want to incur for each request. This might be something like reading data from a file, or creating a reusable SQL connection.
You should also keep in mind that you should keep any portlet state thread safe. Don't create class or object variables that can only be used for one request at a time. The portlet methods are not inhererently thread safe, so you need to make sure that whatever variables a request is interacting with won't be manipulated by another request that is executing concurrently.
I'm not familiar with Portlets, but the answer should be the same as for Servlets.
The init() method is called exactly once, when your application is initially deployed. There is no active request (no one is asking for anything) or response (no one is going to read what the output is). Therefore, it is very reasonable forgetRequestDispatcher() to return null. In doView(), when you're handling a request and response, it makes sense to ask another resource to generate part (or all) of the response.
To address your question directly, getRequestDispatcher() has no problem locating portlet.jsp from init(); it's the request that's missing. (Where do you expect to see the result of portlet.jsp, anyway?)
If you do want to print some output during initialization, you can try logging it to a file, if your application is set up for that. Or, you can display data on System.out, if you know where the container's console is. (I use this second option quite often with servlets.)

Spring declarative transactions and manually scheduling threads

I'm having a strange issue.
In a class I have:
private final ScheduledExecutorService executor
= Executors.newSingleThreadScheduledExecutor();
public MyClass(final MyService service) {
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
service.foo();
}
}, 0, 30, TimeUnit.SECONDS);
}
MyService is a spring bean that has #Transactional on its foo method. MyClass is instantiated only once (effectively singleton in the application)
After the first invocation of service.foo() (which works fine), on subsequent requests to the application I am randomly getting:
java.lang.IllegalStateException: Already value [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[]])] for key [org.hibernate.impl.SessionFactoryImpl#2cd91000] bound to thread [http-bio-8080-exec-10]
A few observations:
when the exception is thrown, the session stored in the TransactionSynchronizationManager is closed
the transaction synchronization manager resource map for the manually scheduled thread is empty
the exception occurs in http-bio-8080-exec threads, but the manually scheduled one is a pool- thread - so there is no 'thread polution'
MyClass is instantiated on startup, in a thread named "Thread-5", i.e. it is not in any way related to the http-bio threads.
If I comment the invocation to service.foo(), or get rid of the #Transactioanl annotation, everything works (except, of course, that data is not inserted in the db)
Any clues what the issue might be?
(Note: I prefer not to use #Scheduled - I don't want MyClass to be a spring bean, and the runnable has to operate on some of its internal state before invoking the service)
Update: After a while I'm able to reproduce it even without the scheduling stuff. So probably a general spring problem with the latest snapshot I'm using.
I assume that exception comes from an invocation of the TransactionInterceptor or the like (some Spring infrastructure bean), or are you using the TransactionSynchronizationManager from your own code somewhere? It appears to me that something is binding sessions to a thread being managed by your container (is that Tomcat 7?) and failing to unbind them before they're returned to the container's thread pool. Thus when the same thread is used for another transactional request later, Spring can't bind the new Session to it because the old one wasn't cleaned up.
I don't actually see anything to make me think it's directly related to your custom scheduling with MyClass. Are you sure it's not just a coincidence that you didn't see the exception when you remove the service.foo() call?
If you could catch one of those threads in a debugger when it's being returned to the pool with a Session still bound to it, you might be able to backtrack to what it was used for. An omniscient debugger would theoretically be perfect for this, though I've never used one myself: ODB and TOD are the two I know of.
Edit: An easier way to find the offending threads: add a Filter (servlet filter, that is) to your app that runs "around" everything else. After chain.doFilter(), as the last act of handling a request before it leaves your application, check the value of TransactionSynchronizationManager.getResourceMap(). It should be an empty map when you're done handling a request. When you find one that isn't, that's where you need to backtrack from to see what happened.

EJB3 - handling RollBackExceptions

I have an EJB3 application which consists of some EJB's for accessing a DB, and exposed via a Session Bean as a web service.
Now there are two things I need to find out:
1) Is there any way I can stop SQL exceptions from causing the web service from throwing a SOAP Fault? The transactions are handled by the container, and currently sql exceptions cause a RollBackException to be thrown, and consequently the transaction to be rolled back (desired behaviour) and the web service to throw a fault (not desired).
2) I wish to extend the webservice to be able to take in a list of entities, and the session bean to persist each. However, I want each entity to be executed in its own transaction, so that if one fails the others are not affected (and again the web service should not fault).
For (1) I have tried to catch the RollBackException, but I assume this is thrown somewhere on another thread, as the catch block is never reached. I assume for (2) I will need to look into User Transactions, but firstly would prefer the container to manage this, and secondly do not know how to force the use of user transactions.
Thanks.
no, you can do all this with container managed transactions (and this is definitely preferable, as managing transactions is a pain).
the gist of the solution is to create a second EJB with a local interface only and the transaction semantics you desire. then your "public" ejb, which the web-service is calling directly, calls into this second ejb via its local interface to do the actual work.
something along the lines of:
public class MyPublicEjb {
#EJB
private MyPrivateImpl impl;
public void doSomething() {
try {
impl.doSomething();
} catch(TXRolledBack) {
// handle rollback ...
}
}
}
I know this looks sort of ugly, but trust me, this is far preferable to directly manipulating transactions.
For (1): Debug your code to find out where the exception is being thrown and what is causing it. Then handle the exception there.
For (2): Wrap each instance with beginTransaction() and commit().
for(each Entity){
try{
//begin transaction
//save entity
//commit
} catch(Exception e) {
//handle Exception, but continue on
}
}

Categories