コード例 #1
0
 /** Parse the additivity option for a non-root category. */
 void parseAdditivityForLogger(Properties props, Logger cat, String loggerName) {
   String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName, props);
   LogLog.debug("Handling " + ADDITIVITY_PREFIX + loggerName + "=[" + value + "]");
   // touch additivity only if necessary
   if ((value != null) && (!value.equals(""))) {
     boolean additivity = OptionConverter.toBoolean(value, true);
     LogLog.debug("Setting additivity for \"" + loggerName + "\" to " + additivity);
     cat.setAdditivity(additivity);
   }
 }
コード例 #2
0
  /**
   * 滚动文件
   *
   * <pre>
   * 1.对文件名带的时间戳进行比较,确定是否更新
   * 2.如果�?��更新,当前文件重命名为:原文件名+日期,重新开始写新的日志文件
   * 3.根据配置的maxBackupIndex,删除过期的文件
   * </pre>
   *
   * @throws IOException Signals that an I/O exception has occurred.
   * @version
   */
  void rollOver() throws IOException {

    String datedFilename = fileName + sdf.format(now);
    // 如果上次写的日期跟当前日期相同,不需要换文件
    if (scheduledFilename.equals(datedFilename)) {
      return;
    }

    // 关闭当前文件,并重命�?
    this.closeFile();

    File target = new File(scheduledFilename);
    if (target.exists()) {
      target.delete();
    }

    File file = new File(fileName);
    boolean result = file.renameTo(target);
    if (result) {
      LogLog.debug(fileName + " -> " + scheduledFilename);
    } else {
      LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");
    }

    // 删除过期文件
    if (maxBackupIndex > 0) {
      File folder = new File(file.getParent());
      List<String> maxBackupIndexDates = getMaxBackupIndexDates();
      for (File ff : folder.listFiles()) { // 遍历目录,将日期不在备份范围内的日志删掉
        if (ff.getName().startsWith(file.getName()) && !ff.getName().equals(file.getName())) {
          // 获取文件名带的日期时间戳
          String markedDate = ff.getName().substring(file.getName().length());
          if (!maxBackupIndexDates.contains(markedDate)) {
            result = ff.delete();
          }
          if (result) {
            LogLog.debug(ff.getName() + " -> deleted ");
          } else {
            LogLog.error("Failed to deleted old DayRollingFileAppender file :" + ff.getName());
          }
        }
      }
    }

    try {
      // 关闭文件,多个关闭操作并行时安装�?
      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
    } catch (IOException e) {
      errorHandler.error("setFile(" + fileName + ", false) call failed.");
    }
    // 更新�?��更新日期�?
    scheduledFilename = datedFilename;
  }
コード例 #3
0
  /** This method must work for the root category as well. */
  void parseCategory(
      Properties props, Logger logger, String optionKey, String loggerName, String value) {

    LogLog.debug("Parsing for [" + loggerName + "] with value=[" + value + "].");
    // We must skip over ',' but not white space
    StringTokenizer st = new StringTokenizer(value, ",");

    // If value is not in the form ", appender.." or "", then we should set
    // the level of the loggeregory.

    if (!(value.startsWith(",") || value.equals(""))) {

      // just to be on the safe side...
      if (!st.hasMoreTokens()) return;

      String levelStr = st.nextToken();
      LogLog.debug("Level token is [" + levelStr + "].");

      // If the level value is inherited, set category level value to
      // null. We also check that the user has not specified inherited for the
      // root category.
      if (INHERITED.equalsIgnoreCase(levelStr) || NULL.equalsIgnoreCase(levelStr)) {
        if (loggerName.equals(INTERNAL_ROOT_NAME)) {
          LogLog.warn("The root logger cannot be set to null.");
        } else {
          logger.setLevel(null);
        }
      } else {
        logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
      }
      LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
    }

    // Begin by removing all existing appenders.
    logger.removeAllAppenders();

    Appender appender;
    String appenderName;
    while (st.hasMoreTokens()) {
      appenderName = st.nextToken().trim();
      if (appenderName == null || appenderName.equals(",")) continue;
      LogLog.debug("Parsing appender named \"" + appenderName + "\".");
      appender = parseAppender(props, appenderName);
      if (appender != null) {
        logger.addAppender(appender);
      }
    }
  }
