All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cisco.oss.foundation.logging.appender.TimeBasedRoller Maven / Gradle / Ivy

/*
 * Copyright 2015 Cisco Systems, Inc.
 *
 *  Licensed 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.
 */
package com.cisco.oss.foundation.logging.appender;

import org.apache.log4j.helpers.FileHelper;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

import java.io.File;

/**
 * Responsible for rolling at a logging time boundary, as configured by a date
 * pattern.
 * 
 * @author Simon
 *         Park
 * @version 2.6
 */
final class TimeBasedRoller extends AbstractRoller implements FileRollable {

  private final class TimeSample {
    private final long sample;

    TimeSample(long timeInMillis) {
      super();
      this.sample = timeInMillis;
    }

    long getMillis() {
      return this.sample;
    }

    boolean isAtOrAfter(long timeInMillis) {
      return this.sample >= timeInMillis;
    }

    boolean isAtOrAfter(TimeSample other) {
      return (other != null) ? (this.sample >= other.sample) : true;
    }
  }

  private final TimeBasedRollStrategy rollStrategy;

  private TimeSample currentSample;

  private TimeSample previousSample;

  TimeBasedRoller(final FoundationFileRollingAppender rollingAppender,
      final AppenderRollingProperties appenderRollingProperties) {
    super(rollingAppender, appenderRollingProperties);
    TimeBasedRollStrategy rollStrategyEnum = TimeBasedRollStrategy
        .findRollStrategy(appenderRollingProperties);
    if (TimeBasedRollStrategy.ROLL_ERROR.equals(rollStrategyEnum)) {
      rollStrategyEnum = TimeBasedRollStrategy.ROLL_EACH_DAY;
      LogLog.warn("Unable to parse date pattern ["
          + appenderRollingProperties.getDatePattern()
          + "] configured on appender [" + rollingAppender.getName()
          + "], defaulting to roll " + rollStrategyEnum.toString());
    }
    LogLog.debug("Appender [" + rollingAppender.getName() + "] to be rolled "
        + rollStrategyEnum.toString());
    this.rollStrategy = rollStrategyEnum;
    this.currentSample = new TimeSample(System.currentTimeMillis());
    this.initNextRolloverTime();
  }

  /**
   * Not thread-safe.
   * 
   * @see FileRollable#roll(org.apache.log4j.spi.LoggingEvent)
   */
  public final boolean roll(final LoggingEvent loggingEvent) {
    boolean rolled = false;
    this.takeTimeSample(loggingEvent);
    final long nextRolloverTime = this.getNextRolloverTimeMillis();
    if (this.isRolloverDue(nextRolloverTime)) {
      super.roll(this.sampledTime());
      this.updateNextRolloverTime();
      rolled = true;
    }
    this.storeTimeSample();
    return rolled;
  }

  /**
   * For test purposes only.
   * 
   * @return The current strategy.
   */
  final TimeBasedRollStrategy getRollStrategy() {
    return this.rollStrategy;
  }

  private void takeTimeSample(final LoggingEvent loggingEvent) {
    this.currentSample = new TimeSample(loggingEvent.getTimeStamp());
  }

  private long sampledTime() {
    if (this.previousSample == null) {
      final File file = super.getAppender().getIoFile();
      if (FileHelper.getInstance().isReadable(file)) {
        this.previousSample = new TimeSample(file.lastModified());
      } else {
        this.previousSample = this.currentSample;
      }
    }
    return this.previousSample.getMillis();
  }

  /**
   * Allow for a thread to be blocked for a long time before its logging event
   * is actually appended; the timestamp of the current logging event may well
   * precede the timestamp of the last logging event to be appended.
   */
  private void storeTimeSample() {
    if (this.currentSample.isAtOrAfter(this.previousSample)) {
      this.previousSample = this.currentSample;
      this.currentSample = null;
    }
  }

  private long getNextRolloverTimeMillis() {
    return this.getProperties().getNextRollOverTime();
  }

  private void setNextRolloverTimeMillis(final long millis) {
    this.getProperties().setNextRollOverTime(millis);
  }

  private boolean isRolloverDue(final long nextRolloverTime) {
    return this.currentSample.isAtOrAfter(nextRolloverTime);
  }

  private void initNextRolloverTime() {
    this.updateNextRolloverTime();
    final File file = super.getAppender().getIoFile();
    if (FileHelper.getInstance().isReadable(file)) {
      final long thenRolloverTimeMillis = this.rollStrategy
          .nextRollTimeInMillis(file.lastModified());
      /*
       * If the 'rollover point' due *after* the 'file modification date' is
       * before the *next* scheduled 'rollover point' from now, then schedule a
       * rollover by using the *old* 'rollover point'. To put it another way, if
       * the 'file modification date' falls within the current period, just use
       * the *next* scheduled 'rollover point' from now.
       */
      if (thenRolloverTimeMillis < this.getNextRolloverTimeMillis()) {
        this.setNextRolloverTimeMillis(thenRolloverTimeMillis);
      }
    } else {
      this.getAppender()
          .getErrorHandler()
          .error(
              "Unable to initialise next rollover time based upon last"
                  + " modification time of " + String.valueOf(file)
                  + " because the file is not readable");
    }
  }

  private void updateNextRolloverTime() {
    final long nowInMillis = this.currentSample.getMillis();
    final long nextRollMillis = this.rollStrategy
        .nextRollTimeInMillis(nowInMillis);
    this.setNextRolloverTimeMillis(nextRollMillis);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy