[java] Log4j: How to configure simplest possible file logging?

My story:

I want to make a thing which is as simple as a simplest possible log4j logger that logs rows to a file. I have found several examples with some functionality, but not a basic, general one that really works, and not one with an explanation how the each row work.

Question:

Could anybody provide one?

Prerequisites:

  • I already know where to put the file and I have the log4j configured and working for console logging.
  • Now I want to log to a file and also find the file from file system once the program has run.
  • Rows needed to be added to the existing log4j.properties file are the desired output.

This question is related to java logging log4j

The answer is


Here's a simple one that I often use:

# Set up logging to include a file record of the output
# Note: the file is always created, even if there is 
# no actual output.
log4j.rootLogger=error, stdout, R

# Log format to standard out
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=   %5p\t[%d] [%t] (%F:%L)\n     \t%m%n\n

# File based log output
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=owls_conditions.log
log4j.appender.R.MaxFileSize=10000KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=   %5p\t[%d] [%t] (%F:%L)\n     \t%m%n\n

The format of the log is as follows:

ERROR   [2009-09-13 09:56:01,760] [main] (RDFDefaultErrorHandler.java:44)
        http://www.xfront.com/owl/ontologies/camera/#(line 1 column 1): Content is not allowed in prolog.

Such a format is defined by the string %5p\t[%d] [%t] (%F:%L)\n \t%m%n\n. You can read the meaning of conversion characters in log4j javadoc for PatternLayout.

Included comments should help in understanding what it does. Further notes:

  • it logs both to console and to file; in this case the file is named owls_conditions.log: change it according to your needs;
  • files are rotated when they reach 10000KB, and one back-up file is kept

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

   <appender name="fileAppender" class="org.apache.log4j.RollingFileAppender">
      <param name="Threshold" value="INFO" />
      <param name="File" value="sample.log"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d %-5p  [%c{1}] %m %n" />
      </layout>
   </appender>

  <root> 
    <priority value ="debug" /> 
    <appender-ref ref="fileAppender" /> 
  </root> 

</log4j:configuration>

Log4j can be a bit confusing. So lets try to understand what is going on in this file: In log4j you have two basic constructs appenders and loggers.

Appenders define how and where things are appended. Will it be logged to a file, to the console, to a database, etc.? In this case you are specifying that log statements directed to fileAppender will be put in the file sample.log using the pattern specified in the layout tags. You could just as easily create a appender for the console or the database. Where the console appender would specify things like the layout on the screen and the database appender would have connection details and table names.

Loggers respond to logging events as they bubble up. If an event catches the interest of a specific logger it will invoke its attached appenders. In the example below you have only one logger the root logger - which responds to all logging events by default. In addition to the root logger you can specify more specific loggers that respond to events from specific packages. These loggers can have their own appenders specified using the appender-ref tags or will otherwise inherit the appenders from the root logger. Using more specific loggers allows you to fine tune the logging level on specific packages or to direct certain packages to other appenders.

So what this file is saying is:

  1. Create a fileAppender that logs to file sample.log
  2. Attach that appender to the root logger.
  3. The root logger will respond to any events at least as detailed as 'debug' level
  4. The appender is configured to only log events that are at least as detailed as 'info'

The net out is that if you have a logger.debug("blah blah") in your code it will get ignored. A logger.info("Blah blah"); will output to sample.log.

The snippet below could be added to the file above with the log4j tags. This logger would inherit the appenders from <root> but would limit the all logging events from the package org.springframework to those logged at level info or above.

  <!-- Example Package level Logger -->
    <logger name="org.springframework">
        <level value="info"/>
    </logger>   

Here is a log4j.properties file that I've used with great success.

logDir=/var/log/myapp

log4j.rootLogger=INFO, stdout
#log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{MM/dd/yyyy hh:mm:ss a}|%-5p|%-30c{1}| %m%n
log4j.appender.stdout.DatePattern='.'yyyy-MM-dd
log4j.appender.stdout.File=${logDir}/myapp.log
log4j.appender.stdout.append=true

The DailyRollingFileAppender will create new files each day with file names that look like this:

myapp.log.2017-01-27
myapp.log.2017-01-28
myapp.log.2017-01-29
myapp.log  <-- today's log

Each entry in the log file will will have this format:

01/30/2017 12:59:47 AM|INFO |Component1   | calling foobar(): userId=123, returning totalSent=1
01/30/2017 12:59:47 AM|INFO |Component2   | count=1 > 0, calling fooBar()

Set the location of the above file by using -Dlog4j.configuration, as mentioned in this posting:

java -Dlog4j.configuration=file:/home/myapp/config/log4j.properties com.foobar.myapp

In your Java code, be sure to set the name of each software component when you instantiate your logger object. I also like to log to both the log file and standard output, so I wrote this small function.

private static final Logger LOGGER = Logger.getLogger("Component1");

public static void log(org.apache.log4j.Logger logger, String message) {

    logger.info(message);
    System.out.printf("%s\n", message);
}

public static String stackTraceToString(Exception ex) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    ex.printStackTrace(pw);
    return sw.toString();
}

And then call it like so:

LOGGER.info(String.format("Exception occurred: %s", stackTraceToString(ex)));

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to logging

How to redirect docker container logs to a single file? Console logging for react? Hide strange unwanted Xcode logs Where are logs located? Retrieve last 100 lines logs Spring Boot - How to log all requests and responses with exceptions in single place? How do I get logs from all pods of a Kubernetes replication controller? Where is the Docker daemon log? How to log SQL statements in Spring Boot? How to do logging in React Native?

Examples related to log4j

No log4j2 configuration file found. Using default configuration: logging only errors to the console How to stop INFO messages displaying on spark console? What is log4j's default log file dumping path How to give environmental variable path for file appender in configuration file in log4j No appenders could be found for logger(log4j)? SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". in a Maven Project log4j:WARN No appenders could be found for logger (running jar file, not web app) Error: "setFile(null,false) call failed" when using log4j java.lang.ClassNotFoundException: org.apache.log4j.Level How can I create 2 separate log files with one log4j config file?