View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.appender.rolling;
18  
19  import java.text.ParseException;
20  import java.util.Calendar;
21  import java.util.Date;
22  import java.util.Objects;
23  import java.util.concurrent.TimeUnit;
24  
25  import org.apache.logging.log4j.core.Core;
26  import org.apache.logging.log4j.core.LifeCycle;
27  import org.apache.logging.log4j.core.LogEvent;
28  import org.apache.logging.log4j.core.config.Configuration;
29  import org.apache.logging.log4j.core.config.ConfigurationScheduler;
30  import org.apache.logging.log4j.core.config.CronScheduledFuture;
31  import org.apache.logging.log4j.core.config.Scheduled;
32  import org.apache.logging.log4j.core.config.plugins.Plugin;
33  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
34  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
35  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36  import org.apache.logging.log4j.core.util.CronExpression;
37  
38  /**
39   * Rolls a file over based on a cron schedule.
40   */
41  @Plugin(name = "CronTriggeringPolicy", category = Core.CATEGORY_NAME, printObject = true)
42  @Scheduled
43  public final class CronTriggeringPolicy extends AbstractTriggeringPolicy {
44  
45      private static final String defaultSchedule = "0 0 0 * * ?";
46      private RollingFileManager manager;
47      private final CronExpression cronExpression;
48      private final Configuration configuration;
49      private final boolean checkOnStartup;
50      private volatile Date lastRollDate;
51      private CronScheduledFuture<?> future;
52  
53      private CronTriggeringPolicy(final CronExpression schedule, final boolean checkOnStartup,
54              final Configuration configuration) {
55          this.cronExpression = Objects.requireNonNull(schedule, "schedule");
56          this.configuration = Objects.requireNonNull(configuration, "configuration");
57          this.checkOnStartup = checkOnStartup;
58      }
59  
60      /**
61       * Initializes the policy.
62       * 
63       * @param aManager
64       *            The RollingFileManager.
65       */
66      @Override
67      public void initialize(final RollingFileManager aManager) {
68          this.manager = aManager;
69          final Date now = new Date();
70          final Date lastRollForFile = cronExpression.getPrevFireTime(new Date(this.manager.getFileTime()));
71          final Date lastRegularRoll = cronExpression.getPrevFireTime(new Date());
72          aManager.getPatternProcessor().setCurrentFileTime(lastRegularRoll.getTime());
73          LOGGER.debug("LastRollForFile {}, LastRegularRole {}", lastRollForFile, lastRegularRoll);
74          aManager.getPatternProcessor().setPrevFileTime(lastRegularRoll.getTime());
75          if (checkOnStartup && lastRollForFile != null && lastRegularRoll != null &&
76                  lastRollForFile.before(lastRegularRoll)) {
77              lastRollDate = lastRollForFile;
78              rollover();
79          }
80  
81          final ConfigurationScheduler scheduler = configuration.getScheduler();
82          if (!scheduler.isExecutorServiceSet()) {
83              // make sure we have a thread pool
84              scheduler.incrementScheduledItems();
85          }
86          if (!scheduler.isStarted()) {
87              scheduler.start();
88          }
89          lastRollDate = lastRegularRoll;
90          future = scheduler.scheduleWithCron(cronExpression, now, new CronTrigger());
91          LOGGER.debug(scheduler.toString());
92      }
93  
94      /**
95       * Determines whether a rollover should occur.
96       * 
97       * @param event
98       *            A reference to the currently event.
99       * @return true if a rollover should occur.
100      */
101     @Override
102     public boolean isTriggeringEvent(final LogEvent event) {
103         return false;
104     }
105 
106     public CronExpression getCronExpression() {
107         return cronExpression;
108     }
109 
110     /**
111      * Creates a ScheduledTriggeringPolicy.
112      * 
113      * @param configuration
114      *            the Configuration.
115      * @param evaluateOnStartup
116      *            check if the file should be rolled over immediately.
117      * @param schedule
118      *            the cron expression.
119      * @return a ScheduledTriggeringPolicy.
120      */
121     @PluginFactory
122     public static CronTriggeringPolicy createPolicy(@PluginConfiguration final Configuration configuration,
123             @PluginAttribute("evaluateOnStartup") final String evaluateOnStartup,
124             @PluginAttribute("schedule") final String schedule) {
125         CronExpression cronExpression;
126         final boolean checkOnStartup = Boolean.parseBoolean(evaluateOnStartup);
127         if (schedule == null) {
128             LOGGER.info("No schedule specified, defaulting to Daily");
129             cronExpression = getSchedule(defaultSchedule);
130         } else {
131             cronExpression = getSchedule(schedule);
132             if (cronExpression == null) {
133                 LOGGER.error("Invalid expression specified. Defaulting to Daily");
134                 cronExpression = getSchedule(defaultSchedule);
135             }
136         }
137         return new CronTriggeringPolicy(cronExpression, checkOnStartup, configuration);
138     }
139 
140     private static CronExpression getSchedule(final String expression) {
141         try {
142             return new CronExpression(expression);
143         } catch (final ParseException pe) {
144             LOGGER.error("Invalid cron expression - " + expression, pe);
145             return null;
146         }
147     }
148 
149     private void rollover() {
150         manager.getPatternProcessor().setPrevFileTime(lastRollDate.getTime());
151         final Date thisRoll = cronExpression.getPrevFireTime(new Date());
152         manager.getPatternProcessor().setCurrentFileTime(thisRoll.getTime());
153         manager.rollover();
154         if (future != null) {
155             lastRollDate = future.getFireTime();
156         }
157     }
158 
159     @Override
160     public boolean stop(final long timeout, final TimeUnit timeUnit) {
161         setStopping();
162         final boolean stopped = stop(future);
163         setStopped();
164         return stopped;
165     }
166 
167     @Override
168     public String toString() {
169         return "CronTriggeringPolicy(schedule=" + cronExpression.getCronExpression() + ")";
170     }
171 
172     private class CronTrigger implements Runnable {
173 
174         @Override
175         public void run() {
176             rollover();
177         }
178     }
179 }