Differentiate logging informations of multiple instances of the same class - java

I'm trying to log the methods call chain of some classes instances of a Java program using Log4j2. Each instance will behave differently based on the inputs they will recive (obviously).
The problem I'm facing is differentiating the logging messages of each instances for easly reconstructing the methods call chains I was talking about.
In addition to logging the entering and the leaving of each method, which is the default logging schema I'm using, I've tried to:
add method call parameters to the log: too few informations and not very readable;
add more informations about the method behaviour: too verbose and not very readable;
adding instance hash code to all the logging messages, which will become something like LOG.trace("{} - Leaving constructor(index:{})", System.identityHashCode(this), index);: good solution, but I've to add some boilerplate code to all the logging methods, which makes the code a little less readable;
using per-instance loggers (so not the per-class/static one) and adding the instance hash code in the logger name (so the logger name will be Classname#hashcode): seems the best solution in clean code terms, but I didn't found any way for declaring logger settings (like logging threshold) for multiple loggere, i.e. for all the loggers which name starts with Classname.
Which one do you think will be the best solution, or do you have any other way to suggest?

For this requirement, you can easily use an nested thread context: Look at "Fish Tagging" in https://logging.apache.org/log4j/2.x/manual/thread-context.html .
Excerpt:
ThreadContext.push(UUID.randomUUID().toString()); // Add the fishtag;
logger.debug("Message 1");
.
.
.
logger.debug("Message 2");
.
.
ThreadContext.pop();

Related

A table that contains View objects tags

First of all I must say I'm new to both Android dev and Java.
I'm trying to find a list of the tags that are used for logging in Android studio.
The examples I've been researching include using:
Log.i(tag:"Info","message");
Log.i(tag:"Values","another message");
Log.i(tag:"Seekbar changed", "and another message");
I tried for the past couple of hours to find a document online, that has a table to describe the reserved tags for View objects, any help will be appreciated.
There is no fixed list of "reserved tags" one can use for logging in Android. You decide for yourself which tags you want to use and what additional information about the state of your objects or primitive types you want to display.
The Log class has six different log levels (debug, error, info, verbose, warn and wtf [What a Terrible Failure]) and corresponding (static) methods (Log.d, Log.e, Log.i, Log.v, Log.w and Log.wtf) each of which you call with two string parameters, one string parameter and one Throwable or two string parameters and one Throwable.
The most commonly used is probably the variant with two string parameters, one parameter for a tag (chosen by you) and one parameter for a message (also chosen by you). See this post for information about which level to choose.
During debugging I often use commands like this one:
Log.e(String.valueOf(myIntVariable), String.valueOf(myOtherVariable));
Let me explain the reason for using the Log class like this. I use the error level because it will give you red entries in the LogCat output (inside an IDE, e.g. Android Studio), and the same IDE will also let you filter out all logs below the error level. However, this is for debugging only; make sure to get rid of those log commands before your app enters production.
Instead of using logs in the way I do, you can also use breakpoints in the debug mode. I guess it is mainly a question of taste if you prefer one or the other. Toasts would be third option (with more boilerplate though).
If you use logs a lot in your code, it makes sense to use real tags. Either you define a string called TAG (or something else) in your class, or you put the name of the containing method as the first parameter. This will give you a sense of the order by which your methods are being called. You can also use other tags as well, and it doesn't have to follow a specific convention either (though you should have a system for it to make sense of it).

What is the best way to do logging for REST method call?

What is the best way to do logging for REST method call?
I tryed two ways to log the information of methods like input passed to the method, output of that method, if exception thrown - what exception, which class and method and exception line are logged.
Method1 : Using finally method
Method2 : Using Spring AOP
Which is the best way to do? Is there any other way we can do logging.
finally is for exceptions. AOP looks good if you have many methods. Otherwise just add the LOG statements (in case you're using a logger framework like log4j) where you think you need them. AOP has a slight performance impact.
I am here adding a point over ACV's suggestion since what ever he has suggested are correct ,
1. AOP will be loose couple that give you more flexibility in terms of optional deployment ,
2.Your actual business logic and method will be remain neat & clean . no extra line would be appear there.
3.Could use your code for entire application even in other application too.

log4j/logback pass logger level as a parameter

I want to do something which seems really straightforward: just pass a lot of logging commands (maybe all, but particularly WARN and ERROR levels) through a method in a simple utility class. I want to do this in particular so that during testing I can suppress the actual output to logging by mocking the method which does this call.
But I can't find out how, with ch.qos.logback.classic.Logger, to call a single method with the Level as a parameter ... obviously I could use a switch command based on this value, but in some logging frameworks there's a method or two which lets you pass the logging Level as a parameter. Seems a bit "primitive" not to provide this.
The method might look a bit like this:
Logger.log( Level level, String msg )
Later
Having now looked up the "XY problem" I understand the scepticism about this question. Dynamic logging is considered bad, at least in Java (possibly less so in Python)... now I know and understand that the preferred route is to configure the logging configuration appropriately for testing.
One minor point, though, if I may: although I haven't implemented this yet with this particular project, I generally find "just" tracing the stacktrace back to the beginning of the particular Thread insufficient, and this is what logback does (with Exceptions passed at WARN or ERROR levels). I plan to implement a system for recording "snapshots" of Threads when they run new Threads... which can then be listed (right back to the start of the app's first Thread) if an error occurs. This is, if you like, another justification for using something to "handle" outgoing log calls. I suppose that if I want to implement something like this I will instead have to try to extend some elements of logback in some way.

Filtering a subclass in log4j

I have a message driven system with, say, com.example.BaseMessagingAgent class, which is a basic class for many message agents. This base class logs message events. There are many subclasses of this base class, implementing different specific agents of system. Let us com.example.MyAgent which extends com.example.BaseMessagingAgent is one of them.
I want to log messages only related to class MyAgent. But I cannot define logging as:
log4j.logger.com.example.MyAgent=DEBUG, APPENDER
because logging occurs in parent class com.example.BasicMessagingAgent - I will record nothing.
And I also do not want to set logging in base class:
log4j.logger.com.example.BaseMessagingAgent=DEBUG, APPENDER
because it will log events for all agents, and I will have a lot of unnecessary logging.
Does enyone know how to limit logging to only one subclass?
You should write a filter for Log4j since AFAIK there is no way to put such information on log4j.properties file. More details at http://books.google.it/books?id=vHvY008Zq-YC&lpg=PA95&ots=yi335bZU7z&dq=&pg=PA95#v=onepage&q&f=false
It's pretty simple, actually.
First, add the appender to the root logger. Really. It will make your life much more simple.
Now configure the whole thing:
log4j.rootLogger=DEBUG, APPENDER
log4j.logger.com=ERROR
log4j.logger.com.example.MyAgent=DEBUG
The default for all classes below "com.*" will be to log only errors. The sole exception is com.example.MyAgent which will log at debug level.
You need to set the root logger to DEBUG as well or it will throw away all the DEBUG log messages.
The next step is to use one logger per instance. To get that, simply remove the static in the line which you create your logger and replace BaseMessagingAgent with getClass()
I know, it looks like overkill but that's how log4j works. Also creating a logger per instance isn't very expensive (unless you create millions of MyAgent per second).
If you really want to add an appender to a single class, then don't forget to turn off additivity (...Class.additivity=false) or you will get all log messages twice.

can we do some change to the object being returned at runtime

is there a possibility to do some changes in object at runtime.
my problem is i have one class which returns me the instance of logger. and that class contains only one public method which returns the logger. below is the class..
public class LoggerManager {
public Logger getLogger(String FQCN) {
Logger logger = Logger.getLogger(FQCN);
logger.setLevel(Level.INFO);
return logger;
}
}
now if i want to change the returning object at runtime,
which means that the logger object which is set to level INFO, i want to change that one to DEBUG.. during program execution only when this code is called at a particular time... without changing the code anywhere.. some thing like that...
logger.setLevel(Level.DEBUG);
can i achieve this, by any means??
as this class is used everywhere within my code.. about a 1000 places, without changing the code by....some means can i achieve this...
I think that you are asking if you can change the behavior of the getLogger(String) method without changing the class. The simple answer is "no you cannot".
There are a couple of tricks you could try:
Putting a different version of the class ahead of the current one in the application's classpath ahead of the current version.
Using BCEL or something to modify the class bytecodes prior to loading.
However, both of these amount to changing the class.
I think your simplest approach is to modify the LogManager class so that you can generate loggers with different levels. With a little thought you should be able to come up with a solution that doesn't impact the rest of your codebase significantly.
However, it is also worth nothing that the normal way to set logging levels is to use a configuration file, rather than explicit calls to setLevel in the application.
is there a possibility to do some changes in object at runtime
Yes, you can make changes on Objects that are returned from method calls.
It is difficult to understand what you want to do. If you set the debug level on the returned logger, it should be set for all places in your running vm that request a Logger with the same FQCN argument.
You could set the desired value before your call, and back to normal afterwards.
Somme logging classes allow this.
I can't be specific here because your didn't say exactly what your Logger class is (Log4j ?).
This logger class seems to be called as a static method.
Therefore, if you have any threads in your system (if using Tomcat for example, or using a background thread), modifying the level is unsafe (it will modify for you but also for all threads).
However, the usual option to your problem is not to change the level.
When you want a log to appear, either :
Log at a level that appears
Choose a different logger (each one can be configured to a specific level).
It is possible to do it with AOP but it is rather compilcated. AOP allows you to handle both pre and post method invocation.
I am not sure why you have to getLogger more than 1000 places in your single project. Do you have more than 1000 classes? Normally, you only need to call it once per class. I would also change the code and redesign overcalling to this method.

Categories