/* * 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(); } } }