View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, 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 Appender<E> {
32  
33      protected boolean started = false;
34  
35      // using a ThreadLocal instead of a boolean add 75 nanoseconds per
36      // doAppend invocation. This is tolerable as doAppend takes at least a few microseconds
37      // on a real appender
38      /**
39       * The guard prevents an appender from repeatedly calling its own doAppend
40       * method.
41       */
42      private ThreadLocal<Boolean> guard = new ThreadLocal<Boolean>();
43  
44      /**
45       * Appenders are named.
46       */
47      protected String name;
48  
49      private FilterAttachableImpl<E> fai = new FilterAttachableImpl<E>();
50  
51      public String getName() {
52          return name;
53      }
54  
55      private int statusRepeatCount = 0;
56      private int exceptionCount = 0;
57  
58      static final int ALLOWED_REPEATS = 3;
59  
60      public void doAppend(E eventObject) {
61          // WARNING: The guard check MUST be the first statement in the
62          // doAppend() method.
63  
64          // prevent re-entry.
65          if (Boolean.TRUE.equals(guard.get())) {
66              return;
67          }
68  
69          try {
70              guard.set(Boolean.TRUE);
71  
72              if (!this.started) {
73                  if (statusRepeatCount++ < ALLOWED_REPEATS) {
74                      addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
75                  }
76                  return;
77              }
78  
79              if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
80                  return;
81              }
82  
83              // ok, we now invoke derived class' implementation of append
84              this.append(eventObject);
85  
86          } catch (Exception e) {
87              if (exceptionCount++ < ALLOWED_REPEATS) {
88                  addError("Appender [" + name + "] failed to append.", e);
89              }
90          } finally {
91              guard.set(Boolean.FALSE);
92          }
93      }
94  
95      abstract protected void append(E eventObject);
96  
97      /**
98       * Set the name of this appender.
99       */
100     public void setName(String name) {
101         this.name = name;
102     }
103 
104     public void start() {
105         started = true;
106     }
107 
108     public void stop() {
109         started = false;
110     }
111 
112     public boolean isStarted() {
113         return started;
114     }
115 
116     public String toString() {
117         return this.getClass().getName() + "[" + name + "]";
118     }
119 
120     public void addFilter(Filter<E> newFilter) {
121         fai.addFilter(newFilter);
122     }
123 
124     public void clearAllFilters() {
125         fai.clearAllFilters();
126     }
127 
128     public List<Filter<E>> getCopyOfAttachedFiltersList() {
129         return fai.getCopyOfAttachedFiltersList();
130     }
131 
132     public FilterReply getFilterChainDecision(E event) {
133         return fai.getFilterChainDecision(event);
134     }
135 }