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          aManager.getPatternProcessor().setTimeBased(true);
74          if (checkOnStartup && lastRollForFile != null && lastRegularRoll != null &&
75                  lastRollForFile.before(lastRegularRoll)) {
76              lastRollDate = lastRollForFile;
77              rollover();
78          }
79  
80          final ConfigurationScheduler scheduler = configuration.getScheduler();
81          if (!scheduler.isExecutorServiceSet()) {
82              // make sure we have a thread pool
83              scheduler.incrementScheduledItems();
84          }
85          if (!scheduler.isStarted()) {
86              scheduler.start();
87          }
88          lastRollDate = lastRegularRoll;
89          future = scheduler.scheduleWithCron(cronExpression, now, new CronTrigger());
90          LOGGER.debug(scheduler.toString());
91      }
92  
93      /**
94       * Determines whether a rollover should occur.
95       *
96       * @param event
97       *            A reference to the currently event.
98       * @return true if a rollover should occur.
99       */
100     @Override
101     public boolean isTriggeringEvent(final LogEvent event) {
102         return false;
103     }
104 
105     public CronExpression getCronExpression() {
106         return cronExpression;
107     }
108 
109     /**
110      * Creates a ScheduledTriggeringPolicy.
111      *
112      * @param configuration
113      *            the Configuration.
114      * @param evaluateOnStartup
115      *            check if the file should be rolled over immediately.
116      * @param schedule
117      *            the cron expression.
118      * @return a ScheduledTriggeringPolicy.
119      */
120     @PluginFactory
121     public static CronTriggeringPolicy createPolicy(@PluginConfiguration final Configuration configuration,
122             @PluginAttribute("evaluateOnStartup") final String evaluateOnStartup,
123             @PluginAttribute("schedule") final String schedule) {
124         CronExpression cronExpression;
125         final boolean checkOnStartup = Boolean.parseBoolean(evaluateOnStartup);
126         if (schedule == null) {
127             LOGGER.info("No schedule specified, defaulting to Daily");
128             cronExpression = getSchedule(defaultSchedule);
129         } else {
130             cronExpression = getSchedule(schedule);
131             if (cronExpression == null) {
132                 LOGGER.error("Invalid expression specified. Defaulting to Daily");
133                 cronExpression = getSchedule(defaultSchedule);
134             }
135         }
136         return new CronTriggeringPolicy(cronExpression, checkOnStartup, configuration);
137     }
138 
139     private static CronExpression getSchedule(final String expression) {
140         try {
141             return new CronExpression(expression);
142         } catch (final ParseException pe) {
143             LOGGER.error("Invalid cron expression - " + expression, pe);
144             return null;
145         }
146     }
147 
148     private void rollover() {
149     	manager.rollover(cronExpression.getPrevFireTime(new Date()), lastRollDate);
150         if (future != null) {
151             lastRollDate = future.getFireTime();
152         }
153     }
154 
155     @Override
156     public boolean stop(final long timeout, final TimeUnit timeUnit) {
157         setStopping();
158         final boolean stopped = stop(future);
159         setStopped();
160         return stopped;
161     }
162 
163     @Override
164     public String toString() {
165         return "CronTriggeringPolicy(schedule=" + cronExpression.getCronExpression() + ")";
166     }
167 
168     private class CronTrigger implements Runnable {
169 
170         @Override
171         public void run() {
172             rollover();
173         }
174     }
175 }