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 }
136