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.core.LogEvent;
025import org.apache.logging.log4j.core.config.plugins.Plugin;
026import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
027import org.apache.logging.log4j.core.config.plugins.PluginFactory;
028
029/**
030 * Filters events that fall within a specified time period in each day.
031 */
032@Plugin(name = "TimeFilter", category = "Core", elementType = "filter", printObject = true)
033public final class TimeFilter extends AbstractFilter {
034    /**
035     * Length of hour in milliseconds.
036     */
037    private static final long HOUR_MS = 3600000;
038
039    /**
040     * Length of minute in milliseconds.
041     */
042    private static final long MINUTE_MS = 60000;
043
044    /**
045     * Length of second in milliseconds.
046     */
047    private static final long SECOND_MS = 1000;
048
049    /**
050     * Starting offset from midnight in milliseconds.
051     */
052    private final long start;
053    /**
054     * Ending offset from midnight in milliseconds.
055     */
056    private final long end;
057    /**
058     * Timezone.
059     */
060    private final TimeZone timezone;
061
062
063    private TimeFilter(final long start, final long end, final TimeZone tz, final Result onMatch,
064                       final Result onMismatch) {
065        super(onMatch, onMismatch);
066        this.start = start;
067        this.end = end;
068        timezone = tz;
069    }
070
071    @Override
072    public Result filter(final LogEvent event) {
073        final Calendar calendar = Calendar.getInstance(timezone);
074        calendar.setTimeInMillis(event.getMillis());
075        //
076        //   get apparent number of milliseconds since midnight
077        //      (ignores extra or missing hour on daylight time changes).
078        //
079        final long apparentOffset = calendar.get(Calendar.HOUR_OF_DAY) * HOUR_MS +
080            calendar.get(Calendar.MINUTE) * MINUTE_MS +
081            calendar.get(Calendar.SECOND) * SECOND_MS +
082            calendar.get(Calendar.MILLISECOND);
083        return apparentOffset >= start && apparentOffset < end ? onMatch : onMismatch;
084    }
085
086    @Override
087    public String toString() {
088        final StringBuilder sb = new StringBuilder();
089        sb.append("start=").append(start);
090        sb.append(", end=").append(end);
091        sb.append(", timezone=").append(timezone.toString());
092        return sb.toString();
093    }
094
095    /**
096     * Create a TimeFilter.
097     * @param start The start time.
098     * @param end The end time.
099     * @param tz timezone.
100     * @param match Action to perform if the time matches.
101     * @param mismatch Action to perform if the action does not match.
102     * @return A TimeFilter.
103     */
104    @PluginFactory
105    public static TimeFilter createFilter(
106            @PluginAttribute("start") final String start,
107            @PluginAttribute("end") final String end,
108            @PluginAttribute("timezone") final String tz,
109            @PluginAttribute("onMatch") final String match,
110            @PluginAttribute("onMismatch") final String mismatch) {
111        final SimpleDateFormat stf = new SimpleDateFormat("HH:mm:ss");
112        long s = 0;
113        if (start != null) {
114            stf.setTimeZone(TimeZone.getTimeZone("UTC"));
115            try {
116                s = stf.parse(start).getTime();
117            } catch (final ParseException ex) {
118                LOGGER.warn("Error parsing start value " + start, ex);
119            }
120        }
121        long e = Long.MAX_VALUE;
122        if (end != null) {
123            stf.setTimeZone(TimeZone.getTimeZone("UTC"));
124            try {
125                e = stf.parse(end).getTime();
126            } catch (final ParseException ex) {
127                LOGGER.warn("Error parsing start value " + end, ex);
128            }
129        }
130        final TimeZone timezone = tz == null ? TimeZone.getDefault() : TimeZone.getTimeZone(tz);
131        final Result onMatch = Result.toResult(match, Result.NEUTRAL);
132        final Result onMismatch = Result.toResult(mismatch, Result.DENY);
133        return new TimeFilter(s, e, timezone, onMatch, onMismatch);
134    }
135
136}