Aug 22

Log4J2 Setup

I feel that a decent guide on how exactly Log4J2 is setup is in order, because there isn’t a real clear explanation on Apache’s site. Now Apache, I know you guys make a lot of stuff, but seriously a lot of this stuff is just over-engineered.

Alright, on to the configuration stuff!

Here’s an example config file, with an explanation as to what is going on here(at least as far as I can understand it)

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
  <appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>
  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File"/>
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>
</configuration>

Okay, let’s start at the very top with the configuration tag:

<configuration status="OFF">

If you change the ‘status’ part of this to a level such as “ALL”, you’ll notice that Log4J2 sends out A LOT of information. As far as I can tell, this is just logging information that is part of Log4J2.

Alright, let’s go on to the appenders. When you create a logger, there are several appenders that you can use to send information to various places. The two appenders that we have here are for the console(i.e. System.out) and a file.

<appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>

The PatternLayout that they have determines how the information will be printed out. For the File appender, there is a fileName property with sys:logFilename. This means that the logger will look for the system property of logFilename. This can be set by either:

  1. passing -DlogFilename=XXX to the program
  2. System.setProperty( “logFilename”, XXX )

If you use option #2, you must also reconfigure the logger as shown in this StackOverflow post.  Fortunately, the patters are in fact well documented.  There are a lot of other appenders out there to append to different things, but we’re not worried about that at the moment.

Okay, now on to the final section: the loggers themselves.

  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File"/>
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>

As you can see here, we have a root logger and a specific logger.  The root logger has a level of ERROR, which means that everything descending from the root logger will print out all ERROR messages.  The root logger will also go two places: the Console logger and the File logger.

The second logger besides the root logger is logging just one specific file.  The log level for that file is ALL, which overrides the ERROR log level of the root logger.  Thus, all log messages from that file will be logged.  These messages will also be sent to both the CONSOLE log and FILE log, as those settings are inherited from the root logger.  Let’s say that we want to send those log messages to the FILE, but everything will also go to the CONSOLE. We would do something like this:

    <root level="ERROR">
      <appender-ref ref="Console" />
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" >
       <appender-ref ref="File" />
    </logger>

Since the more specific logger inherits from the root logger, all log messages from com.rm5248.Logtest2 go to the FILE and the CONSOLE.  There’s more stuff that you can do here with that, but I haven’t really delved into it too deeply.

Anyway, here’s the code that I was using when I was playing around with this.  Hopefully this will help you to get started.

XML Config File:

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
  <appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>
  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File" />
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>
</configuration>

LogTest.java:

package com.rm5248;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.XMLConfigurationFactory;


public class LogTest {

	private static Logger logger = LogManager.getLogger( LogTest.class );

	public static void main( String[] args ){
		File logConfigFile = new File( XML_CONFIG_FILE_GOES_HERE );
		System.setProperty( "logFilename", "filename.log" );		

		try {
			FileInputStream fis = new FileInputStream( logConfigFile );

			XMLConfigurationFactory fc = new XMLConfigurationFactory( );
			fc.getConfiguration(  new ConfigurationFactory.ConfigurationSource( fis ) );

			URI configuration = logConfigFile.toURI();
			Configurator.initialize("config", null, configuration);

			org.apache.logging.log4j.core.LoggerContext ctx =
					(org.apache.logging.log4j.core.LoggerContext) LogManager.getContext( true );
			ctx.reconfigure();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		logger.debug( "hi debug" );
		logger.info( "hi info" );
		logger.error( "hi error" );

		Logtest2.doSomething();
	}

}

Logtest2.java:

package com.rm5248;

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

public class Logtest2 {
	private static Logger logger = LogManager.getLogger( Logtest2.class );
	
	public static void doSomething(){
		logger.debug( "hello" );
		logger.error( "error?!" );
		logger.warn( "warning" );
		logger.info( "la la la" );
	}
}
Aug 04

What the heck, Discovery?

You guys used to be so good. You had a bunch of interesting shows that really let me learn a lot about the world. And now you do crap like mermaids, and now megalodon shark attacks on boats in South Africa.  WHAT THE FUCK?!  Look, I’m all for being entertained, but when I’m watching Discovery, Animal Planet, heck any channel that is owned by Discovery, I’m not looking for entertainment.  I’m looking to learn.

I think that these shows do have a place in the world.  But when you make shows like these, don’t film them as pseudo-documentaries, or “mockumentaries” as people call them.  They should be about possible things that happen.  You guys should be there to help promote thinking about what is there, and what used to be there.  None of this fake crap that you’re putting out there now – it’s frankly insulting.

I know that you guys make enough money as it is.  This is just retarded that you’re doing something like this.  If you want to do something about megalodon, that’s fine.  Let’s do it in a way that lets people learn about megalodon, like what it could have been like.  Also, I don’t want actors playing biologists or anything, get real biologists out there to tell us this stuff.  You do a great disservice to all of us when there are people pretending to be biologists when they really aren’t.

Also, History Channel, I’m looking at you too.  I don’t really have anything against Pawn Stars or American Pickers, because they can be good shows about showing off items from history.  But when I hear crap like Pawn Stars having an item on the show that is in a museum currently, well, that’s just stupid as well.  Again, not that there’s anything wrong with the show itself per se, but when it’s blatantly obvious that they’re not actually buying or selling anything then we have a bit of an issue here.

TruTV, you’re not so good yourself.  I don’t really watch you anymore.  Except for maybe World’s Dumbest.  That’s actually amusing since it’s not really staged, it’s just people making sarcastic comments and mocking dumb people.

Aug 03

A Great Movie Idea

So here’s an idea for a movie that I just thought up: a comedy movie along the lines of Home Alone, but instead of breaking into somebodies house, they try to break into the Wonka factory to steal the secret recipe for chocolate or something like that.  Then they get into all sorts of wacky hijinks because it’s, you know, the Wonka factory.  You’ve got seltzer that lifts you up to the ceiling, gum that makes you fat, people getting stuck in tubes, the list goes on and on!