コード例 #4
0
 /** Read configuration options from url <code>configURL</code>. */
 public void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
   Properties props = new Properties();
   LogLog.debug("Reading configuration from URL " + configURL);
   InputStream istream = null;
   URLConnection uConn = null;
   try {
     uConn = configURL.openConnection();
     uConn.setUseCaches(false);
     istream = uConn.getInputStream();
     props.load(istream);
   } catch (Exception e) {
     if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
       Thread.currentThread().interrupt();
     }
     LogLog.error("Could not read configuration file from URL [" + configURL + "].", e);
     LogLog.error("Ignoring configuration file [" + configURL + "].");
     return;
   } finally {
     if (istream != null) {
       try {
         istream.close();
       } catch (InterruptedIOException ignore) {
         Thread.currentThread().interrupt();
       } catch (IOException ignore) {
       } catch (RuntimeException ignore) {
       }
     }
   }
   doConfigure(props, hierarchy);
 }
コード例 #5
0
  /**
   * Finalize this appender by calling the derived class' <code>close</code> method.
   *
   * @since 0.8.4
   */
  public void finalize() {
    // An appender might be closed then garbage collected. There is no
    // point in closing twice.
    if (this.closed) return;

    LogLog.debug("Finalizing appender named [" + name + "].");
    close();
  }
コード例 #6
0
  /**
   * Implements the usual roll over behaviour.
   *
   * <p>If <code>MaxBackupIndex</code> is positive, then files {<code>File.1</code>, ..., <code>
   * File.MaxBackupIndex -1</code>} are renamed to {<code>File.2</code>, ..., <code>
   * File.MaxBackupIndex</code>}. Moreover, <code>File</code> is renamed <code>File.1</code> and
   * closed. A new <code>File</code> is created to receive further log output.
   *
   * <p>If <code>MaxBackupIndex</code> is equal to zero, then the <code>File</code> is truncated
   * with no backup files created.
   */
  public // synchronization not necessary since doAppend is alreasy synched
  void rollOver() {
    File target;
    File file;

    LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount());
    LogLog.debug("maxBackupIndex=" + maxBackupIndex);

    // If maxBackups <= 0, then there is no file renaming to be done.
    if (maxBackupIndex > 0) {
      // Delete the oldest file, to keep Windows happy.
      file = new File(fileName + '.' + maxBackupIndex);
      if (file.exists()) file.delete();

      // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
      for (int i = maxBackupIndex - 1; i >= 1; i--) {
        file = new File(fileName + "." + i);
        if (file.exists()) {
          target = new File(fileName + '.' + (i + 1));
          LogLog.debug("Renaming file " + file + " to " + target);
          file.renameTo(target);
        }
      }

      // Rename fileName to fileName.1
      target = new File(fileName + "." + 1);

      this.closeFile(); // keep windows happy.

      file = new File(fileName);
      LogLog.debug("Renaming file " + file + " to " + target);
      file.renameTo(target);
    }

    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, false, bufferedIO, bufferSize);
    } catch (IOException e) {
      LogLog.error("setFile(" + fileName + ", false) call failed.", e);
    }
  }
コード例 #7
0
 /**
  * Check the provided <code>Properties</code> object for a {@link
  * org.apache.log4j.spi.LoggerFactory LoggerFactory} entry specified by {@link
  * #LOGGER_FACTORY_KEY}. If such an entry exists, an attempt is made to create an instance using
  * the default constructor. This instance is used for subsequent Category creations within this
  * configurator.
  *
  * @see #parseCatsAndRenderers
  */
 protected void configureLoggerFactory(Properties props) {
   String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY, props);
   if (factoryClassName != null) {
     LogLog.debug("Setting category factory to [" + factoryClassName + "].");
     loggerFactory =
         (LoggerFactory)
             OptionConverter.instantiateByClassName(
                 factoryClassName, LoggerFactory.class, loggerFactory);
     PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
   }
 }
