/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or 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 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 org.jajuk.util.log;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.jajuk.services.core.SessionService;
import org.jajuk.util.Const;
import org.jajuk.util.Messages;
import org.jajuk.util.error.JajukException;
/**
* Logging utility class, facade to logging system
* <p>
* Singleton.
*/
public final class Log {
/** The Constant FONT_END. */
private static final String FONT_END = "</font>";
/** The Constant LOGGER_APACHE_HTTPCLIENT. */
private static final String LOGGER_APACHE_HTTPCLIENT = "org.apache.commons.httpclient";
// verbosity consts
/** The Constant FATAL. */
public static final int FATAL = 0;
/** The Constant ERROR. */
public static final int ERROR = 1;
/** The Constant WARNING. */
public static final int WARNING = 2;
/** The Constant INFO. */
public static final int INFO = 3;
/** The Constant DEBUG. */
public static final int DEBUG = 4;
/** Verbosity level of the logger( between 1 and 5 ) <p> Default used at statup is INFO. */
private static int verbosity = INFO;
/** Jajuk logger. */
private static Logger logger;
/** Anonymized Debug traces spool. */
private static List<String> spoolAnonymized;
/** Clear Debug traces spool. */
private static List<String> spoolClear;
/** The Constant FULL_QUALIFIED_CLASS_NAME. */
private static final String FULL_QUALIFIED_CLASS_NAME = Log.class.getName();
/**
* Log system initialization.
*/
public static void init() {
try {
// set env variable used in the log4j conf file
System.setProperty("jajuk.log", SessionService.getConfFileByPath(Const.FILE_LOGS)
.getAbsolutePath());
DOMConfigurator.configure(Const.FILE_LOG4J_CONF);
} catch (Exception e) {
e.printStackTrace();
}
logger = Logger.getLogger(Log.class.getName());
spoolAnonymized = new ArrayList<String>(Const.FEEDBACK_LINES);
spoolClear = new ArrayList<String>(Const.FEEDBACK_LINES);
// message for logging system start
Log.info("******************JAJUK******************");
Log.info("Version: " + Const.JAJUK_VERSION);
}
/**
* Log a debug-level message.
*
* @param s
*/
public static synchronized void debug(String s) {
// Just display the message if Log is not yet enabled
if (logger == null) {
System.out.println("[DEBUG] " + s);
return;
}
spool("[DEBUG] " + s);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.DEBUG, s, null);
}
/**
* Debug.
*
*
* @param t
*/
public static void debug(Throwable t) {
debug("", t);
}
/**
* Debug.
*
*
* @param sInfosup
* @param t
*/
public static synchronized void debug(String sInfosup, Throwable t) {
// Just make a print stake trace if Log is not yet enabled (example:
// collection commit problem in initialCheckups)
if (logger == null) {
System.out.println("[DEBUG] " + sInfosup);
stack(t);
return;
}
String sOut;
if (Messages.isInitialized()) {
sOut = ((sInfosup == null) ? "" : ": " + sInfosup);
} else {
sOut = ((sInfosup == null) ? "" : ":" + sInfosup);
}
spool("<font color='red'>[DEBUG] " + sOut + FONT_END);
if (t != null) {
spool(t);
}
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.DEBUG, sOut, t);
}
/**
* Log a info-level message.
*
* @param s
*/
public static synchronized void info(String s) {
// Just display the message if Log is not yet enabled
if (logger == null) {
System.out.println("[INFO] " + s);
return;
}
spool("<font color='blue'>[INFO] " + s + FONT_END);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.INFO, s, null);
}
/**
* Log a warning-level message.
*
* @param s
*/
public static synchronized void warn(String s) {
// Just display the message if Log is not yet enabled
if (logger == null) {
System.out.println("[WARN] " + s);
return;
}
spool("<font color='orange'>[WARN] " + s + FONT_END);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, s, null);
}
/**
* Log a warning-level message with info sup.
*
* @param s
* @param sInfoSup
*/
public static synchronized void warn(String s, String sInfoSup) {
String sOut = s + ": " + sInfoSup;
// Just display the message if Log is not yet enabled
if (logger == null) {
System.out.println("[WARN] " + sOut);
return;
}
spool("<font color='orange'>[INFO] " + sOut + FONT_END);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, sOut, null);
}
/**
* Log an warning-level message.
*
* @param code error code
* @param sInfosup : error context information
* @param t the exception itself
*/
public static synchronized void warn(int code, String sInfosup, Throwable t) {
String sOut;
if (Messages.isInitialized()) {
sOut = "(" + code + ") " + Messages.getErrorMessage(code)
+ ((sInfosup == null) ? "" : ":" + sInfosup);
} else {
sOut = "(" + code + ") " + ((sInfosup == null) ? "" : ":" + sInfosup);
}
// Just display the message if Log is not yet enabled
if (logger == null) {
System.out.println("[WARN] " + sOut);
stack(t);
return;
}
spool("<font color='orange'>[WARN] " + sOut + FONT_END);
spool(t);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, sOut, t);
}
/**
* Log an error-level message.
*
* @param code error code
* @param sInfosup : error context information
* @param t the exception itself
*/
public static synchronized void error(int code, String sInfosup, Throwable t) {
// Just make a print stake trace if Log is not yet enabled (example:
// collection commit problem in initialCheckups)
if (logger == null) {
System.out.println("[ERROR] " + code + " / " + sInfosup);
stack(t);
return;
}
String sOut;
if (Messages.isInitialized()) {
sOut = "(" + code + ") " + Messages.getErrorMessage(code)
+ ((sInfosup == null) ? "" : ": " + sInfosup);
} else {
sOut = "(" + code + ") " + ((sInfosup == null) ? "" : ":" + sInfosup);
}
spool("<font color='red'>[ERROR] " + sOut + FONT_END);
if (t != null) {
spool(t);
}
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, sOut, t);
}
/**
* Log an error-level message.
*
* @param code error code
*/
public static synchronized void error(int code) {
String sOut;
if (Messages.isInitialized()) {
sOut = "(" + code + ") " + Messages.getErrorMessage(code);
} else {
sOut = "(" + code + ") ";
}
// Just make a print stake trace if Log is not yet enabled (example:
// collection commit problem in initialCheckups)
if (logger == null) {
System.out.println("[ERROR] " + sOut);
return;
}
spool("<font color='red'>[ERROR] " + sOut + FONT_END);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, sOut, null);
}
/**
* Log an error-level message.
*
* @param t the exception itself
*/
public static synchronized void error(Throwable t) {
// Just make a print stake trace if Log is not yet enabled (example:
// collection commit problem in initialCheckups)
if (logger == null) {
stack(t);
return;
}
spool(t);
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, t.getMessage() + " / " + t.getCause(), t);
}
/**
* Log an error-level message.
*
* @param code
* @param t
*/
public static void error(int code, Throwable t) {
error(code, null, t);
}
/**
* Log an error-level message.
*
* @param sInfosup
* @param je
*/
public static void error(String sInfosup, JajukException je) {
error(je.getCode(), sInfosup, je);
}
/**
* Log an error-level message.
*
* @param je
*/
public static void error(JajukException je) {
error(je.getCode(), null, je);
}
/**
* Log a fatal error message.
*
* @param s
*/
public static synchronized void fatal(String s) {
// Just make a print stake trace if Log is not yet enabled (example:
// collection commit problem in initialCheckups)
if (logger == null) {
System.out.println("[FATAL] " + s);
return;
}
spool("<font color='red'><b>[FATAL] " + s + "</b></font>");
logger.log(FULL_QUALIFIED_CLASS_NAME, Level.FATAL, s, null);
}
/**
* Returns the verbosity.
*
* @return int
*/
public static int getVerbosity() {
return verbosity;
}
/**
* Sets the verbosity.
*
* @param newVerbosity
*/
public static void setVerbosity(int newVerbosity) {
verbosity = newVerbosity;
switch (newVerbosity) {
case DEBUG:
logger.setLevel(Level.DEBUG);
Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN);
Logger.getRootLogger().setLevel(Level.WARN);
break;
case INFO:
logger.setLevel(Level.INFO);
Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN);
Logger.getRootLogger().setLevel(Level.WARN);
break;
case WARNING:
logger.setLevel(Level.WARN);
Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN);
Logger.getRootLogger().setLevel(Level.WARN);
break;
case ERROR:
logger.setLevel(Level.ERROR);
Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.ERROR);
Logger.getRootLogger().setLevel(Level.ERROR);
break;
case FATAL:
logger.setLevel(Level.FATAL);
Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.FATAL);
Logger.getRootLogger().setLevel(Level.FATAL);
break;
}
}
/**
* Convenient method to display stacks properly.
*
* @param e
*/
public static void stack(Throwable e) {
e.printStackTrace();
}
/**
* Return whether Log are in debug mode.
*
* @return true, if checks if is debug enabled
*/
public static boolean isDebugEnabled() {
if (verbosity == Log.DEBUG) {
return true;
}
return false;
}
/**
* Add this message in the memory spool.
*
* @param message
*/
private synchronized static void spool(String message) {
spoolWithAnonymization(message);
spoolInClear(message);
}
private static void spoolWithAnonymization(String message) {
if (spoolAnonymized.size() >= Const.FEEDBACK_LINES) {
spoolAnonymized.remove(0);
}
String anonymizedMessage = anonymize(message);
spoolAnonymized.add(anonymizedMessage);
}
private static void spoolInClear(String message) {
if (spoolClear.size() >= Const.FEEDBACK_LINES) {
spoolClear.remove(0);
}
spoolClear.add(message);
}
/**
* Anonymize a string by replacing strings between braces by stars
* @param sMessage the string to anonymise
* @return anonymized string
*/
private static String anonymize(String sMessage) {
// anonymize standard labels (with {{xxx}})
String sAnonymizedMessage = sMessage.replaceAll("\\{\\{.*\\}\\}", "***");
// additionally anonymize Basic Player logs
int pos = sAnonymizedMessage.indexOf("Player state changed: OPENING");
if (pos != -1) {
// cut away trailing stuff which is personal data
sAnonymizedMessage = sAnonymizedMessage.substring(0, pos + 40);
}
return sAnonymizedMessage;
}
/**
* Spool an exception with stack traces.
*
* @param e
*/
private static void spool(Throwable e) {
spool("<font color='red'>" + "[ERROR] " + e.getClass() + " / {{" + e.getMessage() + "}} / "
+ e.getCause());
StackTraceElement[] ste = e.getStackTrace();
for (StackTraceElement element : ste) {
spool(element.toString());
}
spool(FONT_END);
}
/**
* Gets the spool.
*
* @return Spool traces
*/
@SuppressWarnings("unchecked")
public static List<String> getSpool(boolean anonymized) {
if (anonymized) {
return (List<String>) ((ArrayList<String>) spoolAnonymized).clone();
} else {
return (List<String>) ((ArrayList<String>) spoolClear).clone();
}
}
}