/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.slee.runtime.facilities; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import javax.slee.InvalidArgumentException; import javax.slee.facilities.FacilityException; import javax.slee.facilities.TraceLevel; import javax.slee.facilities.Tracer; import javax.slee.management.NotificationSource; import javax.slee.management.TraceNotification; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.mobicents.slee.container.management.jmx.TraceMBeanImpl; /** * * Start time:21:04:04 2009-03-09<br> * Project: restcomm-jainslee-server-core<br> * Implementation of Tracer object that allows slee comopnents to send * notification on some interesting ocasions. * * @author <a href="mailto:baranowb@gmail.com">baranowb - Bartosz Baranowski</a> * @author martins */ public class TracerImpl implements Tracer { public static final TraceLevel DEFAULT_TRACE_LEVEL = TraceLevel.INFO; public final static String ROOT_TRACER_NAME = ""; private TraceLevel level; private final Logger logger; private final NotificationSourceWrapperImpl notificationSource; private final TraceMBeanImpl traceMBean; private final String name; private final TracerImpl parent; private boolean requestedBySource = false; private boolean configEnabled = false; private boolean infoEnabled = false; private boolean fineEnabled = false; private boolean finerEnabled = false; private boolean finestEnabled = false; private boolean warningEnabled = false; private boolean severeEnabled = false; private final ConcurrentLinkedQueue<TracerImpl> childs = new ConcurrentLinkedQueue<TracerImpl>(); /** * */ public TracerImpl(String name, TracerImpl parent, NotificationSourceWrapperImpl notificationSource, TraceMBeanImpl traceMBean) { this.name = name; this.parent = parent; if (parent != null) { parent.childs.add(this); } this.logger = Logger.getLogger(tracerNameToLog4JLoggerName(name, notificationSource.getNotificationSource())); this.notificationSource = notificationSource; this.traceMBean = traceMBean; syncLevelWithLog4j(); } /** * Generates the log4j logger name for the tracer with specified named and notification source. * * @param tracerName * @param notificationSource * @return */ private String tracerNameToLog4JLoggerName(String tracerName, NotificationSource notificationSource) { final StringBuilder sb = new StringBuilder("javax.slee.").append(notificationSource.toString()); if(!tracerName.equals(ROOT_TRACER_NAME)) { sb.append('.').append(tracerName); } return sb.toString(); } /** * syncs the slee tracer level with the one that related logger has in log4j */ void syncLevelWithLog4j() { // get the level from log4j, only the root one uses effective level Level log4jLevel = parent == null ? logger.getEffectiveLevel() : logger.getLevel(); if (level == null) { // set the level assignLog4JLevel(log4jLevel); } else { // set the level only if differs, otherwise we may loose levels not present in log4j if (tracerToLog4JLevel(level) != log4jLevel) { assignLog4JLevel(log4jLevel); } } // the root must always have a level if (parent == null && level == null) { // defaults to INFO logger.setLevel(Level.INFO); level = TraceLevel.INFO; } // reset the flags resetCacheFlags(false); } /** * assigns the equiv log4j level to the tracer * @param log4jLevel */ private void assignLog4JLevel(Level log4jLevel) { if (log4jLevel == null) { return; } if (log4jLevel == Level.DEBUG) { level = TraceLevel.FINE; } else if (log4jLevel == Level.INFO) { level = TraceLevel.INFO; } else if (log4jLevel == Level.WARN) { level = TraceLevel.WARNING; } else if (log4jLevel == Level.ERROR) { level = TraceLevel.SEVERE; } else if (log4jLevel == Level.TRACE) { level = TraceLevel.FINEST; } else if (log4jLevel == Level.OFF) { level = TraceLevel.OFF; } } /** * manages the flags which cache if levels are enabled */ void resetCacheFlags(boolean resetChilds) { if (isTraceable(TraceLevel.FINEST)) { finestEnabled = true; finerEnabled = true; fineEnabled = true; configEnabled = true; infoEnabled = true; warningEnabled = true; severeEnabled = true; } else { finestEnabled = false; if (isTraceable(TraceLevel.FINER)) { finerEnabled = true; fineEnabled = true; configEnabled = true; infoEnabled = true; warningEnabled = true; severeEnabled = true; } else { finerEnabled = false; if (isTraceable(TraceLevel.FINE)) { fineEnabled = true; configEnabled = true; infoEnabled = true; warningEnabled = true; severeEnabled = true; } else { fineEnabled = false; if (isTraceable(TraceLevel.CONFIG)) { configEnabled = true; infoEnabled = true; warningEnabled = true; severeEnabled = true; } else { if (isTraceable(TraceLevel.INFO)) { infoEnabled = true; warningEnabled = true; severeEnabled = true; } else { infoEnabled = false; if (isTraceable(TraceLevel.WARNING)) { warningEnabled = true; severeEnabled = true; } else { warningEnabled = false; if (isTraceable(TraceLevel.SEVERE)) { severeEnabled = true; } else { severeEnabled = false; } } } } } } } if (resetChilds) { // implicit change of level demands that we update reset flags on childs without level for(TracerImpl child : childs) { if (child.level == null) { child.resetCacheFlags(true); } } } } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#config(java.lang.String) */ public void config(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.CONFIG, message, null); logger.info(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#config(java.lang.String, java.lang.Throwable) */ public void config(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.CONFIG, message, t); logger.info(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#fine(java.lang.String) */ public void fine(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINE, message, null); logger.debug(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#fine(java.lang.String, java.lang.Throwable) */ public void fine(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINE, message, t); logger.debug(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#finer(java.lang.String) */ public void finer(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINER, message, null); logger.debug(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#finer(java.lang.String, java.lang.Throwable) */ public void finer(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINER, message, t); logger.debug(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#finest(java.lang.String) */ public void finest(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINEST, message, null); logger.trace(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#finest(java.lang.String, java.lang.Throwable) */ public void finest(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.FINEST, message, t); logger.trace(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#getParentTracerName() */ public String getParentTracerName() { return parent == null ? null : parent.getTracerName(); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#getTraceLevel() */ public TraceLevel getTraceLevel() throws FacilityException { return level != null ? level : parent.getTraceLevel(); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#getTracerName() */ public String getTracerName() { return name; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#info(java.lang.String) */ public void info(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.INFO, message, null); logger.info(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#info(java.lang.String, java.lang.Throwable) */ public void info(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.INFO, message, t); logger.info(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isConfigEnabled() */ public boolean isConfigEnabled() throws FacilityException { return configEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isFineEnabled() */ public boolean isFineEnabled() throws FacilityException { return fineEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isFinerEnabled() */ public boolean isFinerEnabled() throws FacilityException { return finerEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isFinestEnabled() */ public boolean isFinestEnabled() throws FacilityException { return finestEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isInfoEnabled() */ public boolean isInfoEnabled() throws FacilityException { return infoEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isSevereEnabled() */ public boolean isSevereEnabled() throws FacilityException { return severeEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isTraceable(javax.slee.facilities.TraceLevel) */ public boolean isTraceable(TraceLevel traceLevel) throws NullPointerException, FacilityException { return !getTraceLevel().isHigherLevel(traceLevel); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#isWarningEnabled() */ public boolean isWarningEnabled() throws FacilityException { return warningEnabled; } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#severe(java.lang.String) */ public void severe(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.SEVERE, message, null); logger.error(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#severe(java.lang.String, java.lang.Throwable) */ public void severe(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.SEVERE, message, t); logger.error(message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#trace(javax.slee.facilities.TraceLevel, java.lang.String) */ public void trace(TraceLevel traceLevel, String message) throws NullPointerException, IllegalArgumentException, FacilityException { sendNotification(traceLevel, message, null); logger.log(tracerToLog4JLevel(traceLevel), message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#trace(javax.slee.facilities.TraceLevel, java.lang.String, java.lang.Throwable) */ public void trace(TraceLevel traceLevel, String message, Throwable t) throws NullPointerException, IllegalArgumentException, FacilityException { sendNotification(traceLevel, message, t); logger.log(tracerToLog4JLevel(traceLevel), message,t); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#warning(java.lang.String) */ public void warning(String message) throws NullPointerException, FacilityException { sendNotification(TraceLevel.WARNING, message, null); logger.warn(message); } /* (non-Javadoc) * @see javax.slee.facilities.Tracer#warning(java.lang.String, java.lang.Throwable) */ public void warning(String message, Throwable t) throws NullPointerException, FacilityException { sendNotification(TraceLevel.WARNING, message, t); logger.warn(message,t); } /** * THis is internaly called, by 1.1 tracers * * @param src */ void sendNotification(javax.slee.facilities.TraceLevel level, String message, Throwable t) { if (!isTraceable(level)) { return; } traceMBean.sendNotification(new TraceNotification(notificationSource.getNotificationSource().getTraceNotificationType(), traceMBean, notificationSource.getNotificationSource(), getTracerName(), level, message, t, notificationSource.getNextSequence(), System.currentTimeMillis())); } /** * This checks if the specified tracer name is ok. * * @param tracerName * @param notificationSource * @throws InvalidArgumentException */ public static void checkTracerName(String tracerName, NotificationSource notificationSource) throws NullPointerException,InvalidArgumentException { if (tracerName.equals("")) { // This is root return; } StringTokenizer stringTokenizer = new StringTokenizer(tracerName, ".", true); String lastToken = null; while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); if (lastToken == null) { // this is start lastToken = token; } if (lastToken.equals(token) && token.equals(".")) { throw new InvalidArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal"); } lastToken = token; } if (lastToken.equals(".")) { throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal"); } } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Tracer{ notificationSource = "+notificationSource.getNotificationSource()+" , name = "+getTracerName()+" , parent = "+getParentTracerName()+" , level = "+getTraceLevel()+" }"; } private Level tracerToLog4JLevel(TraceLevel traceLevel) { if (traceLevel.isFine() || traceLevel.isFiner()) { return Level.DEBUG; } if (traceLevel.isInfo() || traceLevel.isConfig()) { return Level.INFO; } if (traceLevel.isFinest()) { return Level.TRACE; } if(traceLevel.isWarning()) { return Level.WARN; } if(traceLevel.isSevere()) { return Level.ERROR; } if(traceLevel.isOff()) { return Level.OFF; } return Level.INFO; } /** * @param level */ public void setTraceLevel(TraceLevel level) { this.level = level; logger.setLevel(tracerToLog4JLevel(level)); resetCacheFlags(true); } public void unsetTraceLevel() { this.level = null; logger.setLevel(null); resetCacheFlags(true); } /** * @return */ public boolean isExplicitlySetTracerLevel() { return level != null; } /** * Sets * @param requestedBySource the requestedBySource to set */ public void setRequestedBySource(boolean requestedBySource) { this.requestedBySource = requestedBySource; } /** * Retrieves * @return the requestedBySource */ public boolean isRequestedBySource() { return requestedBySource; } }