コード例 #8
0
 public void run() {
   while (!isInterrupted()) {
     try {
       ServerSocket serverSocket = new ServerSocket(port);
       while (true) {
         Socket socket = serverSocket.accept();
         LogLog.debug("Connected to client at " + socket.getInetAddress());
         new Thread(new HUPNode(socket, er)).start();
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }
コード例 #9
0
  /**
   * Read configuration options from <code>properties</code>.
   *
   * <p>See {@link #doConfigure(String, LoggerRepository)} for the expected format.
   */
  public void doConfigure(Properties properties, LoggerRepository hierarchy) {
    repository = hierarchy;
    String value = properties.getProperty(LogLog.DEBUG_KEY);
    if (value == null) {
      value = properties.getProperty("log4j.configDebug");
      if (value != null)
        LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
    }

    if (value != null) {
      LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
    }

    //
    //   if log4j.reset=true then
    //        reset hierarchy
    String reset = properties.getProperty(RESET_KEY);
    if (reset != null && OptionConverter.toBoolean(reset, false)) {
      hierarchy.resetConfiguration();
    }

    String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX, properties);
    if (thresholdStr != null) {
      hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, (Level) Level.ALL));
      LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "].");
    }

    configureRootCategory(properties, hierarchy);
    configureLoggerFactory(properties);
    parseCatsAndRenderers(properties, hierarchy);

    LogLog.debug("Finished configuring.");
    // We don't want to hold references to appenders preventing their
    // garbage collection.
    registry.clear();
  }
コード例 #10
0
  /** AppenderSkeleton回调函数, 事件到达时将时间放入Queue. */
  @Override
  public void append(LoggingEvent event) {
    if (queue == null) {
      queue = QueuesHolder.getQueue(queueName);
    }

    boolean sucess = queue.offer(event);

    if (sucess) {
      LogLog.debug(
          "put event to queue success:" + new LoggingEventWrapper(event).convertToString());

    } else {
      LogLog.error("Put event to queue fail:" + new LoggingEventWrapper(event).convertToString());
    }
  }
コード例 #11
0
  void configureRootCategory(Properties props, LoggerRepository hierarchy) {
    String effectiveFrefix = ROOT_LOGGER_PREFIX;
    String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);

    if (value == null) {
      value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
      effectiveFrefix = ROOT_CATEGORY_PREFIX;
    }

    if (value == null) LogLog.debug("Could not find root logger information. Is this OK?");
    else {
      Logger root = hierarchy.getRootLogger();
      synchronized (root) {
        parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
      }
    }
  }
コード例 #12
0
 public void run() {
   try {
     String line = dis.readUTF();
     LogLog.debug("Got external roll over signal.");
     if (ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
       synchronized (er) {
         er.rollOver();
       }
       dos.writeUTF(ExternallyRolledFileAppender.OK);
     } else {
       dos.writeUTF("Expecting [RollOver] string.");
     }
     dos.close();
   } catch (Exception e) {
     LogLog.error("Unexpected exception. Exiting HUPNode.", e);
   }
 }
コード例 #13
0
  public void activateOptions() {
    LogLog.debug("DBAppender.activateOptions called");

    if (connectionSource == null) {
      throw new IllegalStateException("DBAppender cannot function without a connection source");
    }

    sqlDialect = Util.getDialectFromCode(connectionSource.getSQLDialectCode());
    if (GET_GENERATED_KEYS_METHOD != null) {
      cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
    } else {
      cnxSupportsGetGeneratedKeys = false;
    }
    cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
    if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
      throw new IllegalStateException(
          "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
    }

    // all nice and dandy on the eastern front
    super.activateOptions();
  }
コード例 #14
0
ファイル: CalendarFileAppender.java プロジェクト: gugu-lee/as
 void printPeriodicity(int type) {
   switch (type) {
     case TOP_OF_MINUTE:
       LogLog.debug("Appender [" + name + "] to be rolled every minute.");
       break;
     case TOP_OF_HOUR:
       LogLog.debug("Appender [" + name + "] to be rolled on top of every hour.");
       break;
     case HALF_DAY:
       LogLog.debug("Appender [" + name + "] to be rolled at midday and midnight.");
       break;
     case TOP_OF_DAY:
       LogLog.debug("Appender [" + name + "] to be rolled at midnight.");
       break;
     case TOP_OF_WEEK:
       LogLog.debug("Appender [" + name + "] to be rolled at start of week.");
       break;
     case TOP_OF_MONTH:
       LogLog.debug("Appender [" + name + "] to be rolled at start of every month.");
       break;
     default:
       LogLog.warn("Unknown periodicity for appender [" + name + "].");
   }
 }
