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

ch.qos.logback.core.FileAppender Maven / Gradle / Ivy

/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2013, 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.core;

import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

import ch.qos.logback.core.recovery.ResilientFileOutputStream;
import ch.qos.logback.core.util.EnvUtil;
import ch.qos.logback.core.util.FileUtil;

/**
 * FileAppender appends log events to a file.
 *
 * For more information about this appender, please refer to the online manual
 * at http://logback.qos.ch/manual/appenders.html#FileAppender
 *
 * @author Ceki Gülcü
 */
public class FileAppender extends OutputStreamAppender {

  /**
   * Append to or truncate the file? The default value for this variable is
   * true, meaning that by default a FileAppender will
   * append to an existing file and not truncate it.
   */
  protected boolean append = true;

  /**
   * The name of the active log file.
   */
  protected String fileName = null;

  private boolean prudent = false;
  private boolean initialized = false;
  private boolean lazyInit = false;

  /**
   * The File property takes a string value which should be the name of
   * the file to append to.
   * @param file path to destination log file
   */
  public void setFile(String file) {
    if (file == null) {
      fileName = null;
    } else {
      // Trim spaces from both ends. The users probably does not want
      // trailing spaces in file names.
      fileName = file.trim();
    }
  }

  /**
   * Returns the value of the Append property.
   * @return true if file should be appended to instead of overwritten
   */
  public boolean isAppend() {
    return append;
  }

  /**
   * This method is used by derived classes to obtain the raw file property.
   * Regular users should not be calling this method. Note that RollingFilePolicyBase
   * requires public getter for this property.
   *
   * @return the value of the file property
   */
  final public String rawFileProperty() {
    return fileName;
  }

  /**
   * Returns the value of the File property.
   * @return the path to the destination log file
   */
  public String getFile() {
    return fileName;
  }

  /**
   * If the value of File is not null, then
   * {@link #openFile} is called with the values of File and
   * Append properties.
   */
  public void start() {
    int errors = 0;

    // Use getFile() instead of direct access to fileName because
    // the function is overridden in RollingFileAppender, which
    // returns a value that doesn't necessarily match fileName.
    String file = getFile();

    if (file != null) {
      file = getAbsoluteFilePath(file);
      addInfo("File property is set to [" + file + "]");

      if (prudent) {
        if (!isAppend()) {
          setAppend(true);
          addWarn("Setting \"Append\" property to true on account of \"Prudent\" mode");
        }
      }

      if (!lazyInit) {
        try {
          openFile(file);
        } catch (IOException e) {
          errors++;
          addError("openFile(" + file + "," + append + ") failed", e);
        }
      } else {
        // We'll initialize the file output stream later. Use a dummy for now
        // to satisfy OutputStreamAppender.start().
        setOutputStream(new NOPOutputStream());
      }
    } else {
      errors++;
      addError("\"File\" property not set for appender named [" + name + "]");
    }
    if (errors == 0) {
      super.start();
    }
  }

  /**
   * 

* Sets and opens the file where the log output will go. The specified * file must be writable. * *

* If there was already an opened file, then the previous file is closed * first. * *

* Do not use this method directly. To configure a FileAppender or one of * its subclasses, set its properties one by one and then call start(). * * @param filename * The path to the log file. * * @return true if successful; false otherwise * @throws IOException file could not be opened */ protected boolean openFile(String filename) throws IOException { boolean successful = false; filename = getAbsoluteFilePath(filename); synchronized (lock) { File file = new File(filename); if (FileUtil.isParentDirectoryCreationRequired(file)) { boolean result = FileUtil.createMissingParentDirectories(file); if (!result) { addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]"); } } ResilientFileOutputStream resilientFos = new ResilientFileOutputStream( file, append); resilientFos.setContext(context); setOutputStream(resilientFos); successful = true; } return successful; } /** * @see #setPrudent(boolean) * * @return true if in prudent mode */ public boolean isPrudent() { return prudent; } /** * When prudent is set to true, file appenders from multiple JVMs can safely * write to the same file. * * @param prudent whether to enable prudent mode */ public void setPrudent(boolean prudent) { this.prudent = prudent; } public void setAppend(boolean append) { this.append = append; } /** * Gets the enable status of lazy initialization of the file output * stream * * @return true if enabled; false otherwise */ public boolean getLazy() { return lazyInit; } /** * Enables/disables lazy initialization of the file output stream. * This defers the file creation until the first outgoing message. * * @param enable true to enable lazy initialization; false otherwise */ public void setLazy(boolean enable) { lazyInit = enable; } private void safeWrite(E event) throws IOException { ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) getOutputStream(); FileChannel fileChannel = resilientFOS.getChannel(); if (fileChannel == null) { return; } FileLock fileLock = null; try { fileLock = fileChannel.lock(); long position = fileChannel.position(); long size = fileChannel.size(); if (size != position) { fileChannel.position(size); } super.writeOut(event); } finally { if (fileLock != null) { fileLock.release(); } } } @Override protected void writeOut(E event) throws IOException { if (prudent) { safeWrite(event); } else { super.writeOut(event); } } @Override protected void subAppend(E event) { if (!initialized && lazyInit) { initialized = true; try { openFile(getFile()); } catch (IOException e) { this.started = false; addError("openFile(" + fileName + "," + append + ") failed", e); } } super.subAppend(event); } /** * Gets the absolute path to the filename, starting from the app's * "files" directory, if it is not already an absolute path * * @param filename filename to evaluate * @return absolute path to the filename */ private String getAbsoluteFilePath(String filename) { // In Android, relative paths created with File() are relative // to root, so fix it by prefixing the path to the app's "files" // directory. // This transformation is rather expensive, since it involves loading the // Android manifest from the APK (which is a ZIP file), and parsing it to // retrieve the application package name. This should be avoided if // possible as it may perceptibly delay the app launch time. if (EnvUtil.isAndroidOS() && !new File(filename).isAbsolute()) { String dataDir = context.getProperty(CoreConstants.DATA_DIR_KEY); filename = FileUtil.prefixRelativePath(dataDir, filename); } return filename; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy