View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2002, 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.sift;
15  
16  import ch.qos.logback.core.Appender;
17  import ch.qos.logback.core.AppenderBase;
18  import ch.qos.logback.core.model.SiftModel;
19  import ch.qos.logback.core.util.Duration;
20  
21  /**
22   * This appender serves as the base class for actual SiftingAppenders
23   * implemented by the logback-classic and logback-access modules. In a nutshell,
24   * a SiftingAppender contains other appenders which it can build dynamically
25   * depending on discriminating values supplied by the event currently being
26   * processed. The appender to build (dynamically) is specified as part of a
27   * configuration file.
28   *
29   * @author Ceki Gülcü
30   */
31  public abstract class SiftingAppenderBase<E> extends AppenderBase<E> {
32  
33      protected AppenderTracker<E> appenderTracker;
34      AppenderFactory<E> appenderFactory;
35      Duration timeout = new Duration(AppenderTracker.DEFAULT_TIMEOUT);
36      int maxAppenderCount = AppenderTracker.DEFAULT_MAX_COMPONENTS;
37  
38      SiftModel siftModel;
39      Discriminator<E> discriminator;
40  
41      public Duration getTimeout() {
42          return timeout;
43      }
44  
45      public void setTimeout(Duration timeout) {
46          this.timeout = timeout;
47      }
48  
49      public SiftModel getSiftModel() {
50          return siftModel;
51      }
52  
53      public void setSiftModel(SiftModel siftModel) {
54          this.siftModel = siftModel;
55      }
56      
57      public int getMaxAppenderCount() {
58          return maxAppenderCount;
59      }
60  
61      public void setMaxAppenderCount(int maxAppenderCount) {
62          this.maxAppenderCount = maxAppenderCount;
63      }
64  
65      /**
66       * This setter is intended to be invoked by SiftModelHandler. Users have no 
67       * reason to invoke this method directly.
68       */
69      public void setAppenderFactory(AppenderFactory<E> appenderFactory) {
70          this.appenderFactory = appenderFactory;
71      }
72  
73      @Override
74      public void start() {
75          int errors = 0;
76          if (discriminator == null) {
77              addError("Missing discriminator. Aborting");
78              errors++;
79          }
80          if (!discriminator.isStarted()) {
81              addError("Discriminator has not started successfully. Aborting");
82              errors++;
83          }
84          if (appenderFactory == null) {
85              addError("AppenderFactory has not been set. Aborting");
86              errors++;
87          } else {
88              appenderTracker = new AppenderTracker<E>(context, appenderFactory);
89              appenderTracker.setMaxComponents(maxAppenderCount);
90              appenderTracker.setTimeout(timeout.getMilliseconds());
91          }
92          if (errors == 0) {
93              super.start();
94          }
95      }
96  
97      @Override
98      public void stop() {
99          if(!isStarted())
100             return;
101         for (Appender<E> appender : appenderTracker.allComponents()) {
102             appender.stop();
103         }
104     }
105 
106     abstract protected long getTimestamp(E event);
107 
108     @Override
109     protected void append(E event) {
110         if (!isStarted()) {
111             return;
112         }
113         String discriminatingValue = discriminator.getDiscriminatingValue(event);
114         long timestamp = getTimestamp(event);
115 
116         Appender<E> appender = appenderTracker.getOrCreate(discriminatingValue, timestamp);
117         // marks the appender for removal as specified by the user
118         if (eventMarksEndOfLife(event)) {
119             appenderTracker.endOfLife(discriminatingValue);
120         }
121         appenderTracker.removeStaleComponents(timestamp);
122         appender.doAppend(event);
123     }
124 
125     protected abstract boolean eventMarksEndOfLife(E event);
126 
127     public Discriminator<E> getDiscriminator() {
128         return discriminator;
129     }
130 
131     public void setDiscriminator(Discriminator<E> discriminator) {
132         this.discriminator = discriminator;
133     }
134 
135     // sometimes one needs to close a nested appender immediately
136     // for example when executing a command which has its own nested appender
137     // and the command also cleans up after itself. However, an open file appender
138     // will prevent the folder from being deleted
139     // see http://www.qos.ch/pipermail/logback-user/2010-March/001487.html
140 
141     /**
142      * @since 0.9.19
143      */
144     public AppenderTracker<E> getAppenderTracker() {
145         return appenderTracker;
146     }
147 
148     public String getDiscriminatorKey() {
149         if (discriminator != null) {
150             return discriminator.getKey();
151         } else {
152             return null;
153         }
154     }
155 }