コード例 #15
0
  void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
    // extract filters and filter options from props into a hashtable mapping
    // the property name defining the filter class to a list of pre-parsed
    // name-value pairs associated to that filter
    final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
    int fIdx = filterPrefix.length();
    Hashtable filters = new Hashtable();
    Enumeration e = props.keys();
    String name = "";
    while (e.hasMoreElements()) {
      String key = (String) e.nextElement();
      if (key.startsWith(filterPrefix)) {
        int dotIdx = key.indexOf('.', fIdx);
        String filterKey = key;
        if (dotIdx != -1) {
          filterKey = key.substring(0, dotIdx);
          name = key.substring(dotIdx + 1);
        }
        Vector filterOpts = (Vector) filters.get(filterKey);
        if (filterOpts == null) {
          filterOpts = new Vector();
          filters.put(filterKey, filterOpts);
        }
        if (dotIdx != -1) {
          String value = OptionConverter.findAndSubst(key, props);
          filterOpts.add(new NameValue(name, value));
        }
      }
    }

    // sort filters by IDs, insantiate filters, set filter options,
    // add filters to the appender
    Enumeration g = new SortedKeyEnumeration(filters);
    while (g.hasMoreElements()) {
      String key = (String) g.nextElement();
      String clazz = props.getProperty(key);
      if (clazz != null) {
        LogLog.debug(
            "Filter key: ["
                + key
                + "] class: ["
                + props.getProperty(key)
                + "] props: "
                + filters.get(key));
        Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
        if (filter != null) {
          PropertySetter propSetter = new PropertySetter(filter);
          Vector v = (Vector) filters.get(key);
          Enumeration filterProps = v.elements();
          while (filterProps.hasMoreElements()) {
            NameValue kv = (NameValue) filterProps.nextElement();
            propSetter.setProperty(kv.key, kv.value);
          }
          propSetter.activate();
          LogLog.debug(
              "Adding filter of type ["
                  + filter.getClass()
                  + "] to appender named ["
                  + appender.getName()
                  + "].");
          appender.addFilter(filter);
        }
      } else {
        LogLog.warn("Missing class definition for filter: [" + key + "]");
      }
    }
  }
コード例 #16
0
  Appender parseAppender(Properties props, String appenderName) {
    Appender appender = registryGet(appenderName);
    if ((appender != null)) {
      LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
      return appender;
    }
    // Appender was not previously initialized.
    String prefix = APPENDER_PREFIX + appenderName;
    String layoutPrefix = prefix + ".layout";

    appender =
        (Appender)
            OptionConverter.instantiateByKey(props, prefix, org.apache.log4j.Appender.class, null);
    if (appender == null) {
      LogLog.error("Could not instantiate appender named \"" + appenderName + "\".");
      return null;
    }
    appender.setName(appenderName);

    if (appender instanceof OptionHandler) {
      if (appender.requiresLayout()) {
        Layout layout =
            (Layout) OptionConverter.instantiateByKey(props, layoutPrefix, Layout.class, null);
        if (layout != null) {
          appender.setLayout(layout);
          LogLog.debug("Parsing layout options for \"" + appenderName + "\".");
          // configureOptionHandler(layout, layoutPrefix + ".", props);
          PropertySetter.setProperties(layout, props, layoutPrefix + ".");
          LogLog.debug("End of parsing for \"" + appenderName + "\".");
        }
      }
      final String errorHandlerPrefix = prefix + ".errorhandler";
      String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
      if (errorHandlerClass != null) {
        ErrorHandler eh =
            (ErrorHandler)
                OptionConverter.instantiateByKey(
                    props, errorHandlerPrefix, ErrorHandler.class, null);
        if (eh != null) {
          appender.setErrorHandler(eh);
          LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\".");
          parseErrorHandler(eh, errorHandlerPrefix, props, repository);
          final Properties edited = new Properties();
          final String[] keys =
              new String[] {
                errorHandlerPrefix + "." + ROOT_REF,
                errorHandlerPrefix + "." + LOGGER_REF,
                errorHandlerPrefix + "." + APPENDER_REF_TAG
              };
          for (Iterator iter = props.entrySet().iterator(); iter.hasNext(); ) {
            Map.Entry entry = (Map.Entry) iter.next();
            int i = 0;
            for (; i < keys.length; i++) {
              if (keys[i].equals(entry.getKey())) break;
            }
            if (i == keys.length) {
              edited.put(entry.getKey(), entry.getValue());
            }
          }
          PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
          LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\".");
        }
      }
      // configureOptionHandler((OptionHandler) appender, prefix + ".", props);
      PropertySetter.setProperties(appender, props, prefix + ".");
      LogLog.debug("Parsed \"" + appenderName + "\" options.");
    }
    parseAppenderFilters(props, appenderName, appender);
    registryPut(appender);
    return appender;
  }
