View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.filter;
18  
19  import java.text.ParseException;
20  import java.text.SimpleDateFormat;
21  import java.util.Calendar;
22  import java.util.TimeZone;
23  
24  import org.apache.logging.log4j.Level;
25  import org.apache.logging.log4j.Marker;
26  import org.apache.logging.log4j.core.Filter;
27  import org.apache.logging.log4j.core.LogEvent;
28  import org.apache.logging.log4j.core.Logger;
29  import org.apache.logging.log4j.core.config.Node;
30  import org.apache.logging.log4j.core.config.plugins.Plugin;
31  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
32  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33  import org.apache.logging.log4j.core.util.Clock;
34  import org.apache.logging.log4j.core.util.ClockFactory;
35  import org.apache.logging.log4j.message.Message;
36  import org.apache.logging.log4j.util.PerformanceSensitive;
37  
38  /**
39   * Filters events that fall within a specified time period in each day.
40   */
41  @Plugin(name = "TimeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
42  @PerformanceSensitive("allocation")
43  public final class TimeFilter extends AbstractFilter {
44      private static final Clock CLOCK = ClockFactory.getClock();
45  
46      /**
47       * Length of hour in milliseconds.
48       */
49      private static final long HOUR_MS = 3600000;
50  
51      /**
52       * Length of minute in milliseconds.
53       */
54      private static final long MINUTE_MS = 60000;
55  
56      /**
57       * Length of second in milliseconds.
58       */
59      private static final long SECOND_MS = 1000;
60  
61      /**
62       * Starting offset from midnight in milliseconds.
63       */
64      private final long start;
65      
66      /**
67       * Ending offset from midnight in milliseconds.
68       */
69      private final long end;
70      
71      /**
72       * Timezone.
73       */
74      private final TimeZone timeZone;
75  
76      private long midnightToday;
77      private long midnightTomorrow;
78  
79  
80      private TimeFilter(final long start, final long end, final TimeZone timeZone, final Result onMatch,
81                         final Result onMismatch) {
82          super(onMatch, onMismatch);
83          this.start = start;
84          this.end = end;
85          this.timeZone = timeZone;
86          initMidnight(start);
87      }
88  
89      /**
90       * Initializes the midnight boundaries to midnight in the specified time zone.
91       * @param now a time in milliseconds since the epoch, used to pinpoint the current date
92       */
93      void initMidnight(final long now) {
94          final Calendar calendar = Calendar.getInstance(timeZone);
95          calendar.setTimeInMillis(now);
96          calendar.set(Calendar.HOUR_OF_DAY, 0);
97          calendar.set(Calendar.MINUTE, 0);
98          calendar.set(Calendar.SECOND, 0);
99          calendar.set(Calendar.MILLISECOND, 0);
100         midnightToday = calendar.getTimeInMillis();
101 
102         calendar.add(Calendar.DATE, 1);
103         midnightTomorrow = calendar.getTimeInMillis();
104     }
105 
106     /**
107      * Package-protected for tests.
108      *
109      * @param currentTimeMillis the time to compare with the boundaries. May re-initialize the cached midnight
110      *          boundary values.
111      * @return the action to perform
112      */
113     Result filter(final long currentTimeMillis) {
114         if (currentTimeMillis >= midnightTomorrow || currentTimeMillis < midnightToday) {
115             initMidnight(currentTimeMillis);
116         }
117         return currentTimeMillis >= midnightToday + start && currentTimeMillis <= midnightToday + end //
118                 ? onMatch // within window
119                 : onMismatch;
120     }
121 
122     @Override
123     public Result filter(final LogEvent event) {
124         return filter(event.getTimeMillis());
125     }
126 
127     private Result filter() {
128         return filter(CLOCK.currentTimeMillis());
129     }
130 
131     @Override
132     public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
133             final Throwable t) {
134         return filter();
135     }
136 
137     @Override
138     public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
139             final Throwable t) {
140         return filter();
141     }
142 
143     @Override
144     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
145             final Object... params) {
146         return filter();
147     }
148 
149     @Override
150     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
151             final Object p0) {
152         return filter();
153     }
154 
155     @Override
156     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
157             final Object p0, final Object p1) {
158         return filter();
159     }
160 
161     @Override
162     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
163             final Object p0, final Object p1, final Object p2) {
164         return filter();
165     }
166 
167     @Override
168     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
169             final Object p0, final Object p1, final Object p2, final Object p3) {
170         return filter();
171     }
172 
173     @Override
174     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
175             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4) {
176         return filter();
177     }
178 
179     @Override
180     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
181             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5) {
182         return filter();
183     }
184 
185     @Override
186     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
187             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
188             final Object p6) {
189         return filter();
190     }
191 
192     @Override
193     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
194             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
195             final Object p6, final Object p7) {
196         return filter();
197     }
198 
199     @Override
200     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
201             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
202             final Object p6, final Object p7, final Object p8) {
203         return filter();
204     }
205 
206     @Override
207     public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
208             final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
209             final Object p6, final Object p7, final Object p8, final Object p9) {
210         return filter();
211     }
212 
213     @Override
214     public String toString() {
215         final StringBuilder sb = new StringBuilder();
216         sb.append("start=").append(start);
217         sb.append(", end=").append(end);
218         sb.append(", timezone=").append(timeZone.toString());
219         return sb.toString();
220     }
221 
222     /**
223      * Creates a TimeFilter.
224      * @param start The start time.
225      * @param end The end time.
226      * @param tz timezone.
227      * @param match Action to perform if the time matches.
228      * @param mismatch Action to perform if the action does not match.
229      * @return A TimeFilter.
230      */
231     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
232     @PluginFactory
233     public static TimeFilter createFilter(
234             @PluginAttribute("start") final String start,
235             @PluginAttribute("end") final String end,
236             @PluginAttribute("timezone") final String tz,
237             @PluginAttribute("onMatch") final Result match,
238             @PluginAttribute("onMismatch") final Result mismatch) {
239         final long s = parseTimestamp(start, 0);
240         final long e = parseTimestamp(end, Long.MAX_VALUE);
241         final TimeZone timeZone = tz == null ? TimeZone.getDefault() : TimeZone.getTimeZone(tz);
242         final Result onMatch = match == null ? Result.NEUTRAL : match;
243         final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
244         return new TimeFilter(s, e, timeZone, onMatch, onMismatch);
245     }
246 
247     private static long parseTimestamp(final String timestamp, final long defaultValue) {
248         if (timestamp == null) {
249             return defaultValue;
250         }
251         final SimpleDateFormat stf = new SimpleDateFormat("HH:mm:ss");
252         stf.setTimeZone(TimeZone.getTimeZone("UTC"));
253         try {
254             return stf.parse(timestamp).getTime();
255         } catch (final ParseException e) {
256             LOGGER.warn("Error parsing TimeFilter timestamp value {}", timestamp, e);
257             return defaultValue;
258         }
259     }
260 
261 }