001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.filter; 018 019import java.text.ParseException; 020import java.text.SimpleDateFormat; 021import java.util.Calendar; 022import java.util.TimeZone; 023 024import org.apache.logging.log4j.Level; 025import org.apache.logging.log4j.Marker; 026import org.apache.logging.log4j.core.Filter; 027import org.apache.logging.log4j.core.LogEvent; 028import org.apache.logging.log4j.core.Logger; 029import org.apache.logging.log4j.core.config.Node; 030import org.apache.logging.log4j.core.config.plugins.Plugin; 031import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 032import org.apache.logging.log4j.core.config.plugins.PluginFactory; 033import org.apache.logging.log4j.core.util.Clock; 034import org.apache.logging.log4j.core.util.ClockFactory; 035import org.apache.logging.log4j.message.Message; 036import org.apache.logging.log4j.util.PerformanceSensitive; 037 038/** 039 * Filters events that fall within a specified time period in each day. 040 */ 041@Plugin(name = "TimeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true) 042@PerformanceSensitive("allocation") 043public final class TimeFilter extends AbstractFilter { 044 private static final Clock CLOCK = ClockFactory.getClock(); 045 046 /** 047 * Length of hour in milliseconds. 048 */ 049 private static final long HOUR_MS = 3600000; 050 051 /** 052 * Length of minute in milliseconds. 053 */ 054 private static final long MINUTE_MS = 60000; 055 056 /** 057 * Length of second in milliseconds. 058 */ 059 private static final long SECOND_MS = 1000; 060 061 /** 062 * Starting offset from midnight in milliseconds. 063 */ 064 private final long start; 065 066 /** 067 * Ending offset from midnight in milliseconds. 068 */ 069 private final long end; 070 071 /** 072 * Timezone. 073 */ 074 private final TimeZone timeZone; 075 076 private long midnightToday; 077 private long midnightTomorrow; 078 079 080 private TimeFilter(final long start, final long end, final TimeZone timeZone, final Result onMatch, 081 final Result onMismatch) { 082 super(onMatch, onMismatch); 083 this.start = start; 084 this.end = end; 085 this.timeZone = timeZone; 086 initMidnight(start); 087 } 088 089 /** 090 * Initializes the midnight boundaries to midnight in the specified time zone. 091 * @param now a time in milliseconds since the epoch, used to pinpoint the current date 092 */ 093 void initMidnight(final long now) { 094 final Calendar calendar = Calendar.getInstance(timeZone); 095 calendar.setTimeInMillis(now); 096 calendar.set(Calendar.HOUR_OF_DAY, 0); 097 calendar.set(Calendar.MINUTE, 0); 098 calendar.set(Calendar.SECOND, 0); 099 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}