/*
* Copyright to the original author or authors.
*
* Licensed 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 org.rioproject.logging.jul;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.logging.*;
/**
* An extension of {@link java.util.logging.FileHandler} that sets the pattern based on system properties.
*
* <b>Configuration:</b>
* By default each <tt>FileHandler</tt> is initialized using the following
* <tt>LogManager</tt> configuration properties. If properties are not defined
* (or have invalid values) then the specified default values are used.
* <ul>
* <li>FileHandler.level specifies the default level for the <tt>Handler</tt>
* (defaults to <tt>Level.ALL</tt>).
* <li>FileHandler.filter specifies the name of a <tt>Filter</tt> class to use
* (defaults to no <tt>Filter</tt>).
* <li>FileHandler.formatter specifies the name of a <tt>Formatter</tt> class to use
* (defaults to <tt>org.rioproject.log.XMLFormatter</tt>)
* <li>FileHandler.encoding the name of the character set encoding to use
* (defaults to the default platform encoding).
* <li>FileHandler.limit specifies an approximate maximum amount to write (in bytes)
* to any one file. If this is zero, then there is no limit. (Defaults to no limit).
* <li>FileHandler.count specifies how many output files to cycle through (defaults to 1).
* <li>FileHandler.pattern specifies a pattern for generating the output file name. See
* below for details. (Defaults to "%h/java%u.log").
* <li>FileHandler.append specifies whether the FileHandler should append onto
* any existing files (defaults to false).
* </ul>
*
* @author Dennis Reedy
*/
public class FileHandler extends java.util.logging.FileHandler {
static Configuration configuration = getConfiguration();
public FileHandler() throws IOException, SecurityException {
super(configuration.pattern, configuration.limit, configuration.count, configuration.append);
setEncoding(configuration.encoding);
}
@Override
public void setFormatter(Formatter formatter) throws SecurityException {
super.setFormatter(formatter);
/* if we have a RioLogFormatter, turn of colorization */
if(formatter instanceof RioLogFormatter) {
((RioLogFormatter)formatter).setColorization(false);
}
}
public String getLockFileName() {
String lockFileName = "";
try {
Field getLockFileName = this.getClass().getSuperclass().getDeclaredField("lockFileName");
getLockFileName.setAccessible(true);
lockFileName = (String)getLockFileName.get(this);
} catch (NoSuchFieldException e) {
Logger.getAnonymousLogger().log(Level.WARNING, "Getting lockFileName", e);
} catch (IllegalAccessException e) {
Logger.getAnonymousLogger().log(Level.WARNING, "Getting lockFileName", e);
}
return lockFileName;
}
private static Configuration getConfiguration() {
LogManager manager = LogManager.getLogManager();
String propertyBase = FileHandler.class.getName();
String pattern = manager.getProperty(propertyBase+".pattern");
int limit = getLimitProperty(manager, propertyBase + ".limit", 0);
if (limit < 0) {
limit = 0;
}
int count = getIntProperty(manager, propertyBase + ".count", 0);
if (count <= 0) {
count = 1;
}
boolean append = getBooleanProperty(manager, propertyBase + ".append", false);
String encoding = manager.getProperty(propertyBase+".encoding");
String logDirectory = System.getProperty("rio.log.dir");
String service = System.getProperty("org.rioproject.service");
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name;
int ndx = name.indexOf("@");
if(ndx>=1) {
pid = name.substring(0, ndx);
}
if(logDirectory!=null) {
File dir = new File(logDirectory);
if(!dir.exists()) {
dir.mkdirs();
}
pattern = replace(pattern, "${rio.log.dir}", logDirectory);
}
if(service!=null)
pattern = replace(pattern, "${org.rioproject.service}", service);
pattern = replace(pattern, "%pid", pid);
pattern = replace(pattern, "%name", name);
return new Configuration(limit, count, append, pattern, encoding);
}
static int getLimitProperty(LogManager manager, String name, int defaultValue) {
double KB = 1024;
/** Megabytes */
double MB = Math.pow(KB, 2);
/** Gigabytes */
double GB = Math.pow(KB, 3);
String val = manager.getProperty(name);
if (val == null) {
return defaultValue;
}
val = val.trim();
if(val.endsWith("M") || val.endsWith("MB")) {
int ndx = val.indexOf("M");
val = val.substring(0, ndx);
int result = getInteger(val, defaultValue);
return (int) (result*MB);
}
if(val.endsWith("G") || val.endsWith("GB")) {
int ndx = val.indexOf("G");
val = val.substring(0, ndx);
int result = getInteger(val, defaultValue);
return (int) (result*GB);
}
return getInteger(val, defaultValue);
}
static int getIntProperty(LogManager manager, String name, int defaultValue) {
String val = manager.getProperty(name);
if (val == null) {
return defaultValue;
}
return getInteger(val, defaultValue);
}
static int getInteger(String s, int defaultValue) {
try {
return Integer.parseInt(s.trim());
} catch (Exception ex) {
return defaultValue;
}
}
static boolean getBooleanProperty(LogManager manager, String name, boolean defaultValue) {
String val = manager.getProperty(name);
if (val == null) {
return defaultValue;
}
val = val.toLowerCase();
if (val.equals("true") || val.equals("1")) {
return true;
} else if (val.equals("false") || val.equals("0")) {
return false;
}
return defaultValue;
}
static String replace(String str, String pattern, String replace) {
if(str==null)
return "";
int s = 0;
int e;
StringBuilder result = new StringBuilder();
while ((e = str.indexOf(pattern, s)) >= 0) {
result.append(str.substring(s, e));
result.append(replace);
s = e + pattern.length();
}
result.append(str.substring(s));
return result.toString();
}
private static class Configuration {
int limit;
int count;
boolean append;
String pattern;
String encoding;
private Configuration(int limit, int count, boolean append, String pattern, String encoding) {
this.limit = limit;
this.count = count;
this.append = append;
this.pattern = pattern;
this.encoding = encoding;
}
}
}