Implementing logger for java application - java

I am trying to implement logger using apache commonn logging and log4j.xml file as configuration file .
So in the actual java code i am writing log as
I am using appache common logging
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
and i am logging information such as in . I am creating a instance of log for each class
private static Log logger = LogFactory.getLog( MyClass.class );
private static final String name ="SAM";
logger.info("name= "+name);
So now my question is does implementing logger like this create a performanace issue?
Is it necessary to check log like
if ( log.isInfoEnabled( ) )
{
log.info( "Info message" );
}
The confusion is mainly because in Apache common logging they have mentioned to do this and in log4j they have mentioned it is unnecessary.
Each time when we write log in the files?
-Sam

yes and no, logging always reduces your performance, but some functions are more expensive then others, e.g. getting the calling class/method-Name uses reflection and is very slow. But a normal logfuntion is not that expensive if you do not have an expensive statement in the calling logging function (this will be evaluated every time before the log-Level is checked. In this case you can use the .isLevelEnabledcheck to prevent the evaluation). Also logging to the console takes longer for the output than logging to a file. You will find more information about this by googling and in the FAQ/manual of log4j.
You do not have to check the Log-Level before logging. This is done within the log-function itself. Therefore are the different methods for every Level or the Level-Argument in the generic log-Method.

A big potential performance problem with logging is usually if you have something passed into the log method that is very expensive to convert to a string. That's why you have methods like isInfoEnabled(), so that the code can avoid creating the message string from the parameter (otherwise the check within the info() method is too late, the conversion is already done). If your objects passed into the log methods are strings or are not very involved then the is*Enabled() methods won't be that useful.
SLF4J is worth checking out. It doesn't depend on classloader tricks (which is a big part of why commons-logging is reviled), and it has a different way of creating log messages which delays when the message string gets created so that the enabled check can take place within the logging method.

There's a better way to do all of this. You can get really great performance without having to add the clutter of ifDebugEnabled, etc methods. Check out something like Logback (or SLF4J). Here's the great documentation about what kind of an API you want. Note that Log4J and Commons-Logging doesn't have an API like this. Use Parameterized Logging.

Related

Log4j common custom interface

I am using slf4j and log4j2 and i want to create a common interceptor. like below so in future if any log4j uprade came up, i would not have to change every class.
Please review below code and let me know your thoughts regarding performance and memory.
Is there any other better way we can do this?
Class LoggingHelper {
public static void logEvent(Class clazz, String message, Object ...args) {
Logger logger = LoggerFactory.getLogger(clazz);
logger.info(message,args);
}
}
Protecting users against changes in the underlying implementation is exactly what APIs like SLF4J or Log4j2 API (cf. API separation) are for. Although a semantic major version bump in the API can break consumer code, no such change ever occurred: e.g. the recent 2.x version of SLF4J semantically is a minor version bump and only requires updates in the implementations.
Using API wrappers like the one you are proposing is usually a bad idea, because you have to reimplement a lot of details that the API already takes care of. In your example:
instantiating a logger is an expensive operation, that is why loggers are almost always static fields or are instantiated in constructors of services (cf. Static vs non-static loggers),
your wrapper breaks location information: all logs will appear to be generated by LoggingHelper,
your wrapper always creates a temporary varargs array, which must be then collected by the GC. Logging APIs don't create temporary objects for the most common cases: SLF4J supports up to 2 non-varargs parameters, Log4j2 API supports up to 10 non-varargs parameters (cf. garbage-free logging).
Software systems have a tendency to abandon their custom logging APIs: e.g. Jetty dropped its custom logging API in version 10.x.

How to upgrade Priority to log4j-2?

I am trying to upgrade log4j to log4j2. The particular line of code I am trying to upgrade is:
log(targetClass, Priority.DEBUG_INT, message, null);
The static field Priority.DEBUG_INT is no longer available in the new Priority. Instead it looks like the getPriority(Facility facility, org.apache.logging.log4j.Level level) static method is used to access priority int value, to which DEBUG can be specified as the Level.
However, this method also requires a Facility to be specified. How do I know which Facility to specify when calling getPriority?
old Priority: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Priority.html
new Priority: https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/net/Priority.html
new Facility: https://logging.apache.org/log4j/log4j-2.8/log4j-core/apidocs/org/apache/logging/log4j/core/net/Facility.html
Assuming you are talking about Log4j 1's Category.log(String, Priority, Object, Throwable), it appears these Priority classes are pretty (if not completely) unrelated. Log4j 1's Priority is actually the level (indeed it has a subclass Level).
So you would have to look at Log4j 2's Logger class to see if any method with Level parameter matches, but there appears to be no identical alternative (except logMessage maybe, but that appears to be pretty low level).
However, you should check whether that targetClass argument for parameter callerFQCN is actually needed. It looks like it is intended to find the caller of the logger method and might mainly be intended for usage by logging libraries extending Log4j 1. Unless you are indeed upgrading such library, I would assume that the method is misused and a regular Log4j 2 logger.debug(message) would do equally well. Though it would help nonetheless if you could provide more context.

Initialising the logger in each and every class in java of sl4j

'
I am using sl4j for logging in my java classes although I have added the dependency too, my question is that if I have lots of java classes say a count of 50 classes in different packages, then for logging do I need to add the below statement in my every class, rite now suppose below code is for my main class is
final Logger LOG = LoggerFactory.getLogger(Main.class);
Is there any way through which I do not need to initialize the logger of sl4j in each and every class explicitly
It is always recommended to use the following code.
final Logger LOG = LoggerFactory.getLogger(Main.class);
It is required because, all the log statements are specific to specific classes and methods for log analysis. If we create a separate alternative to the above statement, then also we need to define in each class. Think of a situation, we have System.out.println statement which we write everywhere for analysis. Can we think of alternative to the above ? I don't think.
If your project is spring based, you can use AOP to log the messages.

