/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2006, by :
* Corporate:
* EADS Astrium SAS
* Individual:
* Claude Cazenave
*
* $Id: LogConfigurator.java,v 1.11 2008/09/29 16:26:25 altournoud Exp $
*
* Changes
* -------
* 1 sept. 06 : Initial public release (CC);
*
*/
package simtools.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SocketHandler;
public class LogConfigurator {
/**
* The ROOT_LOGGER_PREFIX: use to configure the root logger in the property file.
*/
private static final String ROOT_LOGGER_PREFIX = "ROOT";
/**
* The properties to get the configuration from
*/
Properties properties;
/**
* The prefix used to compute property names
*/
protected String propertyPrefix;
/**
* The resulting configured handler
* It can be either the SocketHandler if a port number defintion is found
* or the the FileHandler if a pattern defintion is found or the ConsoleHandler
*/
protected ArrayList outHandlerList = null;
/**
* The various log levels read from the properties
*/
protected ArrayList levels=new ArrayList();
/**
* The various logger prefix read from the properties
* The level applied to each logger is contained at the same index
* in the levels list
*/
protected ArrayList prefixes=new ArrayList();
/**
* A list of created configurator to automatically
* apply the configuration to the new created loggers
*/
private static ArrayList configurators=new ArrayList();
private static Object configuratorsLock=new Object();
/**(<b>Level</b>) defaultLowestLevel: The default lowest level to be used, if no configuration is specified.*/
private static Level defaultLowestLevel = Level.SEVERE;
/**
* The computed lowes level used to configure the handler
*/
protected Level lowestLevel=null;
/**
* Read the logging configuration
* @param p
* @param prefix
*/
public LogConfigurator(Properties p, String prefix){
properties=p;
propertyPrefix=prefix;
lowestLevel = defaultLowestLevel;
configure();
synchronized(configuratorsLock){
configurators.add(this);
}
}
/**
* Replace Loggger.getLogger call with this method
* in order to apply configuration to the new created loggers
*
* @param name the logger name
* @return the new logger as returned by Logger.getLogger(name)
*/
public static Logger getLogger(String name){
Logger res=Logger.getLogger(name);
synchronized(configuratorsLock){
for(int i=0;i<configurators.size();i++){
((LogConfigurator)configurators.get(i)).apply(res);
}
}
return res;
}
/**
* Apply the logging configuration to the current loggers
* Can be called several times in case new classes are loaded
*/
public void apply(){
LogManager lm=LogManager.getLogManager();
if(lowestLevel != null){
for(Iterator handlerIterator = outHandlerList.iterator(); handlerIterator.hasNext();){
Handler outHandler = (Handler) handlerIterator.next();
outHandler.setLevel(lowestLevel);
}
}
Enumeration e=lm.getLoggerNames();
while(e.hasMoreElements()){
Logger l=lm.getLogger((String)e.nextElement());
apply(l);
}
}
void apply(Logger logger){
for(int i=0;i<prefixes.size();i++){
if(logger.getName().startsWith((String)prefixes.get(i)) || (logger.getName().equals("") && prefixes.get(i).equals(ROOT_LOGGER_PREFIX))){
// remove silently the outHandler
// in case it was already set
for(Iterator handlerIterator = outHandlerList.iterator(); handlerIterator.hasNext();){
Handler outHandler = (Handler) handlerIterator.next();
logger.removeHandler(outHandler);
logger.addHandler(outHandler);
}
// TODO add property to configure that
logger.setUseParentHandlers(false);
logger.setLevel((Level)levels.get(i));
}
}
}
/**
* Get logging configuration from properties and create
* the lgging handler accondingly
*/
protected void configure(){
String loggingOut = getString("loggings.out", getDefaultFileHandlerPattern());
outHandlerList=new ArrayList();
try{
int portId=Integer.parseInt(loggingOut);
String loggingHost = getString("loggings.host","localhost");
try {
outHandlerList.add(new SocketHandler(loggingHost,portId));
} catch (IOException e) {
System.err.println("Logging can not connect with "+loggingHost+":"+portId);
}
}
catch(NumberFormatException nfe){
// if its not a number
if(loggingOut.length()!=0){
try {
outHandlerList.add(new FileHandler(loggingOut,0,getInt("loggings.out.number",1)));
} catch (SecurityException e) {
System.err.println("Security prevents logging into files");
} catch (IOException e) {
System.err.println("Can not log in "+loggingOut);
} catch (IllegalArgumentException e){
System.err.println("Invalid paremeters to log in "+loggingOut);
}
}
}
if(outHandlerList.size() == 0){
outHandlerList.add(new ConsoleHandler());
}
String loggingFormat = getString("loggings.format", "java.util.logging.XMLFormatter");
Formatter format=null;
try {
Class c = Class.forName(loggingFormat);
if(Formatter.class.isAssignableFrom(c)){
try {
format=(Formatter)c.newInstance();
} catch (InstantiationException e) {
System.err.println("Can not instantiate logging format class : "+loggingFormat);
} catch (IllegalAccessException e) {
System.err.println("Can not construct logging format class : "+loggingFormat);
}
}
else{
System.err.println("Invalid logging format class : "+loggingFormat);
}
} catch (ClassNotFoundException e) {
System.err.println("Unknown logging format class : "+loggingFormat);
}
if(format!=null){
for(Iterator handlerIterator = outHandlerList.iterator(); handlerIterator.hasNext();){
Handler outHandler = (Handler) handlerIterator.next();
outHandler.setFormatter(format);
}
}
configureLevels();
}
/**
* Configure logging levels according to properties
*/
protected void configureLevels(){
int loggingNumber = getInt("loggings.number", 0);
for (int i = 0; i < loggingNumber; i++) {
String loggingDef =
getString("loggings.logging" + i, "");
try{
int spcIndex=loggingDef.indexOf(' ');
if(spcIndex<0){
throw new IllegalArgumentException();
}
Level l=Level.parse(loggingDef.substring(0,spcIndex));
String prefix=loggingDef.substring(l.getName().length()+1).trim();
if(lowestLevel.intValue()>l.intValue()){
lowestLevel=l;
}
levels.add(l);
prefixes.add(prefix);
}
catch(IllegalArgumentException ie){
System.err.println("Invalid logging level in : "+loggingDef);
}
}
//If no level has been configured, configure one, and set it as default level.
if(prefixes.size() == 0){
prefixes.add(propertyPrefix);
levels.add(defaultLowestLevel);
prefixes.add(ROOT_LOGGER_PREFIX);
levels.add(defaultLowestLevel);
}
}
/**
* @return the defaukt pattern to use by the FileHandler
*/
protected String getDefaultFileHandlerPattern(){
return "%h"+propertyPrefix+".log";
}
/**
* Compute the property name according to the key parameter
* @param key to compute the property name
* @return the property name
*/
protected String getPropertyName(String key){
return propertyPrefix+"."+key;
}
/**
* Get a String value from properties
* @param key to compute the property name
* @param defaultValue the returned value if no property to define it
* @return the String value
*/
protected String getString(String key, String defaultValue){
return properties.getProperty(getPropertyName(key),defaultValue);
}
/**
* Get a int value from properties
* @param key to compute the property name
* @param defaultValue the returned value if no property to define it
* @return the int value
*/
protected int getInt(String key, int defaultValue){
String res = properties.getProperty(getPropertyName(key));
if (res == null) {
return defaultValue;
}
try {
return Integer.parseInt(res);
} catch (NumberFormatException nfe) {
return defaultValue;
}
}
/**
* Get a boolean value from properties
* @param key to compute the property name
* @param defaultValue the returned value if no property to define it
* @return the value
*/
public boolean getBoolean(String key, boolean defaultValue) {
String res=properties.getProperty(getPropertyName(key), defaultValue ? "TRUE" : "FALSE");
return res.toUpperCase().equals("TRUE");
}
/**
* Method setDefaultLowestLevel
* <br><b>Summary:</b><br>
* Set the default lowest level of logs.
* This level will be used if no configuration is available.
* @param defaultLowestLevel the defaultLowestLevel to set. Level.SEVERE/WARNING etc..
*/
public static void setDefaultLowestLevel(Level defaultLowestLevel) {
//Beware of null arguments.
if(defaultLowestLevel != null){
LogConfigurator.defaultLowestLevel = defaultLowestLevel;
}
}
public void addOutHandler(Handler handler){
if(outHandlerList != null && !outHandlerList.contains(handler)){
outHandlerList.add(handler);
}
}
public boolean removeOutHandler(Handler handler){
boolean result = false;
if(outHandlerList != null){
result = outHandlerList.remove(handler);
}
return result;
}
}