コード例 #17
0
 /** @param connectionSource The connectionSource to set. */
 public void setConnectionSource(ConnectionSource connectionSource) {
   LogLog.debug("setConnectionSource called for DBAppender");
   this.connectionSource = connectionSource;
 }
コード例 #18
0
  protected void append(LoggingEvent event) {
    Connection connection = null;
    try {
      connection = connectionSource.getConnection();
      connection.setAutoCommit(false);

      PreparedStatement insertStatement;
      if (cnxSupportsGetGeneratedKeys) {
        insertStatement = connection.prepareStatement(insertSQL, Statement.RETURN_GENERATED_KEYS);
      } else {
        insertStatement = connection.prepareStatement(insertSQL);
      }

      /*          insertStatement.setLong(1, event.getSequenceNumber());*/
      insertStatement.setLong(1, 0);

      insertStatement.setLong(2, event.getTimeStamp());
      insertStatement.setString(3, event.getRenderedMessage());
      insertStatement.setString(4, event.getLoggerName());
      insertStatement.setString(5, event.getLevel().toString());
      insertStatement.setString(6, event.getNDC());
      insertStatement.setString(7, event.getThreadName());
      insertStatement.setShort(8, DBHelper.computeReferenceMask(event));

      LocationInfo li;

      if (event.locationInformationExists() || locationInfo) {
        li = event.getLocationInformation();
      } else {
        li = LocationInfo.NA_LOCATION_INFO;
      }

      insertStatement.setString(9, li.getFileName());
      insertStatement.setString(10, li.getClassName());
      insertStatement.setString(11, li.getMethodName());
      insertStatement.setString(12, li.getLineNumber());

      int updateCount = insertStatement.executeUpdate();
      if (updateCount != 1) {
        LogLog.warn("Failed to insert loggingEvent");
      }

      ResultSet rs = null;
      Statement idStatement = null;
      boolean gotGeneratedKeys = false;
      if (cnxSupportsGetGeneratedKeys) {
        try {
          rs = (ResultSet) GET_GENERATED_KEYS_METHOD.invoke(insertStatement, null);
          gotGeneratedKeys = true;
        } catch (InvocationTargetException ex) {
          Throwable target = ex.getTargetException();
          if (target instanceof SQLException) {
            throw (SQLException) target;
          }
          throw ex;
        } catch (IllegalAccessException ex) {
          LogLog.warn("IllegalAccessException invoking PreparedStatement.getGeneratedKeys", ex);
        }
      }

      if (!gotGeneratedKeys) {
        insertStatement.close();
        insertStatement = null;

        idStatement = connection.createStatement();
        idStatement.setMaxRows(1);
        rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
      }

      // A ResultSet cursor is initially positioned before the first row; the
      // first call to the method next makes the first row the current row
      rs.next();
      int eventId = rs.getInt(1);

      rs.close();

      // we no longer need the insertStatement
      if (insertStatement != null) {
        insertStatement.close();
        insertStatement = null;
      }

      if (idStatement != null) {
        idStatement.close();
        idStatement = null;
      }

      Set propertiesKeys = event.getPropertyKeySet();

      if (propertiesKeys.size() > 0) {
        PreparedStatement insertPropertiesStatement =
            connection.prepareStatement(insertPropertiesSQL);

        for (Iterator i = propertiesKeys.iterator(); i.hasNext(); ) {
          String key = (String) i.next();
          String value = event.getProperty(key);

          // LogLog.info("id " + eventId + ", key " + key + ", value " + value);
          insertPropertiesStatement.setInt(1, eventId);
          insertPropertiesStatement.setString(2, key);
          insertPropertiesStatement.setString(3, value);

          if (cnxSupportsBatchUpdates) {
            insertPropertiesStatement.addBatch();
          } else {
            insertPropertiesStatement.execute();
          }
        }

        if (cnxSupportsBatchUpdates) {
          insertPropertiesStatement.executeBatch();
        }

        insertPropertiesStatement.close();
        insertPropertiesStatement = null;
      }

      String[] strRep = event.getThrowableStrRep();

      if (strRep != null) {
        LogLog.debug("Logging an exception");

        PreparedStatement insertExceptionStatement =
            connection.prepareStatement(insertExceptionSQL);

        for (short i = 0; i < strRep.length; i++) {
          insertExceptionStatement.setInt(1, eventId);
          insertExceptionStatement.setShort(2, i);
          insertExceptionStatement.setString(3, strRep[i]);
          if (cnxSupportsBatchUpdates) {
            insertExceptionStatement.addBatch();
          } else {
            insertExceptionStatement.execute();
          }
        }
        if (cnxSupportsBatchUpdates) {
          insertExceptionStatement.executeBatch();
        }
        insertExceptionStatement.close();
        insertExceptionStatement = null;
      }

      connection.commit();
    } catch (Throwable sqle) {
      LogLog.error("problem appending event", sqle);
    } finally {
      DBHelper.closeConnection(connection);
    }
  }
