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.Date;
21  import java.util.Objects;
22  import java.util.concurrent.TimeUnit;
23  
24  import org.apache.logging.log4j.core.Core;
25  import org.apache.logging.log4j.core.LogEvent;
26  import org.apache.logging.log4j.core.config.Configuration;
27  import org.apache.logging.log4j.core.config.ConfigurationScheduler;
28  import org.apache.logging.log4j.core.config.CronScheduledFuture;
29  import org.apache.logging.log4j.core.config.Scheduled;
30  import org.apache.logging.log4j.core.config.plugins.Plugin;
31  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
32  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
33  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34  import org.apache.logging.log4j.core.util.CronExpression;
35  
36  /**
37   * Rolls a file over based on a cron schedule.
38   */
39  @Plugin(name = "CronTriggeringPolicy", category = Core.CATEGORY_NAME, printObject = true)
40  @Scheduled
41  public final class CronTriggeringPolicy extends AbstractTriggeringPolicy {
42  
43      private static final String defaultSchedule = "0 0 0 * * ?";
44      private RollingFileManager manager;
45      private final CronExpression cronExpression;
46      private final Configuration configuration;
47      private final boolean checkOnStartup;
48      private volatile Date lastRollDate;
49      private CronScheduledFuture<?> future;
50  
51      private CronTriggeringPolicy(final CronExpression schedule, final boolean checkOnStartup,
52              final Configuration configuration) {
53          this.cronExpression = Objects.requireNonNull(schedule, "schedule");
54          this.configuration = Objects.requireNonNull(configuration, "configuration");
55          this.checkOnStartup = checkOnStartup;
56      }
57  
58      /**
59       * Initializes the policy.
60       * 
61       * @param aManager
62       *            The RollingFileManager.
63       */
64      @Override
65      public void initialize(final RollingFileManager aManager) {
66          this.manager = aManager;
67          final Date now = new Date();
68          final Date lastRollForFile = cronExpression.getPrevFireTime(new Date(this.manager.getFileTime()));
69          final Date lastRegularRoll = cronExpression.getPrevFireTime(new Date());
70          aManager.getPatternProcessor().setCurrentFileTime(lastRegularRoll.getTime());
71          LOGGER.debug("LastRollForFile {}, LastRegularRole {}", lastRollForFile, lastRegularRoll);
72          aManager.getPatternProcessor().setPrevFileTime(lastRegularRoll.getTime());
73          if (checkOnStartup && lastRollForFile != null && lastRegularRoll != null &&
74                  lastRollForFile.before(lastRegularRoll)) {
75              lastRollDate = lastRollForFile;
76              rollover();
77          }
78  
79          final ConfigurationScheduler scheduler = configuration.getScheduler();
80          if (!scheduler.isExecutorServiceSet()) {
81              // make sure we have a thread pool
82              scheduler.incrementScheduledItems();
83          }
84          if (!scheduler.isStarted()) {
85              scheduler.start();
86          }
87          lastRollDate = lastRegularRoll;
88          future = scheduler.scheduleWithCron(cronExpression, now, new CronTrigger());
89          LOGGER.debug(scheduler.toString());
90      }
91  
92      /**
93       * Determines whether a rollover should occur.
94       * 
95       * @param event
96       *            A reference to the currently event.
97       * @return true if a rollover should occur.
98       */
99      @Override
100     public boolean isTriggeringEvent(final LogEvent event) {
101         return false;
102     }
103 
104     public CronExpression getCronExpression() {
105         return cronExpression;
106     }
107 
108     /**
109      * Creates a ScheduledTriggeringPolicy.
110      * 
111      * @param configuration
112      *            the Configuration.
113      * @param evaluateOnStartup
114      *            check if the file should be rolled over immediately.
115      * @param schedule
116      *            the cron expression.
117      * @return a ScheduledTriggeringPolicy.
118      */
119     @PluginFactory
120     public static CronTriggeringPolicy createPolicy(@PluginConfiguration final Configuration configuration,
121             @PluginAttribute("evaluateOnStartup") final String evaluateOnStartup,
122             @PluginAttribute("schedule") final String schedule) {
123         CronExpression cronExpression;
124         final boolean checkOnStartup = Boolean.parseBoolean(evaluateOnStartup);
125         if (schedule == null) {
126             LOGGER.info("No schedule specified, defaulting to Daily");
127             cronExpression = getSchedule(defaultSchedule);
128         } else {
129             cronExpression = getSchedule(schedule);
130             if (cronExpression == null) {
131                 LOGGER.error("Invalid expression specified. Defaulting to Daily");
132                 cronExpression = getSchedule(defaultSchedule);
133             }
134         }
135         return new CronTriggeringPolicy(cronExpression, checkOnStartup, configuration);
136     }
137 
138     private static CronExpression getSchedule(final String expression) {
139         try {
140             return new CronExpression(expression);
141         } catch (final ParseException pe) {
142             LOGGER.error("Invalid cron expression - " + expression, pe);
143             return null;
144         }
145     }
146 
147     private void rollover() {
148         manager.getPatternProcessor().setPrevFileTime(lastRollDate.getTime());
149         final Date thisRoll = cronExpression.getPrevFireTime(new Date());
150         manager.getPatternProcessor().setCurrentFileTime(thisRoll.getTime());
151         manager.rollover();
152         if (future != null) {
153             lastRollDate = future.getFireTime();
154         }
155     }
156 
157     @Override
158     public boolean stop(final long timeout, final TimeUnit timeUnit) {
159         setStopping();
160         final boolean stopped = stop(future);
161         setStopped();
162         return stopped;
163     }
164 
165     @Override
166     public String toString() {
167         return "CronTriggeringPolicy(schedule=" + cronExpression.getCronExpression() + ")";
168     }
169 
170     private class CronTrigger implements Runnable {
171 
172         @Override
173         public void run() {
174             rollover();
175         }
176     }
177 }