View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core;
15  
16  import java.util.List;
17  
18  import ch.qos.logback.core.filter.Filter;
19  import ch.qos.logback.core.spi.ContextAwareBase;
20  import ch.qos.logback.core.spi.FilterAttachableImpl;
21  import ch.qos.logback.core.spi.FilterReply;
22  import ch.qos.logback.core.status.WarnStatus;
23  
24  /**
25   * Similar to AppenderBase except that derived appenders need to handle 
26   * thread synchronization on their own.
27   * 
28   * @author Ceki Gülcü
29   * @author Ralph Goers
30   */
31  abstract public class UnsynchronizedAppenderBase<E> extends ContextAwareBase implements
32      Appender<E> {
33  
34    protected boolean started = false;
35  
36    // using a ThreadLocal instead of a boolean add 75 nanoseconds per
37    // doAppend invocation. This is tolerable as doAppend takes at least a few microseconds
38    // on a real appender
39    /**
40     * The guard prevents an appender from repeatedly calling its own doAppend
41     * method.
42     */
43    private ThreadLocal<Boolean> guard = new ThreadLocal<Boolean>();
44  
45  
46    /**
47     * Appenders are named.
48     */
49    protected String name;
50  
51    private FilterAttachableImpl<E> fai = new FilterAttachableImpl<E>();
52  
53    public String getName() {
54      return name;
55    }
56  
57    private int statusRepeatCount = 0;
58    private int exceptionCount = 0;
59  
60    static final int ALLOWED_REPEATS = 3;
61  
62    public void doAppend(E eventObject) {
63      // WARNING: The guard check MUST be the first statement in the
64      // doAppend() method.
65        
66      // prevent re-entry.
67      if (Boolean.TRUE.equals(guard.get())) {
68        return;
69      }
70  
71      try {
72        guard.set(Boolean.TRUE);
73  
74        if (!this.started) {
75          if (statusRepeatCount++ < ALLOWED_REPEATS) {
76            addStatus(new WarnStatus(
77                "Attempted to append to non started appender [" + name + "].",
78                this));
79          }
80          return;
81        }
82  
83        if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
84          return;
85        }
86  
87        // ok, we now invoke derived class' implementation of append
88        this.append(eventObject);
89  
90      } catch (Exception e) {
91        if (exceptionCount++ < ALLOWED_REPEATS) {
92          addError("Appender [" + name + "] failed to append.", e);
93        }
94      } finally {
95        guard.set(Boolean.FALSE);
96      }
97    }
98  
99    abstract protected void append(E eventObject);
100 
101   /**
102    * Set the name of this appender.
103    */
104   public void setName(String name) {
105     this.name = name;
106   }
107 
108   public void start() {
109     started = true;
110   }
111 
112   public void stop() {
113     started = false;
114   }
115 
116   public boolean isStarted() {
117     return started;
118   }
119 
120   public String toString() {
121     return this.getClass().getName() + "[" + name + "]";
122   }
123 
124   public void addFilter(Filter<E> newFilter) {
125     fai.addFilter(newFilter);
126   }
127 
128   public void clearAllFilters() {
129     fai.clearAllFilters();
130   }
131 
132   public List<Filter<E>> getCopyOfAttachedFiltersList() {
133     return fai.getCopyOfAttachedFiltersList();
134   }
135 
136   public FilterReply getFilterChainDecision(E event) {
137     return fai.getFilterChainDecision(event);
138   }
139 }