| #region Apache License |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to you under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #endregion |
| |
| using System; |
| using System.IO; |
| |
| namespace log4net.Appender.Rolling |
| { |
| /// <summary> |
| /// A implementation of the <see cref="IRollingCondition"/> interface that rolls |
| /// the file cronologically. |
| /// </summary> |
| /// <author>Dominik Psenner</author> |
| public class CronRollingCondition : IRollingCondition |
| { |
| #region Public Instance Constructors |
| |
| public CronRollingCondition() |
| : this("*", "*", "*", "*", "*") |
| { |
| } |
| |
| public CronRollingCondition(string dow, string month, string day, string hour, string minute) |
| { |
| Dow = TryParse(dow); |
| Month = TryParse(month); |
| Day = TryParse(day); |
| Hour = TryParse(hour); |
| Minute = TryParse(minute); |
| } |
| |
| #endregion |
| |
| #region Protected Instance Properties |
| |
| protected Tuple<int?, MatchType> Dow { get; private set; } |
| protected Tuple<int?, MatchType> Month { get; private set; } |
| protected Tuple<int?, MatchType> Day { get; private set; } |
| protected Tuple<int?, MatchType> Hour { get; private set; } |
| protected Tuple<int?, MatchType> Minute { get; private set; } |
| |
| #endregion |
| |
| #region Private Instance Properties |
| |
| private ulong last_rolled = 0; |
| |
| #endregion |
| |
| #region Protected Inner Classes |
| |
| protected enum MatchType |
| { |
| Nothing, |
| Exact, |
| Remainder, |
| } |
| |
| #endregion |
| |
| #region Protected Static Methods |
| |
| /// <summary> |
| /// This method parses a string to match any of these: |
| /// i |
| /// * |
| /// */i |
| /// </summary> |
| /// <param name="input"></param> |
| /// <returns></returns> |
| static protected Tuple<int?, MatchType> TryParse(string input) |
| { |
| // trim input and strip empty spaces |
| string inputParsed = input.Trim().Replace(" ", "").Replace("\t", ""); |
| |
| // match a remainder: */c |
| if (inputParsed.StartsWith("*/") || inputParsed.StartsWith(@"*\")) |
| { |
| // strip first two chars |
| inputParsed = inputParsed.Substring(2); |
| // parse the remainder |
| int i = -1; |
| if (int.TryParse(inputParsed, out i)) |
| { |
| return Tuple.Create<int?, MatchType>(i, MatchType.Remainder); |
| } |
| } |
| else if (inputParsed.StartsWith("*")) // match anything: * |
| { |
| return Tuple.Create<int?, MatchType>(null, MatchType.Nothing); |
| } |
| else // match one specific numer: i |
| { |
| int i = -1; |
| if (int.TryParse(inputParsed, out i)) |
| { |
| return Tuple.Create<int?, MatchType>(i, MatchType.Exact); |
| } |
| } |
| |
| // throw exception by default |
| throw new FormatException(string.Format("The input string '{0}' could not be parsed to a valid format.", input)); |
| } |
| |
| #endregion |
| |
| #region Implementation of IRollingCondition |
| |
| public bool IsMet(string file) |
| { |
| return IsMet(DateTime.Now); |
| } |
| |
| private static ulong GetUniqueIndex(DateTime now) |
| { |
| ulong result = (ulong)now.DayOfWeek; |
| result <<= 3; |
| result += (ulong)now.Month; |
| result <<= 4; |
| result += (ulong)now.Day; |
| result <<= 5; |
| result += (ulong)now.Hour; |
| result <<= 5; |
| result += (ulong)now.Minute; |
| return result; |
| } |
| |
| #endregion |
| |
| #region Public Methods |
| |
| public bool IsMet(DateTime now) |
| { |
| Console.WriteLine("test {0}", now); |
| // check only every minute |
| // we can skip the check as we checked this minute already |
| // and if we don't we may run into the situation to roll a file twice |
| if (GetUniqueIndex(now) == last_rolled) |
| { |
| Console.WriteLine(" skipped"); |
| return false; |
| } |
| if (!IsMet(Dow, (int)now.DayOfWeek)) |
| { |
| return false; |
| } |
| if (!IsMet(Month, now.Month)) |
| { |
| return false; |
| } |
| if (!IsMet(Day, now.Day)) |
| { |
| return false; |
| } |
| if (!IsMet(Hour, now.Hour)) |
| { |
| return false; |
| } |
| if (!IsMet(Minute, now.Minute)) |
| { |
| return false; |
| } |
| |
| last_rolled = GetUniqueIndex(now); |
| return true; |
| } |
| |
| #endregion |
| |
| #region Private Methods |
| |
| private bool IsMet(Tuple<int?, MatchType> match, int item) |
| { |
| switch (match.Item2) |
| { |
| case MatchType.Exact: |
| Console.WriteLine(" {0} != {1} == {2}", match.Item1.Value, item, match.Item1.Value != item); |
| if (match.Item1.Value != item) |
| { |
| return false; |
| } |
| break; |
| case MatchType.Remainder: |
| // special case: */0, the division through 0 is undefined; this match should pass |
| if (match.Item1.Value == 0) |
| { |
| Console.WriteLine("{0} % 0 == 0", item); |
| return false; |
| } |
| else |
| { |
| Console.WriteLine(" {0} % {1} == {2}", item, match.Item1.Value, item % match.Item1.Value); |
| if (item % match.Item1.Value != 0) |
| { |
| return false; |
| } |
| } |
| break; |
| } |
| return true; |
| } |
| |
| #endregion |
| |
| /// <summary> |
| /// Converts the given rolling condition to a nicely formatted string representation. |
| /// </summary> |
| /// <returns></returns> |
| public override string ToString() |
| { |
| return string.Format("{0} {1} {2} {3} {4}", Dow, Month, Day, Hour, Minute); |
| } |
| } |
| } |