1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.filter;
18
19 import java.time.Duration;
20 import java.time.Instant;
21 import java.time.LocalDate;
22 import java.time.LocalTime;
23 import java.time.ZoneId;
24 import java.time.ZonedDateTime;
25 import java.time.format.DateTimeFormatter;
26
27 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.Marker;
29 import org.apache.logging.log4j.core.Filter;
30 import org.apache.logging.log4j.core.LogEvent;
31 import org.apache.logging.log4j.core.Logger;
32 import org.apache.logging.log4j.core.config.Node;
33 import org.apache.logging.log4j.core.config.plugins.Plugin;
34 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
35 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36 import org.apache.logging.log4j.core.util.Clock;
37 import org.apache.logging.log4j.core.util.ClockFactory;
38 import org.apache.logging.log4j.message.Message;
39 import org.apache.logging.log4j.util.PerformanceSensitive;
40
41
42
43
44 @Plugin(name = "TimeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
45 @PerformanceSensitive("allocation")
46 public final class TimeFilter extends AbstractFilter {
47 private static final Clock CLOCK = ClockFactory.getClock();
48 private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
49
50
51
52
53 private static final long HOUR_MS = 3600000;
54
55 private static final long DAY_MS = HOUR_MS * 24;
56
57
58
59
60 private volatile long start;
61 private final LocalTime startTime;
62
63
64
65
66 private volatile long end;
67 private final LocalTime endTime;
68
69 private final long duration;
70
71
72
73
74 private final ZoneId timeZone;
75
76
77
78
79 TimeFilter(final LocalTime start, final LocalTime end, final ZoneId timeZone, final Result onMatch,
80 final Result onMismatch, LocalDate now) {
81 super(onMatch, onMismatch);
82 this.startTime = start;
83 this.endTime = end;
84 this.timeZone = timeZone;
85 this.start = ZonedDateTime.of(now, startTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli();
86 long endMillis = ZonedDateTime.of(now, endTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli();
87 if (end.isBefore(start)) {
88
89 endMillis += DAY_MS;
90 }
91 duration = startTime.isBefore(endTime) ? Duration.between(startTime, endTime).toMillis() :
92 Duration.between(startTime, endTime).plusHours(24).toMillis();
93 long difference = (endMillis - this.start) - duration;
94 if (difference != 0) {
95
96 endMillis -= difference;
97 }
98 this.end = endMillis;
99 }
100
101 private TimeFilter(final LocalTime start, final LocalTime end, final ZoneId timeZone, final Result onMatch,
102 final Result onMismatch) {
103 this(start, end, timeZone, onMatch, onMismatch, LocalDate.now(timeZone));
104 }
105
106 private synchronized void adjustTimes(long currentTimeMillis) {
107 if (currentTimeMillis <= end) {
108 return;
109 }
110 LocalDate date = Instant.ofEpochMilli(currentTimeMillis).atZone(timeZone).toLocalDate();
111 this.start = ZonedDateTime.of(date, startTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli();
112 long endMillis = ZonedDateTime.of(date, endTime, timeZone).withEarlierOffsetAtOverlap().toInstant().toEpochMilli();
113 if (endTime.isBefore(startTime)) {
114
115 endMillis += DAY_MS;
116 }
117 long difference = (endMillis - this.start) - duration;
118 if (difference != 0) {
119
120 endMillis -= difference;
121 }
122 this.end = endMillis;
123 }
124
125
126
127
128
129
130
131
132 Result filter(final long currentTimeMillis) {
133 if (currentTimeMillis > end) {
134 adjustTimes(currentTimeMillis);
135 }
136 return currentTimeMillis >= start && currentTimeMillis <= end ? onMatch : onMismatch;
137 }
138
139 @Override
140 public Result filter(final LogEvent event) {
141 return filter(event.getTimeMillis());
142 }
143
144 private Result filter() {
145 return filter(CLOCK.currentTimeMillis());
146 }
147
148 @Override
149 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
150 final Throwable t) {
151 return filter();
152 }
153
154 @Override
155 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
156 final Throwable t) {
157 return filter();
158 }
159
160 @Override
161 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
162 final Object... params) {
163 return filter();
164 }
165
166 @Override
167 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
168 final Object p0) {
169 return filter();
170 }
171
172 @Override
173 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
174 final Object p0, final Object p1) {
175 return filter();
176 }
177
178 @Override
179 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
180 final Object p0, final Object p1, final Object p2) {
181 return filter();
182 }
183
184 @Override
185 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
186 final Object p0, final Object p1, final Object p2, final Object p3) {
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) {
193 return filter();
194 }
195
196 @Override
197 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
198 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5) {
199 return filter();
200 }
201
202 @Override
203 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
204 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
205 final Object p6) {
206 return filter();
207 }
208
209 @Override
210 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
211 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
212 final Object p6, final Object p7) {
213 return filter();
214 }
215
216 @Override
217 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
218 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
219 final Object p6, final Object p7, final Object p8) {
220 return filter();
221 }
222
223 @Override
224 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
225 final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
226 final Object p6, final Object p7, final Object p8, final Object p9) {
227 return filter();
228 }
229
230 @Override
231 public String toString() {
232 final StringBuilder sb = new StringBuilder();
233 sb.append("start=").append(start);
234 sb.append(", end=").append(end);
235 sb.append(", timezone=").append(timeZone.toString());
236 return sb.toString();
237 }
238
239
240
241
242
243
244
245
246
247
248
249 @PluginFactory
250 public static TimeFilter createFilter(
251 @PluginAttribute("start") final String start,
252 @PluginAttribute("end") final String end,
253 @PluginAttribute("timezone") final String tz,
254 @PluginAttribute("onMatch") final Result match,
255 @PluginAttribute("onMismatch") final Result mismatch) {
256 final LocalTime startTime = parseTimestamp(start, LocalTime.MIN);
257 final LocalTime endTime = parseTimestamp(end, LocalTime.MAX);
258 final ZoneId timeZone = tz == null ? ZoneId.systemDefault() : ZoneId.of(tz);
259 final Result onMatch = match == null ? Result.NEUTRAL : match;
260 final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
261 return new TimeFilter(startTime, endTime, timeZone, onMatch, onMismatch);
262 }
263
264 private static LocalTime parseTimestamp(final String timestamp, final LocalTime defaultValue) {
265 if (timestamp == null) {
266 return defaultValue;
267 }
268
269 try {
270 return LocalTime.parse(timestamp, FORMATTER);
271 } catch (final Exception e) {
272 LOGGER.warn("Error parsing TimeFilter timestamp value {}", timestamp, e);
273 return defaultValue;
274 }
275 }
276
277 }