Does Log4j2 and SLF4J MDC get along? - log4j2

Using Finatra, I'm trying to activate traceID logging, but nothing ends up in Log4J2 output.
Finatra supports SLF4J MDC.
SLF4J MDC is supposed to support Log4J (2?).
Log4J2 is supposed to support MDC and SLF4J.
But in the end, the MDC data is always empty reaching the message construction.
I tested with Logback as the log implementation and I had the MDC logged correctly, and it is actually relying on SLF4J MDC.
I do have to use log4J2 here (cannot be questioned).
Is this just not working because Log4J2 does not work correctly with SLF4J MDC?
To get it to work with Finatra, I just have to remove the LoggingMDCFilter which pretty must only replaces the MDCAdapter with the FinagleMDCAdapter own implementation, backed by Finagle Contexts.

I would add to Piotr's answer.
In accordance with SLF4J's SPI, Log4j 2 provides its own StaticMDCBinder class. This returns Log4j's MDCAdapter that acts as a bridge between the MDC API and Log4j's ThreadContextMap. When Finatra replaces that MDCAdapter the binding is lost so nothing stored in the MDC will make it into the ThreadContextMap. Note that this is necessary because Log4j does not actually use the SLF4J API anywhere except in the adapters.
I believe a better approach than what Piotr suggests would be to modify FinagleMDCInitializer to detect that Log4j-core is present and exit and then have Finatra provide its own ThreadContextMap implementation. In this case only the log4j2.thradContextMap property would need to be provided to reference the custom class and the use of log4j-to-slf4j would not be necessary.
If you do provide a custom ThreadContextMap then the call to MDCInitializer would be unnecessary and you wouldn't really need to make any changes to it as they would only be there to prevent MDCInitializer from breaking the binding with Log4j.

As you noticed in your question FinagleMDCInitializer replaces the MDC used by the logging backend with its own.
Logback uses SLF4J as their internal API (i.e. just Logback) so it will work with any MDCAdapter implementation installed, but all the remaining SLF4J backends won't.
The same hack that permits Logback to work with Finagle can be used in Log4j2 Core. Log4j2 Core is a native implementation of Log4j2 API and it will work with any implementation of ThreadContextMap.
We want to use a ThreadContextMap implementation that delegates all methods to SLF4J's MDC. Fortunately such an implementation is included in the Apache Log4j2 API to SLF4J Adapter (another implementation of the Log4j2 API). So we can use the following trick:
add both log4j-core and log4j-to-slf4j to your application's classpath. Since now there are two implementations of the Log4j2 API available, we need to specify the one we actually want to use. We can do it by adding a file called log4j2.component.properties at the root of your classpath with:
log4j2.loggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory
in the same property file we specify that we want to use the ThreadContextMap implementation included in log4j-to-slf4j:
log4j2.threadContextMap = org.apache.logging.slf4j.MDCContextMap
I assume that you already have log4j-slf4j-impl (Apache SLF4J to Log4j2 API Adapter) on your classpath.
Remark: the proposed solution assumes that FinagleMDCInitializer is called as soon as possible. SLF4J does not have an equivalent of the log4j2.threadContexMap property to force it to use a concrete implementation of MDCAdapter. Until Finagle replaces the implementations, your application will use the MDCAdapter from log4j-slf4j-impl that delegates everything to the ThreadContextMap, that delegates everything to MDCAdapter, ... You'll have a guaranteed StackOverflow.
Edit: If you end up with a StackOverflow, you can:
start with NOOP ThreadContextMap:
log4j2.threadContextMap = org.apache.logging.log4j.spi.NoOpThreadContextMap
replace the MDCAdapter and ThreadContextMap all in one place:
// Replace the `MDCAdapter`
MDCInitializer.init();
try {
// Change ThreadContextMap implementation
System.setProperty("log4j2.threadContextMap", "org.apache.logging.slf4j.MDCContextMap");
// Properties are cached so a reload is needed
PropertiesUtil.getProperties().reload();
// Call ThreadContext.init()
final Method method = ThreadContext.class.getDeclaredMethod("init");
method.setAccessible(true);
method.invoke(null);
} catch (SecurityException | ReflectiveOperationException | IllegalArgumentException e) {
logger.warn("ThreadContext reinitialization failed.", e);
}

Related

How to get and cast JNDI object correctly in Liberty

