
org.openrdf.util.log.ThreadLog Maven / Gradle / Ivy
/* Sesame - Storage and Querying architecture for RDF and RDF Schema
* Copyright (C) 2001-2006 Aduna
*
* Contact:
* Aduna
* Prinses Julianaplein 14 b
* 3817 CS Amersfoort
* The Netherlands
* tel. +33 (0)33 465 99 87
* fax. +33 (0)33 465 99 87
*
* http://aduna-software.com/
* http://www.openrdf.org/
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.openrdf.util.log;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
/**
* Thread-based logging utility. The ThreadLog requires threads to register
* themselves with the ThreadLog. In this registration procedure, a mapping
* is made between the thread calling the registration method and an instance
* of ThreadLog. This mapping is later used in all calls to logging-methods
* to look-up whether these messages should be logged, and where they should
* be logged.
*
* Log messages are assigned a "level of importance". From high to low, these
* levels are ERROR, WARNING, STATUS and TRACE. Messages can be suppressed
* based on these levels. If a Thread registers itself with log level WARNING,
* only errors and warning will be logged; status messages and traces will be
* suppressed.
*/
public class ThreadLog {
/*------------------------------------------------+
| Constants |
+------------------------------------------------*/
public static final int NONE = 0;
public static final int ERROR = 1;
public static final int WARNING = 2;
public static final int STATUS = 3;
public static final int TRACE = 4;
public static final int ALL = 5;
/*------------------------------------------------+
| Static variables |
+------------------------------------------------*/
static SimpleDateFormat _formatter =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
static String[] _levelNames = {
"NONE ",
"ERROR ",
"WARNING",
"STATUS ",
"TRACE ",
"ALL " };
/** Keeps track of which Threads maps to which ThreadLogs. **/
static InheritableThreadLocal _threadContext =
new InheritableThreadLocal();
static ThreadLog _defaultThreadLog;
/** Maps (absolute) file paths to PrintWriters. **/
static HashMap _writerTable = new HashMap();
/*------------------------------------------------+
| Static methods |
+------------------------------------------------*/
/**
* Sets a default log file for all threads that have not registered
* themselves. Logging calls from any of these threads to ThreadLog
* will be logged to the specified log file if their priority is equal
* to or higher then the specified log level. If 'logFile' is equal
* to 'null', messages will be printed to System.err.
* @param logFile The file to log to, or null to log messages
* to System.err.
* @param logLevel One of the constants ERROR, WARNING, STATUS, TRACE, or ALL.
* @see #ERROR
* @see #WARNING
* @see #STATUS
* @see #TRACE
* @see #ALL
**/
public static void setDefaultLog(String logFile, int logLevel) {
if (_defaultThreadLog == null) {
_defaultThreadLog = new ThreadLog();
}
Writer logWriter = null;
try {
logWriter = _getLogWriter(logFile);
}
catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
try {
logWriter = _getLogWriter(null);
}
catch (IOException ignore) {
// ignore
}
}
_defaultThreadLog.setLogWriter(logWriter);
_defaultThreadLog.setLogLev(logLevel);
}
/**
* Unsets the default log file for all threads that have not
* registered themselves.
**/
public static void unsetDefaultLog() {
_defaultThreadLog = null;
}
/**
* Registers the calling thread with the ThreadLog. Logging calls to
* ThreadLog will be logged to the specified log file if their priority is
* equal to or higher then the specified log level. If 'logFile' is equal
* to 'null', messages will be printed to System.err.
* @param logFile The file to log to, or null to log messages
* to System.err.
* @param logLevel One of the constants ERROR, WARNING, STATUS, TRACE, or ALL.
* @see #ERROR
* @see #WARNING
* @see #STATUS
* @see #TRACE
* @see #ALL
**/
public static void registerThread(String logFile, int logLevel) {
ThreadLog threadLog = _createThreadLog();
Writer logWriter = null;
try {
logWriter = _getLogWriter(logFile);
}
catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
try {
logWriter = _getLogWriter(null);
}
catch (IOException ignore) {
// ignore
}
}
threadLog.setLogWriter(logWriter);
threadLog.setLogLev(logLevel);
Thread currentThread = Thread.currentThread();
threadLog.setThreadName(currentThread.getName());
}
/**
* Changes the log level for the calling thread.
* @param logLevel One of the constants ERROR, WARNING, STATUS, TRACE, or ALL.
* @see #ERROR
* @see #WARNING
* @see #STATUS
* @see #TRACE
**/
public static void setLogLevel(int logLevel) {
ThreadLog threadLog = null;
synchronized (_threadContext) {
threadLog = (ThreadLog)_threadContext.get();
}
if (threadLog != null) {
threadLog.setLogLev(logLevel);
}
}
/**
* Creates a ThreadLog for the thread calling this method. If the
* thread has already created a ThreadLog before, this existing
* ThreadLog will be returned.
**/
static ThreadLog _createThreadLog() {
ThreadLog threadLog = null;
synchronized (_threadContext) {
threadLog = (ThreadLog)_threadContext.get();
if (threadLog == null) {
threadLog = new ThreadLog();
_threadContext.set(threadLog);
}
}
return threadLog;
}
/**
* Gets a (possibly shared) Writer to the specified logFile.
**/
static Writer _getLogWriter(String logFile)
throws IOException
{
Writer logWriter = null;
String absPath = null;
File file = null;
if (logFile != null) {
file = new File(logFile);
absPath = file.getAbsolutePath();
}
synchronized (_writerTable) {
logWriter = (Writer)_writerTable.get(absPath);
if (logWriter == null) {
// Create a new log writer
if (absPath != null) {
// Check if parent directory exists yet
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
logWriter = new FileWriter(absPath, true);
}
else {
logWriter = new OutputStreamWriter(System.err);
}
_writerTable.put(absPath, logWriter);
}
}
return logWriter;
}
/**
* Deregisters the calling thread with the ThreadLog. Logging calls to
* ThreadLog on the calling thread will no longer be logged.
**/
public static void deregisterThread() {
synchronized (_threadContext) {
_threadContext.set(null);
}
}
/**
* Gets the ThreadLog for the thread calling this method. If no
* ThreadLog is available, null will be returned.
**/
static ThreadLog _getThreadLog() {
ThreadLog threadLog = null;
synchronized (_threadContext) {
threadLog = (ThreadLog)_threadContext.get();
}
if (threadLog == null) {
threadLog = _defaultThreadLog;
}
return threadLog;
}
/*------------------------------------------------+
| Variables |
+------------------------------------------------*/
/** Writer for the log file. **/
Writer _logWriter;
/** Log level **/
int _logLevel;
/**
* Name of the thread.
**/
String _threadName;
/*------------------------------------------------+
| Constructors |
+------------------------------------------------*/
ThreadLog() {
this(null, ALL);
}
ThreadLog(Writer logWriter) {
this(logWriter, ALL);
}
ThreadLog(Writer logWriter, int logLevel) {
setLogWriter(logWriter);
setLogLev(logLevel);
_threadName = null;
}
/*------------------------------------------------+
| Methods |
+------------------------------------------------*/
void setLogWriter(Writer logWriter) {
_logWriter = logWriter;
}
void setLogLev(int logLevel) {
_logLevel = logLevel;
}
int getLogLevel() {
return _logLevel;
}
void setThreadName(String threadName) {
_threadName = threadName;
}
String getThreadName() {
return _threadName;
}
void doLog(String msg, Object arg, int level) {
// First check log level
if (_logLevel < level) {
return;
}
// Create log message
String logMsg = _createLogMessage(msg, arg, level, _threadName);
// Write log message
// Synchronize on _logWriter to prevent mixed lines
try {
synchronized(_logWriter) {
_logWriter.write(logMsg);
_logWriter.flush();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
static String _createLogMessage(
String msg, Object arg, int level, String threadName)
{
StringBuffer logMsg = new StringBuffer(128);
logMsg.append(_formatter.format(new Date()));
if (threadName != null) {
logMsg.append(" [");
logMsg.append(threadName);
logMsg.append("]");
}
logMsg.append(" [");
logMsg.append(_levelNames[level]);
logMsg.append("] ");
logMsg.append(msg);
if (arg != null) {
logMsg.append(": ");
if (arg instanceof Throwable) {
Throwable throwable = (Throwable)arg;
logMsg.append(throwable.getMessage());
logMsg.append("\n");
java.io.StringWriter stackTrace = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(stackTrace);
throwable.printStackTrace(pw);
logMsg.append(stackTrace.toString());
}
else {
logMsg.append(arg);
}
}
logMsg.append("\n");
return logMsg.toString();
}
/*------------------------------------------------+
| Static utility methods |
+------------------------------------------------*/
/**
* Logs an error.
* @param msg A indicative message for the error.
**/
public static void error(String msg) {
_log(msg, null, ERROR);
}
/**
* Logs an error.
* @param msg A indicative message for the error.
* @param arg An argument related to the error. In case arg is an
* instance of java.lang.Throwable, the message and stack trace
* of the argument will be logged.
**/
public static void error(String msg, Object arg) {
_log(msg, arg, ERROR);
}
/**
* Logs a warning.
* @param msg A indicative message for the warning.
**/
public static void warning(String msg) {
_log(msg, null, WARNING);
}
/**
* Logs a warning.
* @param msg A indicative message for the warning.
* @param arg An argument related to the warning. In case arg is an
* instance of java.lang.Throwable, the message and stack trace
* of the argument will be logged.
**/
public static void warning(String msg, Object arg) {
_log(msg, arg, WARNING);
}
/**
* Logs a message.
* @param msg A indicative message for the message.
**/
public static void log(String msg) {
_log(msg, null, STATUS);
}
/**
* Logs a message.
* @param msg A indicative message for the message.
* @param arg An argument related to the message. In case arg is an
* instance of java.lang.Throwable, the message and stack trace
* of the argument will be logged.
**/
public static void log(String msg, Object arg) {
_log(msg, arg, STATUS);
}
/**
* Logs a trace message.
* @param msg A indicative message for the trace message.
**/
public static void trace(String msg) {
_log(msg, null, TRACE);
}
/**
* Logs a trace message.
* @param msg A indicative message for the trace message.
* @param arg An argument related to the trace message. In case arg is an
* instance of java.lang.Throwable, the message and stack trace
* of the argument will be logged.
**/
public static void trace(String msg, Object arg) {
_log(msg, arg, TRACE);
}
/**
* Logs a message on the specified level.
* @param msg A indicative message for the trace message.
* @param arg An argument related to the trace message. In case arg is an
* instance of java.lang.Throwable, the message and stack trace
* of the argument will be logged.
* @param level One of the constants ERROR, WARNING, STATUS, TRACE, or ALL.
* @see #ERROR
* @see #WARNING
* @see #STATUS
* @see #TRACE
* @see #ALL
**/
protected static void _log(String msg, Object arg, int level) {
ThreadLog threadLog = _getThreadLog();
if (threadLog != null) {
threadLog.doLog(msg, arg, level);
}
}
}