Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make the Apache Log4J logging in this application useful?

I have an application which is a simple networked knock-knock joke app. I incorporated some Log4J (version 2) logging into it. Here is the server class:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;

import java.net.*;
import java.io.*;

public class MessageResponseServer extends Thread /* added in the T just now*/{   /* REPLACED */

   private static final Logger logger = LogManager.getLogger("MessageResponseServer");
        logger.info("MessageResponseServer.java :  INFO message");
    public static void main(String[] args) throws IOException {

        logger.debug("MessageResponseServer.java : DEBUG  message");

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            logger.fatal("MessageResponseServer.java :  FATAL  message - Could not listen on port: 4444.");

            System.exit(1);
        }

        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
                    logger.debug("MessageResponseServer.java :   , debug message");
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }

        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                clientSocket.getInputStream()));
        String inputLine, outputLine;
        MessageResponseProtocol mrp = new MessageResponseProtocol();  /* REPLACED */

        outputLine = mrp.processInput(null);
        out.println(outputLine);

        while ((inputLine = in.readLine()) != null) {
             outputLine = mrp.processInput(inputLine);
             out.println(outputLine);
             if (outputLine.equals("Bye."))
             logger.debug("MessageResponseServer.java : , Exiting. DEBUG Message"); 
                break;
        }
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    }
}

And the following is XML file:

<?xml version="1.0" encoding="UTF-8"?>


<Configuration status="WARN">
  <Appenders>

    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="MyFile" fileName="OutputLogFile.log" immediateFlush="false" append="true">
            <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </File>

  </Appenders>

  <Loggers>
    <Root level="ALL">
      <Appender-Ref ref="Console"/>
      <Appender-Ref ref="MyFile"/>  

    </Root>


  </Loggers>
</Configuration>

What I'd like to do is to figure out how to make the logging a bit more useful. Do you add in special if statements to decide whether to log something(i.e if user enters "quit" I can make a specific log on that ).

Is there perhaps a way to include performance metrics into logging? This would be really useful for me. My goal is for the code to demonstrate something that may aid in making it exhibit fail-safe features later on(i.e , perhaps we might utilize the logs to restart the Client side if it was aborted ).

thanks

like image 535
Caffeinated Avatar asked Apr 21 '15 18:04

Caffeinated


People also ask

What is a purpose of using a logging library such as log4j in an application?

Log4j is used by developers to keep track of what happens in their software applications or online services. It's basically a huge journal of the activity of a system or application. This activity is called 'logging' and it's used by developers to keep an eye out for problems for users.

How does log4j logging work?

Log4j allows logged messages to contain format strings that reference external information through the Java Naming and Directory Interface (JNDI). This allows information to be remotely retrieved across a variety of protocols, including the Lightweight Directory Access Protocol (LDAP).


3 Answers

Firstly, your code does not compile. The first logger.info() call needs to be inside a static{} block, or moved into main(); And your while() loop is going to exit first time through - you need {} brackets around the debug and break statements.

But I need to state my prejudices :)

  1. Personally, I find little use for logger.debug() calls. Modern IDEs (I use Eclipse) provide excellent debugging support without cluttering your code with logger.debug() statements. @rmalchow has already pointed out the disadvantages of unneeded debug statements - I have seen a case where performance increased over 100% once a few if statements were put around logger.debug() calls.
  2. So in my world, logging is for production systems that I cannot debug with the IDE. This brings a number of responsibilities.
  3. Calls to System.err() should be replaced by logger.error() calls. By default these will go to System.err, but you can redirect if required.
  4. If you can't add value, just let exceptions percolate up. I tend to turn them into RuntimeExceptions, but some purists hate this.
  5. When you can add value, don't swallow the stack trace. For instance, your logger.fatal should be logger.fatal("..msg...", exception). This will save many happy hours of grepping code.

As to metrics, you can always roll your own - e.g. time how long a back-end call takes to complete and log at info level. I don't have specific suggestions for a helpful framework, but others may.

like image 55
kiwiron Avatar answered Oct 05 '22 11:10

kiwiron


one idea central to many of the logging frameworks is that you do NOT decide what to do in the application, but in the configuration. so, basically, your application logs everything, and your config "filters" and sends the output to the right place (i.e. different files, the syslog, or even ignoring it completely)

in general, in a development environment, you want to log more, so you might set everything to "DEBUG", while on production, you set it to "INFO".

sometimes, it might be beneficial to do a pattern such as this:

 if(log.isDebug()) {
       log.debug("some formatting");
 }

to avoid executing the formatting (in this case) and throwing it away immediately afterwards.

your pattern layout is also a bit problematic - for example, retrieving the line number is unreliable (it basically depends on the code being compiled with debug=true) and very expensive (it has to retrieve the stacktrace and extract the line information from it).

for actual execution time metrics, you may want to look elsewhere - an excellent library that provides counters and time measurements including max, min, average etc is metrics-core:

https://dropwizard.github.io/metrics/3.1.0/manual/core/

and if you're using spring, you may want to look at my aspect based on this library:

https://github.com/rmalchow/metrics

like image 21
rmalchow Avatar answered Oct 05 '22 12:10

rmalchow


For your application, I think what you have done is enough. you don't need more.

Debug for debugging / Error for exception and Errors. May be add an info for the start and stop server.

Now, if you have had a larger application you should do this :

  1. Change Log4J for Logback see logback vs log4j
  2. Debug parameters passed and return values of every method using AOP.It will save a lot of time during development. I personally, use Jcabi loggable.
like image 34
Master Mind Avatar answered Oct 05 '22 11:10

Master Mind