001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic;
015
016import java.util.ArrayList;
017import java.util.HashMap;
018import java.util.Iterator;
019import java.util.Map;
020
021import org.slf4j.helpers.MarkerIgnoringBase;
022
023import ch.qos.logback.classic.spi.ILoggingEvent;
024import ch.qos.logback.core.Appender;
025import ch.qos.logback.core.CoreConstants;
026
027public class HLogger extends MarkerIgnoringBase {
028
029    private static final long serialVersionUID = 1L;
030
031    static int instanceCount = 0;
032
033    /**
034     * The name of this logger
035     */
036    private String name;
037
038    // The assigned levelInt of this logger. Can be null.
039    private Level level;
040
041    // The effective levelInt is the assigned levelInt and if null, a levelInt is
042    // inherited form a parent.
043    private Level effectiveLevel;
044
045    /**
046     * The parent of this category. All categories have at least one ancestor
047     * which is the root category.
048     */
049    HLogger parent;
050
051    /**
052     * The children of this logger. A logger may have zero or more children.
053     */
054    Map<String, HLogger> childrenMap;
055
056    /**
057     * Array of appenders.
058     */
059    private ArrayList<Appender<ILoggingEvent>> appenderList;
060
061    /**
062     * Additivity is set to true by default, that is children inherit the
063     * appenders of their ancestors by default. If this variable is set to
064     * <code>false</code> then the appenders located in the ancestors of this
065     * logger will not be used. However, the children of this logger will inherit
066     * its appenders, unless the children have their additivity flag set to
067     * <code>false</code> too. See the user manual for more details.
068     */
069    protected boolean additive = true;
070
071    HLogger(String name, HLogger parent) {
072        this.name = name;
073        this.parent = parent;
074        instanceCount++;
075    }
076
077    Level getEffectiveLevel() {
078        return effectiveLevel;
079    }
080
081    Level getLevel() {
082        return level;
083    }
084
085    public String getName() {
086        return name;
087    }
088
089    private boolean isRootLogger() {
090        // only the root logger has a null parent
091        return parent == null;
092    }
093
094    /**
095     * Get a child by its suffix.
096     * 
097     * <p>
098     * IMPORTANT: Calls to this method must be within a syncronized block on this
099     * logger!
100     * 
101     * @param suffix
102     * @return
103     */
104    HLogger getChildBySuffix(final String suffix) {
105        if (childrenMap == null) {
106            return null;
107        } else {
108            return (HLogger) childrenMap.get(suffix);
109        }
110    }
111
112    public synchronized void setLevel(Level newLevel) {
113        if (level == newLevel) {
114            // nothing to do;
115            return;
116        }
117
118        level = newLevel;
119        effectiveLevel = newLevel;
120        if (childrenMap != null) {
121            for (Iterator<HLogger> i = childrenMap.values().iterator(); i.hasNext();) {
122                HLogger child = (HLogger) i.next();
123
124                // tell child to handle parent levelInt change
125                child.handleParentLevelChange(effectiveLevel);
126            }
127        }
128    }
129
130    /**
131     * This method is invoked by parent logger to let this logger know that the
132     * prent's levelInt changed.
133     * 
134     * @param newParentLevel
135     */
136    private synchronized void handleParentLevelChange(Level newParentLevel) {
137        // changes in the parent levelInt affect children only if their levelInt is
138        // null
139        if (level == null) {
140            effectiveLevel = newParentLevel;
141
142            // propagate the parent levelInt change to this logger's children
143            if (childrenMap != null) {
144                for (Iterator<HLogger> i = childrenMap.values().iterator(); i.hasNext();) {
145                    HLogger child = (HLogger) i.next();
146                    // tell child to handle parent levelInt change
147                    child.handleParentLevelChange(effectiveLevel);
148                }
149            }
150        }
151    }
152
153    /**
154     * Remove all previously added appenders from this logger instance. <p/> This
155     * is useful when re-reading configuration information.
156     */
157    public synchronized void removeAllAppenders() {
158        if (appenderList != null) {
159            int len = appenderList.size();
160            for (int i = 0; i < len; i++) {
161                Appender<ILoggingEvent> a = appenderList.get(i);
162                a.stop();
163            }
164            appenderList.clear();
165            appenderList = null;
166        }
167    }
168
169    /**
170     * Invoke all the appenders of this logger.
171     * 
172     * @param event
173     *          The event to log
174     */
175    public void callAppenders(ILoggingEvent event) {
176        ///int writes = 0;
177
178        for (HLogger l = this; l != null; l = l.parent) {
179            // Protected against simultaneous call to addAppender, removeAppender,...
180            synchronized (l) {
181                if (l.appenderList != null) {
182                    l.appendLoopOnAppenders(event);
183                }
184                if (!l.additive) {
185                    break;
186                }
187            }
188        }
189
190        // No appenders in hierarchy, warn user only once.
191        // if(!hierarchy.emittedNoAppenderWarning && writes == 0) {
192        // LogLog.error("No appenders could be found for category (" +
193        // this.getName() + ").");
194        // LogLog.error("Please initialize the log4j system properly.");
195        // hierarchy.emittedNoAppenderWarning = true;
196        // }
197    }
198
199    private int appendLoopOnAppenders(ILoggingEvent event) {
200        int size = 0;
201        Appender<ILoggingEvent> appender;
202
203        if (appenderList != null) {
204            size = appenderList.size();
205            for (int i = 0; i < size; i++) {
206                appender = appenderList.get(i);
207                appender.doAppend(event);
208            }
209        }
210        return size;
211    }
212
213    /**
214     * Remove the appender passed as parameter form the list of appenders.
215     */
216    public synchronized void removeAppender(Appender<ILoggingEvent> appender) {
217        if ((appender == null) || (appenderList == null)) {
218        }
219        appenderList.remove(appender);
220    }
221
222    /**
223     * Create a child of this logger by suffix, that is, the part of the name
224     * extending this logger. For example, if this logger is named "x.y" and the
225     * lastPart is "z", then the created child logger will be named "x.y.z".
226     * 
227     * <p>
228     * IMPORTANT: Calls to this method must be within a syncronized block on this
229     * logger.
230     * 
231     * @param lastPart
232     *          the suffix (i.e. last part) of the child logger name. This
233     *          parameter may not include dots, i.e. the logger separator
234     *          character.
235     * @return
236     */
237    HLogger createChildByLastNamePart(final String lastPart) {
238        int i_index = lastPart.indexOf(CoreConstants.DOT);
239        if (i_index != -1) {
240            throw new IllegalArgumentException("Child name [" + lastPart + " passed as parameter, may not include [" + CoreConstants.DOT + "]");
241        }
242
243        if (childrenMap == null) {
244            childrenMap = new HashMap<String, HLogger>(2);
245        }
246        HLogger childHLogger;
247        if (this.isRootLogger()) {
248            childHLogger = new HLogger(lastPart, this);
249        } else {
250            childHLogger = new HLogger(name + CoreConstants.DOT + lastPart, this);
251        }
252        childrenMap.put(lastPart, childHLogger);
253        childHLogger.effectiveLevel = this.effectiveLevel;
254        return childHLogger;
255    }
256
257    public final void trace(String msg) {
258        if (effectiveLevel.levelInt <= Level.TRACE_INT) {
259            throw new UnsupportedOperationException("not yet implemented");
260        }
261    }
262
263    public void trace(String msg, Throwable t) {
264        // To change body of implemented methods use File | Settings | File
265        // Templates.
266    }
267
268    public void trace(Object parameterizedMsg, Object param1) {
269        // To change body of implemented methods use File | Settings | File
270        // Templates.
271    }
272
273    public void trace(String parameterizedMsg, Object param1, Object param2) {
274        // To change body of implemented methods use File | Settings | File
275        // Templates.
276    }
277
278    public final void debug(String msg) {
279        if (effectiveLevel.levelInt <= Level.DEBUG_INT) {
280            throw new UnsupportedOperationException("not yet implemented");
281        }
282    }
283
284    public void debug(String msg, Throwable t) {
285        // To change body of implemented methods use File | Settings | File
286        // Templates.
287    }
288
289    public void debug(Object parameterizedMsg, Object param1) {
290        // To change body of implemented methods use File | Settings | File
291        // Templates.
292    }
293
294    public void debug(String parameterizedMsg, Object param1, Object param2) {
295        // To change body of implemented methods use File | Settings | File
296        // Templates.
297    }
298
299    public void error(String msg) {
300        // To change body of implemented methods use File | Settings | File
301        // Templates.
302    }
303
304    public void error(String msg, Throwable t) {
305        // To change body of implemented methods use File | Settings | File
306        // Templates.
307    }
308
309    public void error(String parameterizedMsg, Object param1) {
310        // To change body of implemented methods use File | Settings | File
311        // Templates.
312    }
313
314    public void error(String parameterizedMsg, Object param1, Object param2) {
315        // To change body of implemented methods use File | Settings | File
316        // Templates.
317    }
318
319    public void info(String msg) {
320        // To change body of implemented methods use File | Settings | File
321        // Templates.
322    }
323
324    public void info(String msg, Throwable t) {
325        // To change body of implemented methods use File | Settings | File
326        // Templates.
327    }
328
329    public void info(String parameterizedMsg, Object param1) {
330        // To change body of implemented methods use File | Settings | File
331        // Templates.
332    }
333
334    public void info(String parameterizedMsg, Object param1, Object param2) {
335        // To change body of implemented methods use File | Settings | File
336        // Templates.
337    }
338
339    public boolean isTraceEnabled() {
340        return false;
341    }
342
343    public boolean isDebugEnabled() {
344        return false;
345    }
346
347    public boolean isErrorEnabled() {
348        return false; // To change body of implemented methods use File | Settings |
349        // File Templates.
350    }
351
352    public boolean isInfoEnabled() {
353        return false; // To change body of implemented methods use File | Settings |
354        // File Templates.
355    }
356
357    public boolean isWarnEnabled() {
358        return false; // To change body of implemented methods use File | Settings |
359        // File Templates.
360    }
361
362    public void warn(String msg) {
363        // To change body of implemented methods use File | Settings | File
364        // Templates.
365    }
366
367    public void warn(String msg, Throwable t) {
368        // To change body of implemented methods use File | Settings | File
369        // Templates.
370    }
371
372    public void warn(String parameterizedMsg, Object param1) {
373        // To change body of implemented methods use File | Settings | File
374        // Templates.
375    }
376
377    public void warn(String parameterizedMsg, Object param1, Object param2) {
378        // To change body of implemented methods use File | Settings | File
379        // Templates.
380    }
381
382    public void trace(String format, Object arg) {
383    }
384
385    public void trace(String format, Object... argArray) {
386    }
387
388    public void debug(String format, Object arg) {
389    }
390
391    public void debug(String format, Object... argArray) {
392    }
393
394    public void info(String format, Object... argArray) {
395    }
396
397    public void warn(String format, Object... argArray) {
398    }
399
400    public void error(String format, Object... argArray) {
401    }
402}