0

I'm writing a command line application in Java. That app will scan a list of remote resources, do several attempts to access those resources, report failed attempts, and if succesfully accesed, perform some maintenance or diagnosis action and report the outcomes of that action.

As you can imagine, there's a lot of error handling and error reporting. But reporting the errors is a feature. Let me explain: a report with the errors encountered when attempting to access to the remote resource is something the user expects from the app, since those failures are useful for the diagnosis. Such access failures are expected in many cases and the causes should be reported.

As you can see, there's a blurry line between what's an error and what's the expected output of the app, which as every app will have its own errors also.

I'm using the Java Logging API and I'm designing my classes in a way as to be able to add different loggers and swap loggers and/or handlers (to screen, to file, to database, etc), as well as different list of resources to scan (and different types of those resources).

The problem is that I'm tempted to call logger.log() everywhere I was previosly using System.put.println();

Right now I'm now in a position where there's a blury line between what should be printed with System.out.println() and what should be send to the Logger instance.

I believe I'm having a conceptual confusion.

So the questions are, given the fact that errors reporting is a part of the core functionality of the app and that, as any app, it has to handle and log its own errors:

  • What things should be printed with System.out.println()
  • What things should be forwarded to a Logger
  • What things should be both printed with System.out.println() and forwarded to a Logger
  • Should normal output be considered as being log messages of a low severity level or not at all?

EDIT:

Just to clarify, the app could attempt to download a file, but it's not the file what the final user wants, but to see whether or not it was accessible and if not, why. The resource could be a server, a database, a service or a file. The user doesn't want the app to get what the resource offers but to check availability and report the cause. That somehow makes failed attempts code errors the output users want to get from this app. Hence the thin line between logging or printing.

2

The fact that you are writing a console application doesn't change good UI practices.

  • Your business logic should be distinct from your UI. The business logic performs the operations and indicates what might have gone wrong. The UI decided how that should be displayed.

  • If there is information that is useful for tracking the execution of the application after something has happened, it should be written to a log file. This will primarily happen in your business logic classes. The fact that something is written to a log file does not inherently mean that the UI does not need to display it. Things that are important enough to display to the user is likely important enough to log, but it does not need to be in the same form.

    What goes in the log should be more detailed: What exactly went wrong? What were the inputs when that happened? You can also give more fine grained details about what is currently executing. To the user, it might be a single task, but to the code it could be a four step process. The nice thing about logging is the different levels let you have very detailed log messages in your code, but allowing some of them to be omitted from the log file.

  • Don't write code that is statically configured to only work one way. A command line application will obviously be dealing with standard out a lot. However, that doesn't mean your classes must have System.out.println() everywhere. You classes could write to an OutputStream. By initializing your UI classes with the OutputStreams/InputStreams that they should work with, it will make it much easier to test the code. Being able to use a ByteArrayOutputStream in an automated test is a great way to check if content is being output correctly.

    An example of what I am suggesting:

    public class A {
      private final OutputStream _out;
    
      public A(OutputStream out) {
        _out = out;
      }
    
      public void Run() {
        _out.println("Write to UI here");
      }
    }
    

    It is true that System.out is an OutputStream, but there are many classes that implement that interface. If you hard code your classes to use System.out, that is the only way the code can be used. If you pass in the output stream to write to, now you have the option to write to files, network sockets, and other things.

  • Isn't System.out an OutputStream? – Tulains Córdova Jan 16 '15 at 22:22
  • 1
    @user61852 I expanded on the last point to demonstrate what I mean. Doing it this way provides your code with more flexibility. – unholysampler Jan 16 '15 at 22:36
2

Anything that is worth printing at all is worth printing to the logs, since the whole point of logs is to record as much detail as possible about what happened during execution.

As with any other program, by default the user should see only a small subset of the output that's likely to be useful and relevant to him. Due to the nature of your program, you may have lots of options to increase verbosity or change how certain errors are handled, but that principle still applies.

For instance, if the app accepted a command to download some file from some server, I might print out on the console "connecting to website.com", "beginning download", "installing", and not much more, but the logs will contain several additional details like redirects or authorization protocol steps that might be useful in debugging complicated problems someday.

When an error is encountered, typically you'd print a concise summary of the error on the console ("lost connection with server") and tell the user what log file they can look at if they want to see more details.

Should normal output be considered as being log messages of a low severity level or not at all?

Output that the user actually sees should be considered more important, because you're going out of the way to show it to them instead of simply logging it, so it'd better be useful.

A "low severity" error might simply be something your program can workaround ("connection lost, retrying...connection reestablished") or it might be something that implies a possible user error you'd want to warn them about ("http specified, this connection will not be secure"). By itself "severity" isn't a useful indication of whether you should print something to the console or not.

  • Just to clarify, the app could attempt to download a file, but it's not the file what the final user wants, but to see whether or not it was accessible and if not, why. The resource could be a server, a database, a service or a file. The user doesn't want the app to get what the resource offers but to check availability and report the cause. That somehow makes failed attempts code errors the output users want to get from this app. Hence the thin line between logging or printing. – Tulains Córdova Jan 16 '15 at 22:44
  • I usually add an extra ConsoleAppender to the logger, which prints out INFO, WARN and ERROR log messages to stdout. – dotbugfix Jul 29 '15 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.