/*
Copyright (C) 2007 Mobixess Inc. http://www.java-objects-database.com
This file is part of the JODB (Java Objects Database) open source project.
JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.
JODB 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 General Public License
for more details.
You should have received a copy of the GNU 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.
*/
package com.mobixess.jodb.util.logging;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class SimpleConsoleHandler extends ConsoleHandler {
private final static String format = "{0,date} {0,time}";
Date dat = new Date();
private MessageFormat formatter;
private Object args[] = new Object[1];
@SuppressWarnings("unchecked")
private String lineSeparator = (String) java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction("line.separator"));
private String[] LOGGING_CLASSES_FULL = new String[] { Logger.class.getName() };
private String[] LOGGING_CLASSES_PREFIXES = new String[] { "com.spsoft.msgboard.management.userBrowser.core.container.BrowserAppLogger", "java.security.AccessController" };
@Override
public void publish(LogRecord record)
{
format(record);
}
/**
* Format the given LogRecord.
*
* @param record
* the log record to be formatted.
* @return a formatted log record
*/
public synchronized String format(LogRecord record) {
StringBuffer sb = new StringBuffer();
// Minimize memory allocations here.
dat.setTime(record.getMillis());
args[0] = dat;
StringBuffer text = new StringBuffer();
if (formatter == null) {
formatter = new MessageFormat(format);
}
formatter.format(args, text, null);
sb.append(text);
sb.append(" ");
// if (record.getSourceClassName() != null) {
// sb.append(record.getSourceClassName());
// } else {
// sb.append(record.getLoggerName());
// }
// if (record.getSourceMethodName() != null) {
// sb.append(".");
// sb.append(record.getSourceMethodName());
// }
sb.append(getLineAndSrc());
sb.append(" Thread: " + record.getThreadID());
sb.append(lineSeparator);
String message = formatMessage(record);
sb.append("\t"+record.getLevel().getLocalizedName());
sb.append(": ");
sb.append(message);
sb.append(lineSeparator);
if (record.getThrown() != null) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
record.getThrown().printStackTrace(pw);
pw.close();
sb.append(sw.toString());
} catch (Exception ex) {
}
sb.append(lineSeparator);
}
String result = sb.toString();
if(record.getLevel().intValue() <= Level.INFO.intValue()){
System.out.print(result);
}else{
System.err.print(result);
}
return result;
}
// Private method to infer the caller's class and method names
protected String getLineAndSrc() {
// Get the stack trace.
StackTraceElement stack[] = (new Throwable()).getStackTrace();
// First, search back to a method in the Logger class.
int ix = 0;
while (ix < stack.length) {
StackTraceElement frame = stack[ix];
String cname = frame.getClassName();
if (isLoggingClass(cname)) {
break;
}
ix++;
}
// Now search for the first frame before the "Logger" class.
while (ix < stack.length) {
StackTraceElement frame = stack[ix];
String cname = frame.getClassName();
if (!isLoggingClass(cname)) {
// We've found the relevant frame.
//setSourceClassName(cname);
//setSourceMethodName(frame.getMethodName());
return frame.getClassName()+'.'+frame.getMethodName()+'(' + frame.getFileName() + ':' + frame.getLineNumber()
+ ')';
}
ix++;
}
// We haven't found a suitable frame, so just punt. This is
// OK as we are only committed to making a "best effort" here.
return "";
}
private boolean isLoggingClass(String name){
for (int i = 0; i < LOGGING_CLASSES_FULL.length; i++) {
if(LOGGING_CLASSES_FULL[i].equals(name)){
return true;
}
}
for (int i = 0; i < LOGGING_CLASSES_PREFIXES.length; i++) {
if(name.startsWith(LOGGING_CLASSES_PREFIXES[i])){
return true;
}
}
return false;
}
/**
* Localize and format the message string from a log record. This
* method is provided as a convenience for Formatter subclasses to
* use when they are performing formatting.
* <p>
* The message string is first localized to a format string using
* the record's ResourceBundle. (If there is no ResourceBundle,
* or if the message key is not found, then the key is used as the
* format string.) The format String uses java.text style
* formatting.
* <ul>
* <li>If there are no parameters, no formatter is used.
* <li>Otherwise, if the string contains "{0" then
* java.text.MessageFormat is used to format the string.
* <li>Otherwise no formatting is performed.
* </ul>
* <p>
*
* @param record the log record containing the raw message
* @return a localized and formatted message
*/
public synchronized String formatMessage(LogRecord record) {
String format = record.getMessage();
java.util.ResourceBundle catalog = record.getResourceBundle();
if (catalog != null) {
// // We cache catalog lookups. This is mostly to avoid the
// // cost of exceptions for keys that are not in the catalog.
// if (catalogCache == null) {
// catalogCache = new HashMap();
// }
// format = (String)catalogCache.get(record.essage);
// if (format == null) {
try {
format = catalog.getString(record.getMessage());
} catch (java.util.MissingResourceException ex) {
// Drop through. Use record message as format
format = record.getMessage();
}
// catalogCache.put(record.message, format);
// }
}
// Do the formatting.
try {
Object parameters[] = record.getParameters();
if (parameters == null || parameters.length == 0) {
// No parameters. Just return format string.
return format;
}
// Is is a java.text style format?
// Ideally we could match with
// Pattern.compile("\\{\\d").matcher(format).find())
// However the cost is 14% higher, so we cheaply check for
// 1 of the first 4 parameters
if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
return java.text.MessageFormat.format(format, parameters);
}
return format;
} catch (Exception ex) {
// Formatting failed: use localized format string.
return format;
}
}
}