I have a big problem on getting the correct instance or at least casting the instance I got with JNDI-lookup to correct interface at Web Sphere Liberty (16.0.0.4, running on Java 7, though using Oracle Java 1.8.0_45 in the back, developing on Eclipse Neon.2).
When I start the server and the ear containing the EJB, I get the following notification into the log:
The server is binding the xxx.interfaces.MyLocal interface of the MyEJB enterprise bean in the xxx-ejb.jar module of the xxx-ear application. The binding location is: java:global/xxx/MyEJB!xxx.interfaces.MyLocal
Then I have a web application (ear) which has a service provider (with #Produces) for the previously started ejb-service, which will provide the JNDI resource as injectable (#Inject) for the rest of the application (a bit tricky thing, the main idea is to allow to change the lookup location from configuration file + do some other stuff also). It seems to work correctly for all it is supposed to, but when getting the JNDI-resource, it kind of works but not correctly.
If I put the ejb part as a dependency into my web-module, I can inject it directly (#Inject MyLocal myEjb;).
As the injected resource I get an object with the signature:
EJSMyLocal0SLMyEJB_a4549339#cc5d2cdd
with lookup I get an object with signature (at the same time as the inject):
EJSMyLocal0SLMyEJB_a4549339#cdda36a7
(Not the same instance afaik, but the "type" is correct?)
The injected resource is correctly (automatically of course) cast on 'MyLocal' interface and is ok.
When I try to check the resource got with JNDI, it does not qualify as an instance of 'MyLocal' nor as 'MyRemote'? Also the actual cast fails of course with ClassCastException. (MyRemote is basically the same as the MyLocal interface ... MyLocal extends MyRemote, both interfaces are accordingly annotated with #Local and #Remote)
The EJB looks like this at the time of testing...
#Stateless
#Named
#Default
#Local(MyLocal.class)
#Remote(MyRemote.class)
public class MyEJB implements MyLocal, MyRemote { ... }
I also tried to cast the JNDI resource like this.
InitialContext ic = new InitialContext();
Object lookedUpEjb = ic.lookup(lookup); // the 'java:global...' from log
MyRemote jndiEjb = (MyRemote) PortableRemoteObject.narrow(lookedUpEjb, MyRemote.class)
// Tried also casting/checking 'instanceof' to MyLocal...
No difference with that, the same ClassCastException occurs?!
I have the following features in server.xml
<featureManager>
<feature>javaee-7.0</feature>
<feature>ldapRegistry-3.0</feature>
<feature>localConnector-1.0</feature>
<feature>adminCenter-1.0</feature>
<feature>wsSecurity-1.1</feature>
<feature>ejbLite-3.2</feature>
<feature>ejbRemote-3.2</feature>
<feature>cdi-1.2</feature>
<feature>jpa-2.1</feature>
<feature>jsf-2.2</feature>
<feature>jaxrs-2.0</feature>
<feature>jaxws-2.2</feature>
</featureManager>
I found this documentation on the Liberty JNDI functionality:
https://www.ibm.com/support/knowledgecenter/SSAW57_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_ejb_remote.html
I can't see where I go wrong. How do I cast that object from JNDI lookup to MyLocal or MyRemote interfaces?
---- Note ----
Using the #EJB annotation is not an option (it works though), since it will be hard coded reference to the resource. I want it to be optional though, thus JNDI lookup. #EJB will cause the app to crash when the resource is not available.
The problem is that each application has a different ClassLoader and the object that has been bound into JNDI was loaded with the ClassLoader of the application that defined the EJB.
This should not be an issue for Remote EJB interfaces as the ORB should have taken care of this for you. On a remote call that returns such an object, the ORB will serialize the object (from the target ClassLoader) and then deserialize using the client ClassLoader. For a lookup like this, the PortableRemoteObject.narrow should also take care of this. The failure here appears to just be a bug in the ORB.
In order to support cross application access to Local EJB interfaces, either the Local EJB interface needs to be moved to a shared library, that is used by both applications, or both applications configured to use a single global ClassLoader. See this link for more information about using Local EJB interfaces across applications: Correct way to lookup local EJB in websphere - Getting ClassCastException (Note: this link is discussing traditional WebSphere, but the issue is the same with Liberty, as is the resolution to use a shared library for the interface).

log is not accessible in normal groovy file of grails3

Migrated grails2 to grails3.
In grails2 i used lots of
log.info,log.debug
statements in side src/main/groovy files.
but in grails-3 by default log is not injected.
it's giving error like No such property: log for class
This is a planned change. You can use #groovy.util.logging.Commons annotations on your non-grails classes to have log available. Also other like #Log4j, #Slf4j are available, depending on your logging library.
There is one more difference which is important - those annotations will add log as private property and classes which will inherit from them, will also need to be annotated to use logging. Alternative is to manually define protected logger on your class.

Custom Log Level in Grails

I want to be informed when uncaught exceptions occur in my Grails 2.2.4 application. Log4j has an SMTPAppender doing something similar, but only based on a specific log level. In my application there are already a lot of log entries in all available log levels, so sending email on ERROR or FATAL is not really an option because it would also contain non-exception entries.
Filtering uncaught exceptions in Grails is quite easy, I just redirect them to a specific controller and handle it there:
static mappings = {
[...]
"500"(controller: "errors", action: "serverError")
}
My plan was to introduce my own log level and use it only for uncaught exceptions. Documentation suggests this:
final Level EXCEPTION = Level.forName("EXCEPTION", 50);
logger.log(EXCEPTION, "uncaught exception", e);
But I don't know how to use this in Grails with the injected log object. It only supports the base options like log.error('foo',e). Grails documentation says how to add custom appenders, but nothing about custom levels (or did I miss it?!)
Any suggestions?
Grails uses Slf4j and Commons Logging to abstract the logger implementation and allow changing from Log4j to another framework without having to edit every file with a logger. Instead, the wrapper library gets the correct implementation instance based on the requested logger name and what's available from the native API. If you change implementations, the wrapper loggers work the same way as far as your app code is concerned, but they call different implementation loggers to do the actual logging.
But there's no standard between implementations for configuration, so internal Grails startup code works directly with the API to configure loggers, appenders, levels, etc. You can do the same - use the traditional Log4j logger access code to get an instance by logger name, using the same one as the preconfigured logger Grails wired up. I can never remember the naming convention for loggers in artifacts, so I cheat and add a line of code
println log.name
in a method that I know runs, and call that method indirectly via whatever controller action can get there. So for example, if I want to know the logger of FractalService, put that code in its graphJuliaSet method and call the controller action that graphs Julia Sets using this service.
Log4j loggers are singletons, if you access the logger and change it, that will affect all future calls.
So that logger is available via something like:
String name = ... // the name from the println above
Logger logger = Logger.getLogger(name)

How can you log from a Neo4j Server Plugin?

I'm trying to debug a problem in the Neo4J Server plugin I'm writing. Is there a log I can output to? It's not obvious where or how to do this.
Good question. I think you could use Java Logging? That should be routed into the normal logging system.
Just inject org.neo4j.logging.Log in your class containing implementation of your Neo4j stored procedure.
public class YourProcedures {
#Context
public Transaction tx;
#Context
public Log log;
#Procedure(value = "yourProcedure", mode = Mode.READ)
public Stream<YourResult> yourProcedure(#Name("input") String input) {
log.debug("something");
}
}
Logs are then dumped into standard Neo4j log file.
The level is controlled by GraphDatabaseSettings.store_internal_log_level configuration.
The level can be also changed in runtime. Just inject DependencyResolver bean and define this admin procedure. (The framework has listener hooked to config change which reconfigures the internal logging framework. This is the simplest solution I could find.)
#Context
public DependencyResolver dependencyResolver;
#Procedure(value = "setLogLevel", mode = Mode.DBMS)
#Description("Runtime change of logging level")
public void setLogLevel(#Name("level") String level) {
Config config = dependencyResolver.resolveDependency(Config.class);
config.set(GraphDatabaseSettings.store_internal_log_level, Level.valueOf(level));
}
UPDATE:
This ^ solution works, however it is insufficient when one wants to use logging the way usual in Log4j - different loggers organized in hierarchy, each logger at its own level. The org.neo4j.logging.Log component is just a wrapper of Log4j logger for the GlobalProcedures class. This logger is only one of many loggers in hierarchy. In fact, the wrapper blocks access to richer features of underlying framework. (Unfortunately, to define multiple #Context Log fields in YourProcedures class distinguished by some annotation qualifying logger is also impossible because field injection is driven by Map<Class,instance> so there is only one possible instance to inject for any #Context-annotated field according to field type.)
Solution 1:
Use JUL as in accepted answer. The disadvantage is, JUL redirects log event to underlying Log4j anyway so if logger hierarchy is defined in JUL, Log4j must be set to lowest possible level in order to make JUL levels sensitive.
Solution 2:
Use Log4j directly (i.e. public static final Logger logger = LogManager.getLogger("some.identifier.in.hierarchy") in YourProcedures). There are some issues with redefining configuration programmatically though it is possible, I dropped this solution only because I had some trouble deploying this solution in non-docker environment.
Solution 3: (finally chosen)
I defined custom component LogWithHierarchy (it can be built from own ExtensionFactory loaded using ServiceLoaders - I was inspired in APOC config implementation). This component provides API of the form debug(loggerName, message), info(loggerName, message) etc. The component knows original Log, drills down into its log4j LoggerContext and redirects all logging requests to particular logger in this LoggerContext. Log messages finally end in debug.log. With this solution the original log4j logger hierarchy is fully utilized, levels can be changed dynamically in runtime (setLogLevel must be changed to operate on aforementioned LoggerContext) and still everything is implemented using standard Neo4j plugin support.

Using resources.groovy to define services

I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)

Resources