Spring MBeanExporter: Log an exception's stacktrace
In Spring MVC, an exception's stack trace is logged if it makes it all the way back up to the framework (for example, if there is a NullPointerException). Is there a simple way to do this using Spring's MBeanExporter?
I know that I could have try-catches in the method to do this, but that would lead to clutter. I checked the Spring documentation (Chapter 22 is the one on JMX) and didn't see anything. I also haven't seen anything on SO. I also looked at the source code for MBeanExport开发者_JS百科er, and there seems to be a way to register listeners for MBean registration, but not for MBean request handling.
In my application based on Spring 3.1, neither @ManagedAttributes nor @ManagedOperations are caught or logged.
So I went through an extension of MBeanExporter, which fails whenever a MBean method call fails:
public class LoggingFailedCallsMBeanExporter extends MBeanExporter {
protected ModelMBean createModelMBean() throws MBeanException {
// super method does:
// return (this.exposeManagedResourceClassLoader ? new SpringModelMBean() : new RequiredModelMBean());
ModelMBean superModelMBean = super.createModelMBean();
// but this.exposeManagedResourceClassLoader is not visible, so we switch on the type of the returned ModelMBean
if (superModelMBean instanceof SpringModelMBean) {
return new SpringModelMBean() {
@Override
public Object invoke(String opName, Object[] opArgs, String[] sig) throws MBeanException, ReflectionException {
try {
return super.invoke(opName, opArgs, sig);
} catch (MBeanException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (ReflectionException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (RuntimeException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (Error e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
}
}
};
} else {
return new RequiredModelMBean() {
@Override
public Object invoke(String opName, Object[] opArgs, String[] sig) throws MBeanException, ReflectionException {
try {
return super.invoke(opName, opArgs, sig);
} catch (MBeanException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (ReflectionException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (RuntimeException e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
} catch (Error e) {
LOGGER.warn("Issue on a remote call", e);
throw e;
}
}
};
}
}
MBeanExporter
is a very flexible thing, and can handle many different situations. Since you showed us no sample code, I'll assume you're using the annotations @ManagedOperation
and @ManagedAttribute
, since those seem to be the most common.
If you have a getter method annotated with @ManagedAttribute
, and this getter throws an exception, then this will not be logged anywhere, it will just be propagated to the client for it to handle. This is sometimes annoying, but there seems to be no way of configuring it to do otherwise.
@ManagedOperation
methods, however, will have their exceptions caught and logged. I don't know why this distinction is made, but that's the way it is.
精彩评论