Calling log4j's log methods indirectly (from a helper method)

I'd like to put the logger.debug(...) call into a helper method, and call that helper method from anywhere that needs to write the log. While this mostly works fine, the log entry itself shows the helper method as the source of the call, which is understandable since log4j isn't aware of me using a helper method for logging.
Is there any way to tell it to skip the helper method when figuring out the source of the logger.debug(...) call and instead use its caller?
By source, I mean %F:%L of org.apache.log4j.PatternLayout: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
To illustrate what I mean, here's an example stack trace:
1. logger.debug(msg, throwable)
2. logHelper(logger, msg, throwable) <-- currently shows as the source of the call, since it calls logger.debug directly
3. someFunction <-- where the real logable event occurs, so I'd want this to be logged as the source
The reason I'm doing this is because I'd like an exception logged only by name (e.toString) if the log level is INFO, or with a full stack trace if the level is DEBUG. I'm open to suggestions for alternatives.
Thanks! :)
You can't instruct Log4J to "skip" a level in its source detection.
What you can do, though, is subclass PatternLayout and override the format(LoggingEvent) method to your liking (i.e. only produce the exception's toString() when in INFO mode, etc).
One way to do this is to have the helper class call:
logger.log(LogHelper.class.getName(), Level.DEBUG, message, t);
... instead of:
logger.debug(message, t);
So when log4j tries to determine the source of the event, it will stop when it reaches the parent of LogHelper instead of the parent of Logger.
Verified working as expected.
For Log4j2 the answer is provided completely by the use of logger wrappers as described in the Log4j2 manual under Example Usage of a Generated Logger Wrapper. One can simply generate (using the org.apache.logging.log4j.core.tools.Generate$ExtendedLogger tools illustrated there) a logger wrapper with a single STUB level, and then adapt that to create custom logging methods mimicking the use of the logIfEnabled(FQCN, LEVEL, Marker, message, Throwable) - possibly ignoring the STUB level and using the regular ones - then if desired, deleting or commenting out the STUB level and its methods). For this purpose the FormattedMessage can be helpful.
The method and source line, while expensive, can then be easily shown as part of the full location information by using the %l location conversion pattern element in the PatternLayout given in the configuration, or more specifically using the %L line number and/or the %M method conversion.
Now with complete example at: Java Logging: Log4j Version2.x: show the method of an end-client caller (not an intermediate logging helper method)
For log4j2, you can write a simple wrapper class or generate one as Webel suggests. See my answer for log4j2:
https://stackoverflow.com/a/39045963/116810

Should logger be private static or not

Should logger be declared static or not? Usually I've seen two types of declaration for a logger :
protected Log log = new Log4JLogger(aClass.class);
or
private static Log log = new Log4JLogger(aClass.class);
Which one should be used? what are the pro's and con's of both?
The advantage of the non-static form is that you can declare it in an (abstract) base class like follows without worrying that the right classname will be used:
protected Log log = new Log4JLogger(getClass());
However its disadvantage is obviously that a whole new logger instance will be created for every instance of the class. This may not per se be expensive, but it adds a significant overhead. If you'd like to avoid this, you'd like to use the static form instead. But its disadvantage is in turn that you have to declare it in every individual class and take care in every class that the right classname is been used during logger's construction because getClass() cannot be used in static context. However, in the average IDE you can create an autocomplete template for this. E.g. logger + ctrl+space.
On the other hand, if you obtain the logger by a factory which in turn may cache the already-instantiated loggers, then using the non-static form won't add that much overhead. Log4j for example has a LogManager for this purpose.
protected Log log = LogManager.getLogger(getClass());
I used to think that all loggers should be static; however, this article at wiki.apache.org brings up some important memory concerns, regarding classloader leaks. Declaring a logger as static prevents the declaring class (and associated classloaders) from being garbage collected in J2EE containers that use a shared classloader. This will result in PermGen errors if you redeploy your application enough times.
I don't really see any way to work around this classloader leak issue, other than declaring loggers as non-static.
The most important difference is how it affects your log files: in which category do logs go?
In your first choice, the logs of a subclass end up in the category of the superclass. That seem very counter-intuitive to me.
There is a variant of your first case:
protected Log log = new Log4JLogger(getClass());
In that case, your log category says which object the code that logged was working on.
In your second choice (private static), the log category is the class that contains the logging code. So normally the class that is doing the thing that is being logged.
I would strongly recommend that last option. It has these advantages, compared to the other solutions:
There is a direct relation between the log and the code. It is easy to find back where a log message came from.
If someone has to tune logging levels (which is done per category), it is usually because they are interested (or not) in some particular messages, written by a particular class. If the category is not the class that is writing the messages, it is harder to tune the levels.
You can log in static methods
Loggers only need to be initialized (or looked up) once per class, so at startup, instead of for every instance created.
It also has disadvantages:
It needs to be declared in every class where you log messages (no reuse of superclass loggers).
You need to take care to put the right classname when initializing the logger. (But good IDE's take care of that for you).
Use inversion of control and pass the logger into the constructor. If you create the logger inside the class you are going to have a devil of a time with your unit tests. You are writing unit tests aren't you?

Categories