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     */
017    package org.apache.logging.log4j.core.filter;
018    
019    import java.text.ParseException;
020    import java.text.SimpleDateFormat;
021    import java.util.Calendar;
022    import java.util.TimeZone;
023    
024    import org.apache.logging.log4j.core.LogEvent;
025    import org.apache.logging.log4j.core.config.plugins.Plugin;
026    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
027    import 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)
033    public 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.getTimeMillis());
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 Result match,
110                @PluginAttribute("onMismatch") final Result 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 = match == null ? Result.NEUTRAL : match;
132            final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
133            return new TimeFilter(s, e, timezone, onMatch, onMismatch);
134        }
135    
136    }