Search code examples
javalogginglogfile

How to write all the System output to a file in JAVA?


I have created a JAVA application. Sometimes, users do invalid operations on it or there are some exceptions that the application encounters when it outputs the errors. However, these outputs are not visible unless I run the application from command line using java -jar myapp.jar

I wish to record all of these to a file in the form of a log but I am unable to find a function or object which is responsible for outputting these errors etc.

To simplify my explanation, assume that my application outputs number from 1 to 10 using a for loop and a Sytem.out command. How can I record everything that is output to the System?

Thanks


Solution

  • Agreed with above, you should use a logging framework. I prefer to use abstractions such as SLF4J.

    In this example you can use log4j underneath. Here is an example log4j.properties file you can put in the classpath of your java application.

    #Rootlogger logs to console and logfile
    log4j.rootLogger=INFO,stdout,logfile
    
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
    
    log4j.appender.logfile=org.apache.log4j.RollingFileAppender
    log4j.appender.logfile.File=/tmp/apname.log
    log4j.appender.logfile.MaxFileSize=1024KB
    # Keep three backup files.
    log4j.appender.logfile.MaxBackupIndex=3
    # Pattern to output: date [thread] priority [category] - message
    log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
    log4j.appender.logfile.layout.ConversionPattern=%d [%t] %p [%c] - %m%n
    
    #=============== CREATE A SEPARATE HANDLER FOR LOGGING SPECIFIC PACKAGES
    log4j.appender.MYPACKAGEHANDLER=org.apache.log4j.RollingFileAppender
    log4j.appender.MYPACKAGEHANDLER.File=/tmp/mypackage.log
    # 1/2 GB
    log4j.appender.MYPACKAGEHANDLER.MaxFileSize=512MB
    # Keep three backup files.
    log4j.appender.MYPACKAGEHANDLER.MaxBackupIndex=3
    # Pattern to output: message only
    log4j.appender.MYPACKAGEHANDLER.layout=org.apache.log4j.PatternLayout
    log4j.appender.MYPACKAGEHANDLER.layout.ConversionPattern=%m%n
    
    log4j.additivity.com.techtrip.mypackage=false
    log4j.logger.com.techtrip.mypackage=DEBUG, MYPACKAGEHANDLER
    

    Using this config will create two log files with a rolling appender, printing all debug log output of any class that logs in the com.techtrip.mypackage to /tmp/mypackage.log.

    Suppose a simple example class with a Logger and a Formatter:

    package com.techtrip.mypackage;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Foo {
    
        private Logger logger = LoggerFactory.getLogger(Foo.class);
    
        private String someString;
    
        private Foo() {
            super();
        }
        public void setSomeString(String someString) {
            if (logger.isDebugEnabled()){
                logger.debug(String.format("Setting someString %s", someString));
            }
    
            this.someString = someString;
        }
    }
    

    This will log the setter output to the log file. Turn it off by simply changing the property file. Very simple.