Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Logback: the reliable, generic, fast and flexible logging framework. Copyright (C) 1999-2011, QOS.ch. All rights reserved. This program and the accompanying materials are dual-licensed under either the terms of the Eclipse Public License v1.0 as published by the Eclipse Foundation or (per the licensee's choosing) under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.
 
 package ch.qos.logback.classic.turbo;
 
 import java.io.File;
 import java.net.URL;
 import java.util.List;
 
 
 
 import static ch.qos.logback.core.CoreConstants.MILLIS_IN_ONE_SECOND;

Reconfigure a LoggerContext when the configuration file changes.

Author(s):
Ceki Gulcu
 
 public class ReconfigureOnChangeFilter extends TurboFilter {

  
Scan for changes in configuration file once every minute.
 
   // 1 minute - value mentioned in documentation
   public final static long DEFAULT_REFRESH_PERIOD = 60 * ;
 
   protected volatile long nextCheck;
 
 
   @Override
   public void start() {
      = ConfigurationWatchListUtil.getConfigurationWatchList();
     if ( != null) {
       List<FilewatchList = .getCopyOfFileWatchList();
       long inSeconds =  / 1000;
       addInfo("Will scan for changes in [" + watchList + "] every "
               + inSeconds + " seconds. ");
       synchronized () {
         updateNextCheck(System.currentTimeMillis());
       }
       super.start();
     } else {
       addWarn("Empty ConfigurationWatchList in context");
     }
   }
 
   @Override
   public String toString() {
     return "ReconfigureOnChangeFilter{" +
             "invocationCounter=" +  +
             '}';
   }
 
   // The next fields counts the number of time the decide method is called
   //
   // IMPORTANT: This field can be updated by multiple threads. It follows that
   // its values may *not* be incremented sequentially. However, we don't care
   // about the actual value of the field except that from time to time the
   // expression (invocationCounter++ & mask) == mask) should be true.
   private long invocationCounter = 0;
 
   private volatile long mask = 0xF;
   private volatile long lastMaskCheck = System.currentTimeMillis();
 
 
   @Override
   public FilterReply decide(Marker markerLogger loggerLevel level,
                             String formatObject[] paramsThrowable t) {
     if (!isStarted()) {
       return .;
     }
    // for performance reasons, skip change detection (MASK-1) times out of MASK.
    // Only once every MASK calls is change detection code executed
    // Note that MASK is a variable itself.
    if (((++) & ) != ) {
      return .;
    }
    long now = System.currentTimeMillis();
    synchronized () {
      updateMaskIfNecessary(now);
      if (changeDetected(now)) {
        // Even though reconfiguration involves resetting the loggerContext,
        // which clears the list of turbo filters including this instance, it is
        // still possible for this instance to be subsequently invoked by another
        // thread if it was already executing when the context was reset.
      }
    }
    return .;
  }
  // experiments indicate that even for CPU intensive applications with 200 or more threads MASK
  // values in the order of 0xFFFF is appropriate
  private static final int MAX_MASK = 0xFFFF;
  // if less  than MASK_INCREASE_THRESHOLD milliseconds elapse between invocations of updateMaskIfNecessary() method,
  // then the mask should be increased
  private static final long MASK_INCREASE_THRESHOLD = 100;
  // if more than MASK_DECREASE_THRESHOLD milliseconds elapse between invocations of updateMaskIfNecessary() method,
  // then the mask should be decreased
  private static final long MASK_DECREASE_THRESHOLD = *8;
  // update the mask so as to execute change detection code about once every 100 to 8000 milliseconds.
  private void updateMaskIfNecessary(long now) {
    final long timeElapsedSinceLastMaskUpdateCheck = now - ;
     = now;
    if (timeElapsedSinceLastMaskUpdateCheck <  && ( < )) {
         = ( << 1) | 1;
    } else if (timeElapsedSinceLastMaskUpdateCheck > ) {
       =  >>> 2;
    }
  }
  // by detaching reconfiguration to a new thread, we release the various
  // locks held by the current thread, in particular, the AppenderAttachable
  // reader lock.
  private void detachReconfigurationToNewThread() {
    addInfo("Detected change in [" + .getCopyOfFileWatchList() + "]");
  }
  void updateNextCheck(long now) {
     = now + ;
  }
  protected boolean changeDetected(long now) {
    if (now >= ) {
      updateNextCheck(now);
    }
    return false;
  }
  }
  public long getRefreshPeriod() {
    return ;
  }
  public void setRefreshPeriod(long refreshPeriod) {
    this. = refreshPeriod;
  }
  class ReconfiguringThread implements Runnable {
    public void run() {
      if ( == null) {
        addInfo("Due to missing top level configuration file, skipping reconfiguration");
        return;
      }
      LoggerContext lc = (LoggerContext;
      addInfo(. + "named [" + .getName() + "]");
      if (.toString().endsWith("xml")) {
        performXMLConfiguration(lc);
      } else if (.toString().endsWith("groovy")) {
        if (EnvUtil.isGroovyAvailable()) {
          lc.reset();
          // avoid directly referring to GafferConfigurator so as to avoid
          // loading  groovy.lang.GroovyObject . See also http://jira.qos.ch/browse/LBCLASSIC-214
          GafferUtil.runGafferConfiguratorOn(lcthis);
        } else {
          addError("Groovy classes are not available on the class path. ABORTING INITIALIZATION.");
        }
      }
    }
    private void performXMLConfiguration(LoggerContext lc) {
      JoranConfigurator jc = new JoranConfigurator();
      jc.setContext();
      StatusChecker statusChecker = new StatusChecker();
      List<SaxEventeventList = jc.recallSafeConfiguration();
      URL mainURL = ConfigurationWatchListUtil.getMainWatchURL();
      lc.reset();
      long threshold = System.currentTimeMillis();
      try {
        if (statusChecker.hasXMLParsingErrors(threshold)) {
          fallbackConfiguration(lceventListmainURL);
        }
      } catch (JoranException e) {
        fallbackConfiguration(lceventListmainURL);
      }
    }
    private void fallbackConfiguration(LoggerContext lcList<SaxEventeventListURL mainURL) {
      JoranConfigurator joranConfigurator = new JoranConfigurator();
      joranConfigurator.setContext();
      if (eventList != null) {
        addWarn("Falling back to previously registered safe configuration.");
        try {
          lc.reset();
          joranConfigurator.informContextOfURLUsedForConfiguration(mainURL);
          joranConfigurator.doConfigure(eventList);
          addInfo("Re-registering previous fallback configuration once more as a fallback configuration point");
          joranConfigurator.registerSafeConfiguration();
        } catch (JoranException e) {
          addError("Unexpected exception thrown by a configuration considered safe."e);
        }
      } else {
        addWarn("No previous configuration to fall back to.");
      }
    }
  }
New to GrepCode? Check out our FAQ X