Cleaner debug level logging in Java? - java

Is there a cleaner way for me to write debug level log statements? In some ways one could say that the string literals are basically commenting the code and providing logging in one line and that it is already very clean. But after I add debug level log statements, I find the code much less easier to read up and down. Take this example (I may update to a real example if I get back to my home PC):
int i = 0;
logger.debug("Setting i to 0,"); //Just an example, would show something more complex
i++;
InputStream is = socket.getInputStream();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
IOUtils.write(request, dos);
logger.debug("request written to output");
while (!is.read(buffer))
logger.debug("Reading into buffer");
logger.debug("Data read completely from socket");
CustomObject.doStuff(buffer);
logger.debug("Stuff has been done to buffer");

You could try using aspects, although these have the limitation that you can only put log statements "around" method calls, i.e. before entering and/or after leaving a specific method.
For more detailed logging, I am afraid there is no other way than hand-coded log messages.
I typically strive to remove the not-so-much-needed debug log statements from the code once I made sure that it works the way it should (for which unit tests are a must).

Ask yourself if I run this in a different machine/country/planet, and things go wrong and all I have is only a log file what information do I need to know what has gone wrong ?
Use debug logs in a for loop, or a while loop sparingly. For example, if you are reading 1000 records from a file, performing an op for each record. You could record before the for loop that "file exists and is readable and is going to read 1000 records" and print status after the process is done. If it is say 1000000 records then you could print something every say 100 or 1000 iterations
In your code except for the logger for setting i to 0 everything else sorta makes sense to me. Also care to use log.isDebugEnabled() if your string in the logger statmeent is hard to compute..
ex:
if(log.isDebugEnabled) {
logger.debug("Here " + obj.aMethodCallThatTakes5MinsToEvaluateToString());
}
UPDATE 1: SLF4J solves only half the problem.
if(slfLog.isDebugEnabled) {
slfLog.debug(obj.getObjectThatTakes5Mins());
}
Yes the toString is prevented but if you are logging an actual object which is result of some computation you are not prevented.

If you want very fine grained debug instructions I am not sure you can separate the actual code from the debug code.
If you want it at a higher level, maybe adding your logging using AOP could help make things easier to read, maybe use a proxy object?
But if you have debug instructions as fine grained as in the example you provided, IMHO you could gain more by replacing the loggers with unit tests. Don't write in a log that something happened, test that it did.

You will not be able to do much if you dislike the log statements. The information needs to be there somehow.
What you CAN do, is strongly considering what NEEDS to be there. You are basically writing for the log file reader who per definition does not know about how your program works, so the information needs to be concise and correct. Personally I very frequently add the method name to the log statement.
Also note that slf4j allows you to use the {}-syntax which helps somewhat
log.debug("main() date={}, args={}", new java.util.Date(), args);
Also note that having unit tests, allow you to move much stuff to there simply because you know that THAT works.

Related

Save content of code bein executed by test into File

I want to write a program that counts the lines of code being executed when
a test, lets say TestA(), runs. More importantly, I need to store the
lines of code being executed
by TestA(), into a codeLines: String.
I find this concept really bizarre and so far, I did not have any luck with
online resources. Do you know of any way that such functionality could be achieved?
From what I understand of the question, it seems like the closest functionality that you can easily attain is by using a debugger, which lets you step through lines, step into lines, and see what line is doing what in the code.

Implementing variable based logging?

I have made a nice UI with three different logs (a general log and two class specific ones).
Every log can print different lines with different colors.
I was thinking of doing this so I can show info/errors/warnings.
Now, the thing is, that I'd like to have detailed debug only when I set a variable (something like detailedDebug = true).
I'd like something like this:
Simple | Detailed
Error thrown in ... | Error thrown.. + dump of all variables related to the error
Now, with if statements I can achieve that easily, but, that seems overly complicated (complicating the code for debugging reasons too).
How could I implement this (while making it easy to use and most importantly clean)?
Should I make a method in every class that uses the logging features that automatically checks for a variable then does what asked?
You should use the the log level as the variable to control the detail. When you want more detail, turn the level down to FINEST.
Hoewever, some operations that you wish to log might require considerable resources to calculate the detail (example, you may retrieve info from the DB, etc). In this case you should use if statements because the resources will be consumed even if the log level is at ERROR level.
Example :
The following code will always execute :
logger.log(Level.FINEST, "Some detailed log info which sows the results from DB {0}",
new Object[]{ getResults() });
If you only want to execute this code when you are showing FINEST, you need to wrap the statement in an if statement :
if (logger.isLoggable(Level.FINEST)) {
// Some intensive logging
}

How do I log from a mapper? (hadoop with commoncrawl)

I'm using the commoncrawl example code from their "Mapreduce for the Masses" tutorial. I'm trying to make modifications to the mapper and I'd like to be able to log strings to some output. I'm considering setting up some noSQL db and just pushing my output to it, but it doesn't feel like a good solution. What's the standard way to do this kind of logging from java?
While there is no special solution for the logs aside of usual logger (at least one I am aware about) I can see about some solutions.
a) if logs are of debug purpose - indeed write usual debug logs. In case of the failed tasks you can find them via UI and analyze.
b) if this logs are some kind of output you want to get alongside some other output from you job - assign them some specail key and write to the context. Then in the reducer you will need some special logic to put them to the output.
c) You can create directory on HDFS and make mapper to write to there. It is not classic way for MR because it is side effect - in some cases it can be fine. Especially taking to account that after each mapper will create its own file - you can use command hadoop fs -getmerge ... to get all logs as one file.
c) If you want to be able to monitor the progress of your job, number of error etc - you can use counters.

slf4j How to specify max logged number for a line

I've got a huge number of log messages in project's log. I want to reduce that number by logging only first N of them for every line of code where log is used.
Are there any existent solutions for my task?
Thanks in advance.
This is not something i have tried myself, but if you use logback as the underlying logging mechanism of slf4j, I imagine you could write a custom filter that takes care of filtering the log output as you specify it.
http://logback.qos.ch/manual/filters.html
I decided to implement a LoggerWrapper by myself.
We can obtain the current line of a caller, count its occurrence and decide whether print a message or not. I think it's quite simple but a kind of routine.

How to make System.err write in one block

I'd like to solve following issue: imagine that you are doing lots of outputs in System.out, and from time to time there is an Exception thrown. When you look into the console, you can see that the exception's trace text is mixed up with normal output done by System.out. I understand that these two are different streams (System.out and System.err) and I guess that the output of the exception is done internally by some other thread, that is why it is mixed up.
However, is it somehow possible for the code to stop until output for the exception is done? The only solution I can think of is to put Thread.sleep, but maybe there might be some option I am not aware of.
Just curious really :) It'd be nice for debugging (that's the reason I ask, because reading the output and exceptions mixed up in between is terrible)
If you have multiple threads and their output is getting interleaved, you should think about using a logging facility rather than trying to share the stderr and stdout-
http://download.oracle.com/javase/6/docs/api/java/util/logging/package-summary.html
Or apache's log4j:
http://logging.apache.org/log4j/1.2/
How about redirecting System.err to a file?
System.setErr( ... );
The problem needs to be solved elsewhere, in the process which merges two file streams into the output you see - by only printing out a line when it is done. Since that is most likely not an option to you if you are talking about the "java.exe" output, you need to investigate elsewhere.
I have not tested, but I would start with having a look at invoking flush() on System.out before you send output to System.err.
When java implicitly imports the lang (java.lang.*) package, the System class has 2 standard output streams.
System.err
System.out
And because these both output to the same standard output, you have to choose one and change it from standard output to file output. My recommendation would be to change the System.err output like so:
import java.io.* ......
System.setErr (new PrintWriter (new FileWriter ("Errors.txt")));
Hope this helps!
EDIT
Sorry, can't leave comments yet, but the logging idea above is very good. Depending on what you are doing, logging will be an optimal solution. But I try to avoid logging because it tends to become very memory extensive if it is used too much.
Write to a separate stream in memory to format your output, then write the single string at once. You may still end up with your single string in the middle of an exception's text, though. Fundamentally what you are doing requires synchronization, or a separate stream (think one output file per thread).
I don't see how Thread.sleep will do anything other than complicate the issue.
Create a new PrintStream to file descriptor 2 with autoflush set to false.
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.err, false, "UTF-8")));
Just make sure to call System.err.flush after important error messages.
If you want to merge stderr into stdout, you can do the above but with FileDescriptor.out.

Categories

Resources