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