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.core.Filter;
25  import org.apache.logging.log4j.core.LogEvent;
26  import org.apache.logging.log4j.core.config.Node;
27  import org.apache.logging.log4j.core.config.plugins.Plugin;
28  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
30  
31  /**
32   * Filters events that fall within a specified time period in each day.
33   */
34  @Plugin(name = "TimeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
35  public final class TimeFilter extends AbstractFilter {
36  
37      /**
38       * Length of hour in milliseconds.
39       */
40      private static final long HOUR_MS = 3600000;
41  
42      /**
43       * Length of minute in milliseconds.
44       */
45      private static final long MINUTE_MS = 60000;
46  
47      /**
48       * Length of second in milliseconds.
49       */
50      private static final long SECOND_MS = 1000;
51  
52      /**
53       * Starting offset from midnight in milliseconds.
54       */
55      private final long start;
56      /**
57       * Ending offset from midnight in milliseconds.
58       */
59      private final long end;
60      /**
61       * Timezone.
62       */
63      private final TimeZone timezone;
64  
65  
66      private TimeFilter(final long start, final long end, final TimeZone tz, final Result onMatch,
67                         final Result onMismatch) {
68          super(onMatch, onMismatch);
69          this.start = start;
70          this.end = end;
71          timezone = tz;
72      }
73  
74      @Override
75      public Result filter(final LogEvent event) {
76          final Calendar calendar = Calendar.getInstance(timezone);
77          calendar.setTimeInMillis(event.getTimeMillis());
78          //
79          //   get apparent number of milliseconds since midnight
80          //      (ignores extra or missing hour on daylight time changes).
81          //
82          final long apparentOffset = calendar.get(Calendar.HOUR_OF_DAY) * HOUR_MS +
83              calendar.get(Calendar.MINUTE) * MINUTE_MS +
84              calendar.get(Calendar.SECOND) * SECOND_MS +
85              calendar.get(Calendar.MILLISECOND);
86          return apparentOffset >= start && apparentOffset < end ? onMatch : onMismatch;
87      }
88  
89      @Override
90      public String toString() {
91          final StringBuilder sb = new StringBuilder();
92          sb.append("start=").append(start);
93          sb.append(", end=").append(end);
94          sb.append(", timezone=").append(timezone.toString());
95          return sb.toString();
96      }
97  
98      /**
99       * Create a TimeFilter.
100      * @param start The start time.
101      * @param end The end time.
102      * @param tz timezone.
103      * @param match Action to perform if the time matches.
104      * @param mismatch Action to perform if the action does not match.
105      * @return A TimeFilter.
106      */
107     @PluginFactory
108     public static TimeFilter createFilter(
109             @PluginAttribute("start") final String start,
110             @PluginAttribute("end") final String end,
111             @PluginAttribute("timezone") final String tz,
112             @PluginAttribute("onMatch") final Result match,
113             @PluginAttribute("onMismatch") final Result mismatch) {
114         final long s = parseTimestamp(start, 0);
115         final long e = parseTimestamp(end, Long.MAX_VALUE);
116         final TimeZone timezone = tz == null ? TimeZone.getDefault() : TimeZone.getTimeZone(tz);
117         final Result onMatch = match == null ? Result.NEUTRAL : match;
118         final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
119         return new TimeFilter(s, e, timezone, onMatch, onMismatch);
120     }
121 
122     private static long parseTimestamp(final String timestamp, final long defaultValue) {
123         if (timestamp == null) {
124             return defaultValue;
125         }
126         final SimpleDateFormat stf = new SimpleDateFormat("HH:mm:ss");
127         stf.setTimeZone(TimeZone.getTimeZone("UTC"));
128         try {
129             return stf.parse(timestamp).getTime();
130         } catch (final ParseException e) {
131             LOGGER.warn("Error parsing TimeFilter timestamp value {}", timestamp, e);
132             return defaultValue;
133         }
134     }
135 
136 }