/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.core.util.logging;
import jlibs.core.io.FileUtil;
import jlibs.core.lang.Ansi;
import jlibs.core.lang.ImpossibleException;
import jlibs.core.util.CollectionUtil;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
/**
* This is an implementation of {@link java.util.logging.Formatter}, to use ansi colors in logging.
* <p>
* Example Usage:
* <pre class="prettyprint">
* Logger logger = LogManager.getLogManager().getLogger("");
* logger.setLevel(Level.FINEST);
*
* Handler handler = logger.getHandlers()[0];
* handler.setLevel(Level.FINEST);
* handler.setFormatter(new {@link AnsiFormatter}());
*
* for(Level level: map.keySet())
* logger.log(level, "this is "+level+" message"); * </pre>
* </pre>
*
* This class has public final constants to access Ansi instance used for each level.<br>
* These constants are made public, so that you can use them any where. for example you can do:
* <pre class="prettyprint">
* import static jlibs.core.util.logging.AnsiFormatter.*;
*
* {@link #SEVERE}.out("User authentication failed");
* </pre>
*
* The colors used by AnsiFormatter for any level can be changed to match you taste. To do this you need to create a properties file.<br>
* for example:
* <pre class="prettyprint">
* # myansi.properties
* SEVERE=DIM;RED;GREEN
* WARNING=BRIGHT;RED;YELLOW
* </pre>
* Now use following system property:
* <pre class="prettyprint">
* -Dansiformatter.default=/path/to/myansi.properties
* </pre>
* Each entry in this property file is to be given as below:
* <pre class="prettyprint">
* LEVEL=Attribute[;Foreground[;Background]]
* </pre>
* key is the level name;<br>
* value is semicolon(;) separated values, where where tokens are attribute, foreground and background respectively.<br>
* if any non-trailing token in value is null, you still need to specify empty value. for example:
* <pre class="prettyprint">
* SEVERE=DIM;;GREEN # foreground is not specified
* </pre>
* In your properties file, you don't need to specify entries for each level. you can specify entries only for those levels that you want to change.
*
* @see jlibs.core.lang.Ansi
*
* @author Santhosh Kumar T
*/
public class AnsiFormatter extends Formatter{
private static final Map<Level, Ansi> map = new LinkedHashMap<Level, Ansi>();
static{
try{
load(AnsiFormatter.class.getResource("ansiformatter.properties"));
}catch(IOException ex){
throw new ImpossibleException(ex);
}
String file = System.getProperty("ansiformatter.default");
try{
if(file!=null && new File(file).exists())
load(FileUtil.toURL(new File(file)));
}catch(IOException ex){
ex.printStackTrace();
}
}
public static final Ansi SEVERE = map.get(Level.SEVERE);
public static final Ansi WARNING = map.get(Level.WARNING);
public static final Ansi INFO = map.get(Level.INFO);
public static final Ansi CONFIG = map.get(Level.CONFIG);
public static final Ansi FINE = map.get(Level.FINE);
public static final Ansi FINER = map.get(Level.FINER);
public static final Ansi FINEST = map.get(Level.FINEST);
private static void load(URL url) throws IOException{
Properties props = CollectionUtil.readProperties(url.openStream(), null);
for(String name: props.stringPropertyNames())
map.put(Level.parse(name), new Ansi(props.getProperty(name)));
}
private Formatter delegate;
public AnsiFormatter(Formatter delegate){
this.delegate = delegate;
}
public AnsiFormatter(){
this(new PreciseFormatter());
}
@Override
public String format(LogRecord record){
return map.get(record.getLevel()).colorize(delegate.format(record));
}
}