/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.logging;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* This class represents the interface to a single logging framework
* that is easily accessible by any component. Using the LogManager, a component
* can quickly submit a log message, and can rely upon the LogManager to determine
* (a) whether that message is to be recorded or discarded; and (b) where
* to send any recorded messages. Thus, the component's code that submits
* messages does not have to be modified to alter the logging behavior of the
* application.
* <p>
* By default, all context(s) are logged by the LogManager. The messages that
* the LogManager actually records and sends to the destinations
* can be controlled using two different and orthogonal parameters.
* The first is a message <i>level</i> that filters messages based upon detail,
* and the second is a message <i>context</i> that filters messages based upon
* origin. The LogManager tracks only those context(s) that should NOT be
* logged. Only if a message (which also is defined with these two parameters)
* passes both filters will it be sent to the destinations.
* <p>
* Each message is submitted with one of the following levels (determined
* by the particular method used to submit the message), sorted from the
* least detailed to the greatest:
* <li><b>Critical</b>: This level of message is generally
* used to record an event or error that must be recorded (if any logging
* is used). If it is used to record an error, it generally means that the
* system encountered a critical error which affects the integrity, accuracy,
* reliability and/or capability of the system.</li>
* <li><b>Error</b>: Error messages are generally used
* to record unexpected problems, or errors that are not critical in nature
* and from which the system can automatically recover.</li>
* <li><b>Warning</b>: Warning messages generally described
* expected errors from which the system should recover. However, this level
* is used to record the fact that such an error or event did occur.</li>
* <li><b>Information</b>: This level of logging is the usually
* the normal level. All interesting periodic events should be logged at this
* level so someone looking through the log can see the amount and kind of
* processing happening in the system.</li>
* <li><b>Detail</b>: Such messages are moderately detailed,
* and help to debug typical problems in the system. Generally, these
* messages are not so detailed that the big picture gets lost.</li>
* <li><b>Trace</b>: A trace message is the most detailed
* logging level, used to trace system execution for really nasty problems.
* At this level, logging will be so verbose that the system performance
* may be affected.</li>
* <p>
* The context for a message is any application-specified String. Again, only
* those message contexts that match those in the LogManager's configuration will
* be sent to the destinations.
*
*/
public final class LogManager {
public static class LoggingProxy implements InvocationHandler {
private final Object instance;
private final String loggingContext;
private final int level;
public LoggingProxy(Object instance, String loggingContext, int level) {
this.instance = instance;
this.loggingContext = loggingContext;
this.level = level;
}
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
boolean log = LogManager.isMessageToBeRecorded(loggingContext, level);
if (log) {
StringBuffer message = new StringBuffer();
message.append("before "); //$NON-NLS-1$
message.append(method.getName());
message.append(":"); //$NON-NLS-1$
message.append(instance);
message.append("("); //$NON-NLS-1$
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
message.append(args[i]);
} else {
message.append("null"); //$NON-NLS-1$
}
if (i != args.length - 1) {
message.append(","); //$NON-NLS-1$
}
}
}
message.append(")"); //$NON-NLS-1$
LogManager.log(level, loggingContext, message.toString());
}
try {
Object result = method.invoke(instance, args);
if (log) {
LogManager.log(level, loggingContext,
"after " + method.getName()+ " : "+result); //$NON-NLS-1$ //$NON-NLS-2$
}
return result;
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
static volatile Logger logListener = new JavaLogger(); // either injected or manually set using the set methods
/**
* Send a critical message to the log. This level of message is generally
* used to record an event or error that must be recorded (if any logging
* is used). If it is used to record an error, it generally means that the
* system encountered a critical error which affects the integrity, accuracy,
* reliability and/or capability of the system.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param message the log message; the message is
* not logged if this parameter is null
*/
public static void logCritical(String context, Object message) {
logMessage(MessageLevel.CRITICAL, context, message);
}
/**
* Send a critical message to the log. This level of message is generally
* used to record an event or error that must be recorded (if any logging
* is used). If it is used to record an error, it generally means that the
* system encountered a critical error which affects the integrity, accuracy,
* reliability and/or capability of the system.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param message the log message (may be null)
*/
public static void logCritical(String context, Throwable e, Object message) {
log(MessageLevel.CRITICAL,context,e,message);
}
/**
* Send an error message to the log. Error messages are generally used
* to record unexpected problems, or errors that are not critical in nature
* and from which the system can automatically recover.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param message the log message; the message is
* not logged if this parameter is null
*/
public static void logError(String context, Object message) {
logMessage(MessageLevel.ERROR, context,message);
}
/**
* Send an error message to the log. Error messages are generally used
* to record unexpected problems, or errors that are not critical in nature
* and from which the system can automatically recover.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param message the log message (may be null)
*/
public static void logError(String context, Throwable e, Object message) {
log(MessageLevel.ERROR,context,e,message);
}
/**
* Send a warning message to the log. Warning messages generally described
* expected errors from which the system should recover. However, this level
* is used to record the fact that such an error or event did occur.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param message the log message; the message is
* not logged if this parameter is null
*/
public static void logWarning(String context, Object message) {
logMessage(MessageLevel.WARNING, context,message);
}
/**
* Send a warning message to the log. Warning messages generally described
* expected errors from which the system should recover. However, this level
* is used to record the fact that such an error or event did occur.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param message the log message (may be null)
*/
public static void logWarning(String context, Throwable e, Object message) {
log(MessageLevel.WARNING,context,e,message);
}
/**
* Send a information message to the log. This level of logging is the usually
* the normal level. All interesting periodic events should be logged at this
* level so someone looking through the log can see the amount and kind of
* processing happening in the system.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param message the log message; the message is
* not logged if this parameter is null
*/
public static void logInfo(String context, Object message) {
logMessage(MessageLevel.INFO, context,message);
}
/**
* Send a detail message to the log. Such messages are moderately detailed,
* and help to debug typical problems in the system. Generally, these
* messages are not so detailed that the big picture gets lost.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param msgParts the individual parts of the log message; the message is
* not logged if this parameter is null
*/
public static void logDetail(String context, Object msgPart) {
logMessage(MessageLevel.DETAIL, context, msgPart);
}
public static void logDetail(String context, Object msgPart, Object msgPart1) {
logMessage(MessageLevel.DETAIL, context, msgPart, msgPart1);
}
public static void logDetail(String context, Object msgPart, Object msgPart1, Object msgPart2) {
logMessage(MessageLevel.DETAIL, context, msgPart, msgPart1, msgPart2);
}
public static void logDetail(String context, Object ... msgParts) {
logMessage(MessageLevel.DETAIL, context, msgParts);
}
/**
* Send a detail message to the log. Such messages are moderately detailed,
* and help to debug typical problems in the system. Generally, these
* messages are not so detailed that the big picture gets lost.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param message the log message (may be null)
*/
public static void logDetail(String context, Throwable e, Object ... message) {
log(MessageLevel.DETAIL,context,e,message);
}
/**
* Send a trace message to the log. A trace message is the most detailed
* logging level, used to trace system execution for really nasty problems.
* At this level, logging will be so verbose that the system performance
* may be affected.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param msgParts the individual parts of the log message; the message is
* not logged if this parameter is null
*/
public static void logTrace(String context, Object ... msgParts) {
logMessage(MessageLevel.TRACE, context, msgParts);
}
public static void logTrace(String context, Object msgPart) {
logMessage(MessageLevel.TRACE, context, msgPart);
}
public static void logTrace(String context, Object msgPart, Object msgPart1) {
logMessage(MessageLevel.TRACE, context, msgPart, msgPart1);
}
public static void logTrace(String context, Object msgPart, Object msgPart1, Object msgPart2) {
logMessage(MessageLevel.TRACE, context, msgPart, msgPart1, msgPart2);
}
/**
* Send a trace message to the log. A trace message is the most detailed
* logging level, used to trace system execution for really nasty problems.
* At this level, logging will be so verbose that the system performance
* may be affected.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param msgParts the individual parts of the log message (may be null)
*/
public static void logTrace(String context, Throwable e, Object ... msgParts) {
logMessage(MessageLevel.TRACE,context,e,msgParts);
}
/**
* Send a message of the specified level to the log.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param msgLevel
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param message the individual parts of the log message; the message is
* not logged if this parameter is null
*/
public static void log(int msgLevel, String context, Object message) {
logMessage(msgLevel, context, message);
}
/**
* Send a message of the specified level to the log.
* <p>
* Only if the log manager is configured to send such messages to the
* destination will the message be recorded.
* @param context the context for this log message (for example, the component
* that is generating this message).
* @param e the exception that is to be logged; the message is
* not logged if this parameter is null
* @param message the individual parts of the log message; the message is
* not logged if this parameter is null
*/
public static void log(int msgLevel, String context, Throwable e, Object... message) {
if (!isMessageToBeRecorded(context, msgLevel)) {
return;
}
logListener.log(msgLevel, context, e, message);
}
public static void setLogListener(Logger listener) {
logListener.shutdown();
if (listener != null) {
logListener = listener;
}
else {
logListener = new JavaLogger();
}
}
/**
* Utility method to identify whether a log message with the specified
* context and level will be recorded in the LogManager's destinations.
* @param context
* @param msgLevel
* @return true if the message would be recorded if sent to the LogManager,
* or false if it would be discarded by the LogManager.
*/
public static boolean isMessageToBeRecorded(String context, int msgLevel) {
if (logListener != null) {
return logListener.isEnabled(context, msgLevel);
}
return true;
}
private static void logMessage(int level, String context, Object ... msgParts) {
if (msgParts == null || msgParts.length == 0 || !isMessageToBeRecorded(context, level)) {
return;
}
logListener.log(level, context, msgParts);
}
private static void logMessage(int level, String context, Object msgPart) {
if (msgPart == null || !isMessageToBeRecorded(context, level)) {
return;
}
logListener.log(level, context, msgPart);
}
private static void logMessage(int level, String context, Object msgPart, Object msgPart1) {
if (msgPart == null || !isMessageToBeRecorded(context, level)) {
return;
}
logListener.log(level, context, msgPart, msgPart1);
}
private static void logMessage(int level, String context, Object msgPart, Object msgPart1, Object msgPart2) {
if (msgPart == null || !isMessageToBeRecorded(context, level)) {
return;
}
logListener.log(level, context, msgPart, msgPart1, msgPart2);
}
/**
* Create a logging proxy, that logs at entry and exit points of the method calls on the provided interfaces.
*/
public static Object createLoggingProxy(final String loggingContext,
final Object instance,
final Class<?>[] interfaces,
final int level) {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new LoggingProxy(instance, loggingContext, level));
}
public static Object createLoggingProxy(final String loggingContext,
final Object instance,
final Class<?>[] interfaces,
final int level,
ClassLoader classLoader) {
return Proxy.newProxyInstance(classLoader, interfaces, new LoggingProxy(instance, loggingContext, level));
}
public static void putMdc(String key, String val) {
logListener.putMdc(key, val);
}
public static void removeMdc(String key) {
logListener.removeMdc(key);
}
}