I am trying to migrate some code from log4j 1.x to 2.x. Some things are easy to replace, but I cannot find the way to replace this:
Object obj = event.getMDC("xxx"); //event is org.apache.log4j.spi.LoggingEvent type from log4j 1.x.
I know about the method with the bridge but for now I want to skip it and try to do it like this.
MDC can be replace with ThreadContext and I see some people using org.apache.logging.log4j.core.LogEvent but it doesn't contain the same methods as LoggingEvent (examples):
.getRenderMessage()
.getTrowableInformation()
.getMDC();
Related
I am trying to migrate from Log4j 1.7 to Log4j2.4
In 1.7, I as creating AppLogger class by extending org.apache.log4j.Logger and using extending debug/error/fatal Methods
e.g.,
public void error(Object message) {
Object error = message;
if (message instanceof Exception) {
Exception e = (Exception) message;
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
error = sw.toString();
}
super.error(error);
}
But in Log4j 2.x, I am not able to extend the class org.apache.logging.log4j.Logger;
What is the Best way to achieve this?
I can understand why you might have wanted to do this with Log4j 1.x, but I cannot figure out why you would want to do this with log4j 2. The best place to do this is in a Layout, but most already do this.
As Ralph pointed out, Log4j2 has a very rich set of functionality, and if you go over the documentation, you often find that you can achieve your goals using the built-in layouts, lookups, filters and other features.
Writing a custom lookup only takes a few lines of code and gives you a powerful hook into the logging subsystem which you can use for many purposes.
If you really want to extend Logger for whatever reason, be aware that some layouts require Log4j to walk the stacktrace to report which class and line in your code from the logger was called from. This mechanism is a bit complex and in general I would recommend you create a Logger wrapper instead of extending it. (Prefer delegation to subclassing.)
Log4j has a tool to make this easy for you: the Custom Logger Generator tool documented in the Custom Log Levels page. Try this and see if it gives you what you need.
I am confused about the difference between log4j2-slf4j binding and log4j2-slf4j adapter.
Can someone explain in plain English what the differences are? The links I put up say the adapter "routes" to SLF4J and the binding "allows SLF4J to use Log4j", but I don't really understand what this means. Also, do I need both, or just one of them?
You must use only one. If you put both, you will cause an endless cycle. The following may give you an idea:
Log4j 2 SLF4J Binding
If you have code in your application like this:
// Instance of SLF4J
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(MyClass.class);
And you want to use Log4J 2 (log4j2.xml), then you might need:
Log4j 2 to SLF4J Adapter
If you have code in your application like this:
// Instance of Log4J 2
private static final org.apache.logging.log4j.Logger LOG =
org.apache.logging.log4j.LogManager.getLogger(MyClass.class);
And you want to use SLF4J (e.g. logback.xml), then you might need:
I have code fetched from jar that uses java.util.logging.Logger.
Jar contains about 1000 logger usages and each class start from:
private static final Logger LOG = Logger.getLogger(SomeClass.class.getName());
I want to handle all logs there, means, to point them to my Logger usage and not to java.util.logging.Logger.
Therefore I wrote my own logger.
So instead:
LOG.log(Level.SEVERE, "Error sleeping", e);
I can write:
MyLogger.toLog(TLogLevel.WFS_ERROR, "Monkey", "Error sleeping", e );
The problem is I need run over all java files and replace with mine.
Messy way, hmm
Does anyone know how can by easy way to convert java.util.logging.Logger to com.boo.MyLogger?
Thanks,
The SLF4J project has a jul-to-slf4j bridge that can be used to redirect java.util.logging.Logger calls to SLF4J. You could use that (by making your MyLogger implement the interface defined by SLF4J).
Note that, however, unlike all other logging libraries, j.u.l. is hard-wired into the Java class libraries and cannot be bridged without a performance penalty.
Also, I don't know what you are doing with MyLogger, but usually there is no need to write your own. There are plenty of logging implementations to choose from, and they can be configured in many different ways. And even if you do have to write your own Logger implementation, you should use an existing interface (such as SLF4J which seems to most popular these days).
Take a look at SLF4J:
The Simple Logging Facade for Java or (SLF4J) serves as a simple
facade or abstraction for various logging frameworks, e.g.
java.util.logging, log4j and logback, allowing the end user to plug in
the desired logging framework at deployment time.
Using that you could then also use logback (same author) to log to a common logging framework using the various bridges already available. Or, write your own, but either way you would not have to worry about replacing all that code...
Oracle's Java 7 Logger is configurable, its implementation is simply:
public static Logger getLogger(String name) {
// This method is intentionally not a wrapper around a call
// to getLogger(name, resourceBundleName). If it were then
// this sequence:
//
// getLogger("Foo", "resourceBundleForFoo");
// getLogger("Foo");
//
// would throw an IllegalArgumentException in the second call
// because the wrapper would result in an attempt to replace
// the existing "resourceBundleForFoo" with null.
LogManager manager = LogManager.getLogManager();
return manager.demandLogger(name);
}
So you can also via code set a logging level; besides declarative.
LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME).setLevel(Level.INFO);
Lars Vogel has a nice page, also with its own Logger class.
All put together is quite workable, but maybe sometimes somewhat hard to understand.
I use slf4j for logging in my project. And i want to use MDC for logging user ID parameters. So i check tutorials and doc, and make code like:
MDC.put("key", userId)
userId actually is a string.
And i use my usual log4j xml with properties like appenders etc. Add there %X{key} but nothing happen. I simply don't see anything in place of %X{key} but other parameters like %-5p or %c works well.
So i used debug to watch what happen in MDC.put() method, and find out that in initialization of MDC used:
MDCAdapter mdcAdapter;
mdcAdapter = StaticMDCBinder.SINGLETON.getMDCA();
Debug in IDEA shows that it have "Log4jMDCAdapter" like one of implementation for MDCAdapter.
But then i look at StaticMDCBinder, and there are code like:
public MDCAdapter getMDCA() {
return new NOPMDCAdapter();
}
So how it possible that slf4j can initialize MDC with proper adapter for example log4j ??? I didnt get it. Because it always use NOPMDCAdapter it cant store anything in MDC, and cant show it in logging. How i can fix it??
In classpath i have:
log4j-1.2.16.jar
slf4j-api-1.6.1.jar
slf4j-api-1.6.2.jar
slf4j-jcl-1.6.2.jar
slf4j-log4j12-1.6.2.jar
SLF4J's MDC is just a facade to switch over the applicable implementation of MDC based on the underlying logger. If it doesn't find any appropriate MDCAdapter from the logger it fallsback to NO-OP adapter.
For this it tries to find class named StaticMDCBinder
https://github.com/qos-ch/slf4j/blob/v_1.7.25/slf4j-api/src/main/java/org/slf4j/MDC.java#L99
So in this case as mentioned in #Wizzard's answer if there are two StaticMDCBinder classes in your class path tomcat will pick one of it.
slf4j-simple does have a StaticMDCBinder which defaults to NO-OP adapter so removing
slf4j-simple jar should solve the issue here.
Problem solved.
It was transcendent dependency from other libraries which used in project. Namely slf4j-jcl, i add part into maven pom, and now it works fine.
I am using slf4j for logging in my application.
I get the purpose of slf4j. I would like to know how to find out which logging-library slf4j is currently binding to. I have log4j in my referenced libraries. I am assuming that slf4j has bound itself to log4j.
What I would like to know is, is there any way to explicitly confirm this binding?
Just do what SLF4J does to discover the binding:
final StaticLoggerBinder binder = StaticLoggerBinder.getSingleton();
Now you can try to find out what is the actual implementation logback in my case:
System.out.println(binder.getLoggerFactory());
System.out.println(binder.getLoggerFactoryClassStr());
This prints:
ch.qos.logback.classic.LoggerContext[default]
ch.qos.logback.classic.selector.DefaultContextSelector
The StaticLoggerBinder's getLoggerFactoryClassStr() method is probably what you're looking for.
Easy. Put a breakpoint on .. say.. LOG.info(...). Once debugger stops there, step into.. and viola.. you will find yourself in the code of the actual logger... say log4j or logback.. whatever.
It's possible to do this using the main slf4j public API (i.e. without the internal StaticLoggerBinder), e.g. to detect if slf4j has bpound to log4j2:
if ("org.apache.logging.slf4j.Log4jLoggerFactory".equals(
org.slf4j.LoggerFactory.getILoggerFactory().getClass().getName()
)
{ ... }
Or, avoiding the need to have StaticLoggerBinder (which is not part of slf4j-api):
log.info(log.getClass().getName());
In my case this prints
ch.qos.logback.classic.Logger