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        
112        // LOG4J2-531: call getNextTime twice to force initialization of both prevFileTime and nextFileTime
113        aManager.getPatternProcessor().getNextTime(aManager.getFileTime(), interval, modulate);
114        
115        nextRolloverMillis = ThreadLocalRandom.current().nextLong(0, 1 + maxRandomDelayMillis)
116                + aManager.getPatternProcessor().getNextTime(aManager.getFileTime(), interval, modulate);
117    }
118
119    /**
120     * Determines whether a rollover should occur.
121     * @param event   A reference to the currently event.
122     * @return true if a rollover should occur.
123     */
124    @Override
125    public boolean isTriggeringEvent(final LogEvent event) {
126        if (manager.getFileSize() == 0) {
127            return false;
128        }
129        final long nowMillis = event.getTimeMillis();
130        if (nowMillis >= nextRolloverMillis) {
131            nextRolloverMillis = ThreadLocalRandom.current().nextLong(0, 1 + maxRandomDelayMillis)
132                    + manager.getPatternProcessor().getNextTime(nowMillis, interval, modulate);
133            return true;
134        }
135        return false;
136    }
137
138    /**
139     * Creates a TimeBasedTriggeringPolicy.
140     * @param interval The interval between rollovers.
141     * @param modulate If true the time will be rounded to occur on a boundary aligned with the increment.
142     * @return a TimeBasedTriggeringPolicy.
143     * @deprecated Use {@link #newBuilder()}.
144     */
145    @Deprecated
146    public static TimeBasedTriggeringPolicy createPolicy(
147            @PluginAttribute("interval") final String interval,
148            @PluginAttribute("modulate") final String modulate) {
149        return newBuilder()
150                .withInterval(Integers.parseInt(interval, 1))
151                .withModulate(Boolean.parseBoolean(modulate))
152                .build();
153    }
154    
155    @PluginBuilderFactory
156    public static TimeBasedTriggeringPolicy.Builder newBuilder() {
157        return new Builder();
158    }
159
160    @Override
161    public String toString() {
162        return "TimeBasedTriggeringPolicy(nextRolloverMillis=" + nextRolloverMillis + ", interval=" + interval
163                + ", modulate=" + modulate + ")";
164    }
165
166}