コード例 #19
0
ファイル: CalendarFileAppender.java プロジェクト: gugu-lee/as
  /**
   * Implements the usual roll over behaviour.
   *
   * <p>If <code>MaxBackupIndex</code> is positive, then files { <code>File.1</code>, ..., <code>
   * File.MaxBackupIndex -1</code> are renamed to {<code>File.2</code>, ..., <code>
   * File.MaxBackupIndex</code> . Moreover, <code>File</code> is renamed <code>File.1</code> and
   * closed. A new <code>File</code> is created to receive further log output.
   *
   * <p>If <code>MaxBackupIndex</code> is equal to zero, then the <code>File</code> is truncated
   * with no backup files created.
   */
  public // synchronization not necessary since doAppend is alreasy synched
  void rollOver(int rolltype) throws IOException {
    //
    if (RollingFileType == rolltype) {
      File target;
      File file;
      LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount());
      LogLog.debug("maxBackupIndex=" + maxBackupIndex);

      // If maxBackups <= 0, then there is no file renaming to be done.
      if (maxBackupIndex > 0) {
        file = new File(buildLogFilePathAnddeleteTimeoutFile(maxBackupIndex));
        if (file.exists()) file.delete();
        // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex,
        // ..., 3, 2}
        for (int i = maxBackupIndex - 1; i >= 1; i--) {
          file = new File(buildLogFilePathAnddeleteTimeoutFile(i));
          if (file.exists()) {
            target = new File(buildLogFilePathAnddeleteTimeoutFile(i + 1));
            LogLog.debug("Renaming file " + file + " to " + target);
            file.renameTo(target);
          }
        }

        // Rename fileName to fileName.1
        target = new File(buildLogFilePathAnddeleteTimeoutFile(1));

        this.closeFile(); // keep windows happy.

        file = new File(fileName);
        LogLog.debug("Renaming file " + file + " to " + target);
        file.renameTo(target);
      }

      try {
        // This will also close the file. This is OK since multiple
        // close operations are safe.
        this.setFile(fileName, false, bufferedIO, bufferSize);
      } catch (IOException e) {
        LogLog.error("setFile(" + fileName + ", false) call failed.", e);
      }
    } else if (DailyRollingFileType == rolltype) {
      /* Compute filename, but only if datePattern is specified */
      if (datePattern == null) {
        errorHandler.error("Missing DatePattern option in rollOver().");
        return;
      }
      String datedFile = sdf.format(now);
      // It is too early to roll over because we are still within the
      // bounds of the current interval. Rollover will occur once the
      // next interval is reached.
      if (scheduledDate.equals(datedFile)) {
        return;
      }
      // close current file, and rename it to datedFilename
      this.closeFile();
      String targetfilename = buildLogFilePathAnddeleteTimeoutFile(-1);

      fileName = targetfilename;

      try {
        // This will also close the file. This is OK since multiple
        // close operations are safe.
        this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
      } catch (IOException e) {
        errorHandler.error("setFile(" + fileName + ", false) call failed.");
      }
      scheduledDate = datedFile;
    }
  }