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.appender.rolling;
018
019import java.util.concurrent.ThreadLocalRandom;
020import java.util.concurrent.TimeUnit;
021
022import org.apache.logging.log4j.core.Core;
023import org.apache.logging.log4j.core.LogEvent;
024import org.apache.logging.log4j.core.config.plugins.Plugin;
025import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
026import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
027import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
028import org.apache.logging.log4j.core.util.Integers;
029
030/**
031 * Rolls a file over based on time.
032 */
033@Plugin(name = "TimeBasedTriggeringPolicy", category = Core.CATEGORY_NAME, printObject = true)
034public final class TimeBasedTriggeringPolicy extends AbstractTriggeringPolicy {
035
036
037    public static class Builder implements org.apache.logging.log4j.core.util.Builder<TimeBasedTriggeringPolicy> {
038
039        @PluginBuilderAttribute
040        private int interval = 1;
041
042        @PluginBuilderAttribute
043        private boolean modulate = false;
044
045        @PluginBuilderAttribute
046        private int maxRandomDelay = 0;
047
048        @Override
049        public TimeBasedTriggeringPolicy build() {
050            final long maxRandomDelayMillis = TimeUnit.SECONDS.toMillis(maxRandomDelay);
051            return new TimeBasedTriggeringPolicy(interval, modulate, maxRandomDelayMillis);
052        }
053
054        public int getInterval() {
055            return interval;
056        }
057
058        public boolean isModulate() {
059            return modulate;
060        }
061
062        public int getMaxRandomDelay() {
063            return maxRandomDelay;
064        }
065
066        public Builder withInterval(final int interval){
067            this.interval = interval;
068            return this;
069        }
070
071        public Builder withModulate(final boolean modulate){
072            this.modulate = modulate;
073            return this;
074        }
075
076        public Builder withMaxRandomDelay(final int maxRandomDelay){
077            this.maxRandomDelay = maxRandomDelay;
078            return this;
079        }
080
081    }
082
083    private long nextRolloverMillis;
084    private final int interval;
085    private final boolean modulate;
086    private final long maxRandomDelayMillis;
087
088    private RollingFileManager manager;
089
090    private TimeBasedTriggeringPolicy(final int interval, final boolean modulate, final long maxRandomDelayMillis) {
091        this.interval = interval;
092        this.modulate = modulate;
093        this.maxRandomDelayMillis = maxRandomDelayMillis;
094    }
095
096    public int getInterval() {
097        return interval;
098    }
099
100    public long getNextRolloverMillis() {
101        return nextRolloverMillis;
102    }
103
104    /**
105     * Initializes the policy.
106     * @param aManager The RollingFileManager.
107     */
108    @Override
109    public void initialize(final RollingFileManager aManager) {
110        this.manager = aManager;
111        long current = aManager.getFileTime();
112        if (current == 0) {
113            current = System.currentTimeMillis();
114        }
115
116        // LOG4J2-531: call getNextTime twice to force initialization of both prevFileTime and nextFileTime
117        aManager.getPatternProcessor().getNextTime(current, interval, modulate);
118        aManager.getPatternProcessor().setTimeBased(true);
119
120        nextRolloverMillis = ThreadLocalRandom.current().nextLong(0, 1 + maxRandomDelayMillis)
121                + aManager.getPatternProcessor().getNextTime(current, interval, modulate);
122    }
123
124    /**
125     * Determines whether a rollover should occur.
126     * @param event   A reference to the currently event.
127     * @return true if a rollover should occur.
128     */
129    @Override
130    public boolean isTriggeringEvent(final LogEvent event) {
131        final long nowMillis = event.getTimeMillis();
132        if (nowMillis >= nextRolloverMillis) {
133            nextRolloverMillis = ThreadLocalRandom.current().nextLong(0, 1 + maxRandomDelayMillis)
134                    + manager.getPatternProcessor().getNextTime(nowMillis, interval, modulate);
135            manager.getPatternProcessor().setCurrentFileTime(System.currentTimeMillis());
136            return true;
137        }
138        return false;
139    }
140
141    /**
142     * Creates a TimeBasedTriggeringPolicy.
143     * @param interval The interval between rollovers.
144     * @param modulate If true the time will be rounded to occur on a boundary aligned with the increment.
145     * @return a TimeBasedTriggeringPolicy.
146     * @deprecated Use {@link #newBuilder()}.
147     */
148    @Deprecated
149    public static TimeBasedTriggeringPolicy createPolicy(
150            @PluginAttribute("interval") final String interval,
151            @PluginAttribute("modulate") final String modulate) {
152        return newBuilder()
153                .withInterval(Integers.parseInt(interval, 1))
154                .withModulate(Boolean.parseBoolean(modulate))
155                .build();
156    }
157
158    @PluginBuilderFactory
159    public static TimeBasedTriggeringPolicy.Builder newBuilder() {
160        return new Builder();
161    }
162
163    @Override
164    public String toString() {
165        return "TimeBasedTriggeringPolicy(nextRolloverMillis=" + nextRolloverMillis + ", interval=" + interval
166                + ", modulate=" + modulate + ")";
167    }
168
169}