I just ask about the logger name...
It it possible to give a custom name for a logger, or to use class name.
But what to use in which case?
-> Using a custom name for each application module: some classes are used by 2 modules -> to which logger name should it belong to?
-> Using classname: it seems to require a good package organisation -> best practices for logging known about that?
I prefer using class names for the purpose of debugging. You can read the log trace (and the class name will be displayed) from the log file and view line code, etc. It's useful in that sense. If someone else maintains your code, they don't have to do hectic searches on finding where the "custom name" is populated (in which class).
I still prefer classnames. It does not require a good package organisation but reflects your (good - hey what else?) package orgnization. And it's a common pattern to use the class names.
You can read the logging class file from the logs and set log levels on packages.
And following the common pattern prevents me from spending too much time on thinking about good (perfect) custom logger names ;-)
I've never heard of anyone use anything other than class name. I think anything else would be a mistake, leading to potential loss of logging detail down the line.
Don't overthink this one, just run with class name.
I donno about anything else than class name because in any case it's very easy to read through class for locating the issue or anything else..! And it is also better to log the code using all kinda log levels e.g. trace for all possible details, fatal for exception and similarly the debud,error,info etc.
Related
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();
A colleague and I were discussing best practices for managing a Configuration file, and we wanted to get some further feedback from others.
Our goal is for the configuration-file to specify what action should be taken, when certain events occur.
The 2 options that we are debating:
In the config-file, specify the class-path of the class, which implements the action to be taken (eg: "ActionToTake" : "com.company.publish.SendEveryoneAnEmailClass").
Inside the code, when this event is encountered, we can then do Class.forName(config.ActionToTake).newInstance().run() in order to invoke the specified action.
In the config-file, specify in a human-readable-phrase, the action that should be taken (eg: "ActionToTake" : "SendEveryoneAnEmail"). Inside the code, when this event is encountered, we can then parse config.ActionToTake, and perform a mapping that translates this to action implementation (eg: new SendEveryoneAnEmailClass().run())
We are currently a very small team, and the only people reading/using this config file currently, is our team of software devs. But it's unclear if this will continue to be true in future.
Reasoning behind option 1: Anyone reading the config file will explicitly and immediately know what class will get invoked, and where it's implemented. This also allows for the action-class to be implemented/imported from a completely separate JAR file, without recompiling/changing our code.
Reasoning behind option 2: The config file should be a high level description of user-intent, and should not contain implementation details such as specific class names & package paths. Refactoring of class/package names can also be done without having to make config file changes.
Thoughts on which of these 2 design philosophies is preferred for configuration files?
1st option's advantage is, as jas noticed, the ability to 'link' code in the future. It's a real advantage only if you sell/distribute your software as a closed sourced package or if you plan to hot-swap behavior on production. You've already pointed out the cons - refactoring
2nd option:
It won't help you with refactoring. If you change your action from SendEmail to BringBeer but you leave the string send email then you failed.
Readability. send-everyone-an-email is as good as SendEveryoneAnEmail. Every developer will know what will happen. It can't be confused with LaunchRockets. Your code can find class based on some text, not necessarily the full qualified name. Your code can assume that Actions are in some specific package unless explicitly provided. And that is a way to combine both options.
Consider also another possibility: do the configuration in code. If you don't want to recompile the package, you can use scripting language (groovy). It lets you create very readable dsl, and you will have refactoring.
I need to create a map of our domain classes simple names to their fully canonical names. I want to do this only for classes that are under our package structure, and that implement Serializable.
In serialization we use the canonical names of classes alot --it's a good default behaviour as its a very conservative approach, but our model objects are going to move around between packages, and I don't want that to represent a breaking change requiring migration scripts, so I'd like this map. I've already tooled our serializer to use this map, now I just need a good strategy for populating it. Its been frustrating.
First alternative: have each class announce itself statically
the most obvious and most annoying: edit each class in question to include the code
static{
Bootstrapper.classAliases.put(
ThisClass.class.getSimpleName(),
ThisClass.class.getCanonicalName()
);
}
I knew I could do this from the get-go, I started on it, and I really hate it. There's no way this is going to be maintained properly, new classes will be introduced, somebody will forget to add this line, and I'll get myself in trouble.
Second alternative: read through the jar
traverse the jar our application is in, load each class, and see if it should be added to this map. This solution smelled pretty bad -- I'm disturbing the normal loading order and I'm coupled tightly to a particular deployment scheme. Gave up on this fairly quickly.
Third alternative: use java.lang.Instrumentation
requires me to run java with a java agent. More specifics about deployment.
Fourth alternative: hijack class loaders
My first idea was to see if I could add a listener to the class loaders, and then listen for my desired classes being loaded, adding them to this map as they're loaded into the JVM. strictly speaking this isn't doing this statically, but its close enough.
After discovering the tree-like nature of class loaders, and the various different schemes used by the different threads and different libraries, I thought that implementing this solution would be both too complicated and lead to bugs.
Fifth alternative: leverage the build system & a properties file
This one seems like one of the better solutions but I don't have the ant skill to do it. My plan would be to search each file for the pattern
//using human readable regex
[whitespace]* package [whitespace]* com.mycompany [char]*;
[char not 'class']*
class [whitespace]+ (<capture:"className">[nameCharacter]+) [char not '{']* implements [char not '{'] Serializable [char not '{'] '{'
//using notepad++'s regex
\s*package\s+([A-Za-z\._]*);.*class\s+(\w+)\s+implements\s+[\w,_<>\s]*Serializable
and then write out each matching entry in the form [pathFound][className]=[className] to a properties file.
Then I add some fairly simple code to load this properties file into a map at runtime.
am I missing something obvious? Why is this so difficult to do? I know that the lazy nature of java classes means that the language is antithetical to code asking the question "what classes are there", and I guess my problem is a derivative of this question, but still, I'm surprised at how much I'm having to scratch my brain to do this.
So I suppose my question is 2 fold:
how would you go about making this map?
If it would be with your build system, what is the ant code needed to do it? Is this worth converting to gradle for?
Thanks for any help
I would start with your fifth alternative. So, there is a byte code manipulation project called - javassist which lets you load .class files and deal with them using java objects. For example, you can load a "Foo.class" and start asking it things like give me your package, public methods etc.
Checkout the ClassPool & CtClass objects.
List<CtClass> classes = new ArrayList<>();
// Using apache commons I/O you can use a glob pattern to populate ALL_CLASS_FILES_IN_PROJECT
for (File file : ALL_CLASS_FILES_IN_PROJECT) {
ClassPool default = ClassPool.getDefault();
classes.add(default.makeClass(new FileInputStream(file.getPath())));
}
The classes list will have all the classes ready for you to now deal with. You can add this to a static block in some entry point class that always gets loaded.
If this doesn't work for you, the next bet is to use the javaagent to do this. Its not that hard to do it, but it will have some implication on your deployment (the agent lib jar should be made available & the -javaagent added to the startup args).
I have tried to understand dependency injection and not quite gotten it, except I have managed to pick up the understanding that it makes it hard to understand somebody else's code. :'(
Anyway, I'm not sure how to briefly describe my problem but I will try. I am currently the sole coder working on a Java project that's been worked on by dozens of loners over about six years. It makes heavy use of Google's Guice library. I'm supposed to take some existing code and implement it differently; specifically, use the existing methods for password authentication and, instead of applying it to each JMenuItem in a JMenu, apply it to the whole JMenu, so that if the wrong password or no password is entered, all JMenuItems are disabled. This doesn't happen if the password is wrong, leading me to believe the problem is in the if statement, which is a long string of dependencies in itself:
if (!ViewScanApp.getApplication().getHistoryManager().isAuthenticated())
I trace my way back through this, to find that the HistoryManager class is an interface, and there my path seems to die; there's no code there, and it doesn't make a reference to any other class. I have found the end of the path through random exploration of the 100-odd classes in the project, but I can't quite seem to connect them. I cannot find where the first class I can find on the other end of this stack, AccessManagerImpl, gets called.
I could use an explanation of dependency injection that might be applicable to this situation. Thank you so much!
Assuming there's no #ImplementedBy annotation on the HistoryManager interface, you'll need to examine the Guice Module that is responsible for binding this type.
In Eclipse, there is a command to look for occurrences of a class. I'll bet that Netbeans has something similar. Use it to look for occurrences of HistoryManager. At least one of these should occur in a class that implements com.google.inject.Module (or extends AbstractModule). You'll likely see something like
protected void configure() {
…
bind(HistoryManager.class).to(HistoryManagerImpl.class);
…
}
Or, if you like quick-and-dirty empiricism, you can throw in a println():
HistoryManager mgr = ViewScanApp.getApplication().getHistoryManager();
System.out.println("HistoryManager implementation: " + mgr.getClass());
if (!mgr.isAuthenticated())
…
However you locate it, HistoryManagerImpl class is where you'll want to pick up the trail.
I haven't used it, but the Guice graphing tool might be helpful too.
Fire up a debugger. It will walk you through the exact class that is implementing that interface (assuming you have the source code to it)
Whenever you have an interface definition in Eclipse which is injected with Guice, instead of using F3 to go to the defintion which you would do if it was a class, then use Ctrl-T to choose among the implementations of that interface.
If you have more than one to choose from, then you need the module bindings printed out so you know which one to pick. Unfortunately Eclipse doesn't understand injection yet.
Someone might yell at me to read the faqqing faq, but I'm in a hurry ...
Does anyone have a way to make javax or log4j logger refactor-sensitive?
Say, that currently utils.Something has the logger handle:
final static private Logger logger = Logger.getLogger(Something.class.getName());
And logging.properties has
.level = warning
utils.Something.level=info
Then using Eclipse to refactor Something to
nutilla.Somewhere
resulting in my logger handle and logger property becoming out of sync.
Perhaps, set logging levels programmatically?
Has anyone bothered to do it and was it worth the trouble?
Clarification:
After refactoring utils.Something to nutilla.Somewhere, the logger handle now would only log warning and not info, because of the entry in logging.properties file. So the question is, is there a way to replace the function of logging.properties file with programmatic means and if so, is it worth the trouble?
Reason and Motivation for question
I'm obstinate at not listening when advising me to avoid refactoring because ...
Refactoring is a constant habit of mine. I create classes by the hour, merge them, delete them, extract methods, etc ... I'm a restless class creator who finds no time wondering where to initially place a class. I dislike sitting down wasting time wondering where to place them initially - so I just place them in the most convenient package namespace.
After building a good amount of class/interface structure, it becomes apparent to me where certain classes, interfaces or methods shd have been then all the refactoring activities take place and ... tada ... that's when my logging.properties file is ruined a hundred lines.
If you configure logging using class (as opposed to package) names, checking "Update fully qualified class names in non-Java text files" in eclipse's rename refactoring dialog should do the trick.
I do not think there is a way out of the box that updated the package names and class names in your properties file as a result of refactoring actions.
You can:
update the properties file by hand when refactoring is done (refactoring should be an action that is not undertaken eveery week :=)
use fixed strings to create loggers (make logging more functional instead of physical)
load the properties file and adjust the property names on the basis of constants you declare in your class before initialising log4j with that properties collection
I would go for the first option myself, too much automagic behaviour can get you in a very non-transparent situation quickly.
I wouldn't use it (I think it makes more sense to be careful when refactoring) but here it goes:
private static Logger logger = Logger.getLogger(new Exception().getStackTrace()[0].getClassName());