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 * Ending offset from midnight in milliseconds. 067 */ 068 private final long end; 069 /** 070 * Timezone. 071 */ 072 private final TimeZone timezone; 073 074 private long midnightToday; 075 private long midnightTomorrow; 076 077 078 private TimeFilter(final long start, final long end, final TimeZone tz, final Result onMatch, 079 final Result onMismatch) { 080 super(onMatch, onMismatch); 081 this.start = start; 082 this.end = end; 083 timezone = tz; 084 initMidnight(start); 085 } 086 087 /** 088 * Initializes the midnight boundaries to midnight in the specified time zone. 089 * @param now a time in milliseconds since the epoch, used to pinpoint the current date 090 */ 091 void initMidnight(final long now) { 092 final Calendar calendar = Calendar.getInstance(timezone); 093 calendar.setTimeInMillis(now); 094 calendar.set(Calendar.HOUR_OF_DAY, 0); 095 calendar.set(Calendar.MINUTE, 0); 096 calendar.set(Calendar.SECOND, 0); 097 calendar.set(Calendar.MILLISECOND, 0); 098 midnightToday = calendar.getTimeInMillis(); 099 100 calendar.add(Calendar.DATE, 1); 101 midnightTomorrow = calendar.getTimeInMillis(); 102 } 103 104 /** 105 * Package-protected for tests. 106 * 107 * @param currentTimeMillis the time to compare with the boundaries. May re-initialize the cached midnight 108 * boundary values. 109 * @return the action to perform 110 */ 111 Result filter(final long currentTimeMillis) { 112 if (currentTimeMillis >= midnightTomorrow || currentTimeMillis < midnightToday) { 113 initMidnight(currentTimeMillis); 114 } 115 return currentTimeMillis >= midnightToday + start && currentTimeMillis <= midnightToday + end // 116 ? onMatch // within window 117 : onMismatch; 118 } 119 120 @Override 121 public Result filter(final LogEvent event) { 122 return filter(event.getTimeMillis()); 123 } 124 125 private Result filter() { 126 return filter(CLOCK.currentTimeMillis()); 127 } 128 129 @Override 130 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg, 131 final Throwable t) { 132 return filter(); 133 } 134 135 @Override 136 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg, 137 final Throwable t) { 138 return filter(); 139 } 140 141 @Override 142 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 143 final Object... params) { 144 return filter(); 145 } 146 147 @Override 148 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 149 final Object p0) { 150 return filter(); 151 } 152 153 @Override 154 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 155 final Object p0, final Object p1) { 156 return filter(); 157 } 158 159 @Override 160 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 161 final Object p0, final Object p1, final Object p2) { 162 return filter(); 163 } 164 165 @Override 166 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 167 final Object p0, final Object p1, final Object p2, final Object p3) { 168 return filter(); 169 } 170 171 @Override 172 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 173 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4) { 174 return filter(); 175 } 176 177 @Override 178 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 179 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5) { 180 return filter(); 181 } 182 183 @Override 184 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 185 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5, 186 final Object p6) { 187 return filter(); 188 } 189 190 @Override 191 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 192 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5, 193 final Object p6, final Object p7) { 194 return filter(); 195 } 196 197 @Override 198 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 199 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5, 200 final Object p6, final Object p7, final Object p8) { 201 return filter(); 202 } 203 204 @Override 205 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 206 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5, 207 final Object p6, final Object p7, final Object p8, final Object p9) { 208 return filter(); 209 } 210 211 @Override 212 public String toString() { 213 final StringBuilder sb = new StringBuilder(); 214 sb.append("start=").append(start); 215 sb.append(", end=").append(end); 216 sb.append(", timezone=").append(timezone.toString()); 217 return sb.toString(); 218 } 219 220 /** 221 * Create a TimeFilter. 222 * @param start The start time. 223 * @param end The end time. 224 * @param tz timezone. 225 * @param match Action to perform if the time matches. 226 * @param mismatch Action to perform if the action does not match. 227 * @return A TimeFilter. 228 */ 229 @PluginFactory 230 public static TimeFilter createFilter( 231 @PluginAttribute("start") final String start, 232 @PluginAttribute("end") final String end, 233 @PluginAttribute("timezone") final String tz, 234 @PluginAttribute("onMatch") final Result match, 235 @PluginAttribute("onMismatch") final Result mismatch) { 236 final long s = parseTimestamp(start, 0); 237 final long e = parseTimestamp(end, Long.MAX_VALUE); 238 final TimeZone timezone = tz == null ? TimeZone.getDefault() : TimeZone.getTimeZone(tz); 239 final Result onMatch = match == null ? Result.NEUTRAL : match; 240 final Result onMismatch = mismatch == null ? Result.DENY : mismatch; 241 return new TimeFilter(s, e, timezone, onMatch, onMismatch); 242 } 243 244 private static long parseTimestamp(final String timestamp, final long defaultValue) { 245 if (timestamp == null) { 246 return defaultValue; 247 } 248 final SimpleDateFormat stf = new SimpleDateFormat("HH:mm:ss"); 249 stf.setTimeZone(TimeZone.getTimeZone("UTC")); 250 try { 251 return stf.parse(timestamp).getTime(); 252 } catch (final ParseException e) { 253 LOGGER.warn("Error parsing TimeFilter timestamp value {}", timestamp, e); 254 return defaultValue; 255 } 256 } 257 258}