Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Java/Tomcat/java/org/apache/catalina/valves/   (Apache Software Stiftung Version 2.4.65©)  Datei vom 10.10.2023 mit Größe 20 kB image not shown  

Quelle  AccessLogValve.java   Sprache: JAVA

 
/*
 * 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.
 */

package org.apache.catalina.valves;


import java.io.BufferedWriter;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.catalina.LifecycleException;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.buf.B2CConverter;


/**
 * This is a concrete implementation of {@link AbstractAccessLogValve} that outputs the access log to a file. The
 * features of this implementation include:
 * <ul>
 * <li>Automatic date-based rollover of log files</li>
 * <li>Optional log file rotation</li>
 * </ul>
 * <p>
 * For UNIX users, another field called <code>checkExists</code> is also available. If set to true, the log file's
 * existence will be checked before each logging. This way an external log rotator can move the file somewhere and
 * Tomcat will start with a new file.
 * </p>
 * <p>
 * For JMX junkies, a public method called <code>rotate</code> has been made available to allow you to tell this
 * instance to move the existing log file to somewhere else and start writing a new log file.
 * </p>
 */

public class AccessLogValve extends AbstractAccessLogValve {

    private static final Log log = LogFactory.getLog(AccessLogValve.class);

    // ------------------------------------------------------ Constructor
    public AccessLogValve() {
        super();
    }

    // ----------------------------------------------------- Instance Variables


    /**
     * The as-of date for the currently open log file, or a zero-length string if there is no open log file.
     */

    private volatile String dateStamp = "";


    /**
     * The directory in which log files are created.
     */

    private String directory = "logs";

    /**
     * The prefix that is added to log file filenames.
     */

    protected volatile String prefix = "access_log";


    /**
     * Should we rotate our log file? Default is true (like old behavior)
     */

    protected boolean rotatable = true;

    /**
     * Should we defer inclusion of the date stamp in the file name until rotate time? Default is false.
     */

    protected boolean renameOnRotate = false;


    /**
     * Buffered logging.
     */

    private boolean buffered = true;


    /**
     * The suffix that is added to log file filenames.
     */

    protected volatile String suffix = "";


    /**
     * The PrintWriter to which we are currently logging, if any.
     */

    protected PrintWriter writer = null;


    /**
     * A date formatter to format a Date using the format given by <code>fileDateFormat</code>.
     */

    protected SimpleDateFormat fileDateFormatter = null;


    /**
     * The current log file we are writing to. Helpful when checkExists is true.
     */

    protected File currentLogFile = null;

    /**
     * Instant when the log daily rotation was last checked.
     */

    private volatile long rotationLastChecked = 0L;

    /**
     * Do we check for log file existence? Helpful if an external agent renames the log file so we can automagically
     * recreate it.
     */

    private boolean checkExists = false;

    /**
     * Date format to place in log file name.
     */

    protected String fileDateFormat = ".yyyy-MM-dd";

    /**
     * Character set used by the log file. If it is <code>null</code>, UTF-8 will be used. An empty string will be
     * treated as <code>null</code> when this property is assigned.
     */

    protected volatile String encoding = null;

    /**
     * The number of days to retain the access log files before they are removed.
     */

    private int maxDays = -1;
    private volatile boolean checkForOldLogs = false;

    // ------------------------------------------------------------- Properties


    public int getMaxDays() {
        return maxDays;
    }


    public void setMaxDays(int maxDays) {
        this.maxDays = maxDays;
    }


    /**
     * @return the directory in which we create log files.
     */

    public String getDirectory() {
        return directory;
    }


    /**
     * Set the directory in which we create log files.
     *
     * @param directory The new log file directory
     */

    public void setDirectory(String directory) {
        this.directory = directory;
    }

    /**
     * Check for file existence before logging.
     *
     * @return <code>true</code> if file existence is checked first
     */

    public boolean isCheckExists() {

        return checkExists;

    }


    /**
     * Set whether to check for log file existence before logging.
     *
     * @param checkExists true meaning to check for file existence.
     */

    public void setCheckExists(boolean checkExists) {

        this.checkExists = checkExists;

    }


    /**
     * @return the log file prefix.
     */

    public String getPrefix() {
        return prefix;
    }


    /**
     * Set the log file prefix.
     *
     * @param prefix The new log file prefix
     */

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }


    /**
     * Should we rotate the access log.
     *
     * @return <code>true</code> if the access log should be rotated
     */

    public boolean isRotatable() {
        return rotatable;
    }


    /**
     * Configure whether the access log should be rotated.
     *
     * @param rotatable true if the log should be rotated
     */

    public void setRotatable(boolean rotatable) {
        this.rotatable = rotatable;
    }


    /**
     * Should we defer inclusion of the date stamp in the file name until rotate time.
     *
     * @return <code>true</code> if the logs file names are time stamped only when they are rotated
     */

    public boolean isRenameOnRotate() {
        return renameOnRotate;
    }


    /**
     * Set the value if we should defer inclusion of the date stamp in the file name until rotate time
     *
     * @param renameOnRotate true if defer inclusion of date stamp
     */

    public void setRenameOnRotate(boolean renameOnRotate) {
        this.renameOnRotate = renameOnRotate;
    }


    /**
     * Is the logging buffered. Usually buffering can increase performance.
     *
     * @return <code>true</code> if the logging uses a buffer
     */

    public boolean isBuffered() {
        return buffered;
    }


    /**
     * Set the value if the logging should be buffered
     *
     * @param buffered <code>true</code> if buffered.
     */

    public void setBuffered(boolean buffered) {
        this.buffered = buffered;
    }


    /**
     * @return the log file suffix.
     */

    public String getSuffix() {
        return suffix;
    }


    /**
     * Set the log file suffix.
     *
     * @param suffix The new log file suffix
     */

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    /**
     * @return the date format date based log rotation.
     */

    public String getFileDateFormat() {
        return fileDateFormat;
    }


    /**
     * Set the date format date based log rotation.
     *
     * @param fileDateFormat The format for the file timestamp
     */

    public void setFileDateFormat(String fileDateFormat) {
        String newFormat;
        if (fileDateFormat == null) {
            newFormat = "";
        } else {
            newFormat = fileDateFormat;
        }
        this.fileDateFormat = newFormat;

        synchronized (this) {
            fileDateFormatter = new SimpleDateFormat(newFormat, Locale.US);
            fileDateFormatter.setTimeZone(TimeZone.getDefault());
        }
    }

    /**
     * Return the character set name that is used to write the log file.
     *
     * @return Character set name, or <code>null</code> if the default character set is used.
     */

    public String getEncoding() {
        return encoding;
    }

    /**
     * Set the character set that is used to write the log file.
     *
     * @param encoding The name of the character set.
     */

    public void setEncoding(String encoding) {
        if (encoding != null && encoding.length() > 0) {
            this.encoding = encoding;
        } else {
            this.encoding = null;
        }
    }

    // --------------------------------------------------------- Public Methods

    /**
     * Execute a periodic task, such as reloading, etc. This method will be invoked inside the classloading context of
     * this container. Unexpected throwables will be caught and logged.
     */

    @Override
    public synchronized void backgroundProcess() {
        if (getState().isAvailable() && getEnabled() && writer != null && buffered) {
            writer.flush();
        }

        int maxDays = this.maxDays;
        String prefix = this.prefix;
        String suffix = this.suffix;

        if (rotatable && checkForOldLogs && maxDays > 0) {
            long deleteIfLastModifiedBefore = System.currentTimeMillis() - (maxDays * 24L * 60 * 60 * 1000);
            File dir = getDirectoryFile();
            if (dir.isDirectory()) {
                String[] oldAccessLogs = dir.list();

                if (oldAccessLogs != null) {
                    for (String oldAccessLog : oldAccessLogs) {
                        boolean match = false;

                        if (prefix != null && prefix.length() > 0) {
                            if (!oldAccessLog.startsWith(prefix)) {
                                continue;
                            }
                            match = true;
                        }

                        if (suffix != null && suffix.length() > 0) {
                            if (!oldAccessLog.endsWith(suffix)) {
                                continue;
                            }
                            match = true;
                        }

                        if (match) {
                            File file = new File(dir, oldAccessLog);
                            if (file.isFile() && file.lastModified() < deleteIfLastModifiedBefore) {
                                if (!file.delete()) {
                                    log.warn(sm.getString("accessLogValve.deleteFail", file.getAbsolutePath()));
                                }
                            }
                        }
                    }
                }
            }
            checkForOldLogs = false;
        }
    }

    /**
     * Rotate the log file if necessary.
     */

    public void rotate() {
        if (rotatable) {
            // Only do a logfile switch check once a second, max.
            long systime = System.currentTimeMillis();
            if ((systime - rotationLastChecked) > 1000) {
                synchronized (this) {
                    if ((systime - rotationLastChecked) > 1000) {
                        rotationLastChecked = systime;

                        String tsDate;
                        // Check for a change of date
                        tsDate = fileDateFormatter.format(new Date(systime));

                        // If the date has changed, switch log files
                        if (!dateStamp.equals(tsDate)) {
                            close(true);
                            dateStamp = tsDate;
                            open();
                        }
                    }
                }
            }
        }
    }

    /**
     * Rename the existing log file to something else. Then open the old log file name up once again. Intended to be
     * called by a JMX agent.
     *
     * @param newFileName The file name to move the log file entry to
     *
     * @return true if a file was rotated with no error
     */

    public synchronized boolean rotate(String newFileName) {

        if (currentLogFile != null) {
            File holder = currentLogFile;
            close(false);
            try {
                holder.renameTo(new File(newFileName));
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                log.error(sm.getString("accessLogValve.rotateFail"), e);
            }

            /* Make sure date is correct */
            dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis()));

            open();
            return true;
        } else {
            return false;
        }

    }

    // -------------------------------------------------------- Private Methods


    private File getDirectoryFile() {
        File dir = new File(directory);
        if (!dir.isAbsolute()) {
            dir = new File(getContainer().getCatalinaBase(), directory);
        }
        return dir;
    }


    /**
     * Create a File object based on the current log file name. Directories are created as needed but the underlying
     * file is not created or opened.
     *
     * @param useDateStamp include the timestamp in the file name.
     *
     * @return the log file object
     */

    private File getLogFile(boolean useDateStamp) {
        // Create the directory if necessary
        File dir = getDirectoryFile();
        if (!dir.mkdirs() && !dir.isDirectory()) {
            log.error(sm.getString("accessLogValve.openDirFail", dir));
        }

        // Calculate the current log file name
        File pathname;
        if (useDateStamp) {
            pathname = new File(dir.getAbsoluteFile(), prefix + dateStamp + suffix);
        } else {
            pathname = new File(dir.getAbsoluteFile(), prefix + suffix);
        }
        File parent = pathname.getParentFile();
        if (!parent.mkdirs() && !parent.isDirectory()) {
            log.error(sm.getString("accessLogValve.openDirFail", parent));
        }
        return pathname;
    }

    /**
     * Move a current but rotated log file back to the unrotated one. Needed if date stamp inclusion is deferred to
     * rotation time.
     */

    private void restore() {
        File newLogFile = getLogFile(false);
        File rotatedLogFile = getLogFile(true);
        if (rotatedLogFile.exists() && !newLogFile.exists() && !rotatedLogFile.equals(newLogFile)) {
            try {
                if (!rotatedLogFile.renameTo(newLogFile)) {
                    log.error(sm.getString("accessLogValve.renameFail", rotatedLogFile, newLogFile));
                }
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                log.error(sm.getString("accessLogValve.renameFail", rotatedLogFile, newLogFile), e);
            }
        }
    }


    /**
     * Close the currently open log file (if any)
     *
     * @param rename Rename file to final name after closing
     */

    private synchronized void close(boolean rename) {
        if (writer == null) {
            return;
        }
        writer.flush();
        writer.close();
        if (rename && renameOnRotate) {
            File newLogFile = getLogFile(true);
            if (!newLogFile.exists()) {
                try {
                    if (!currentLogFile.renameTo(newLogFile)) {
                        log.error(sm.getString("accessLogValve.renameFail", currentLogFile, newLogFile));
                    }
                } catch (Throwable e) {
                    ExceptionUtils.handleThrowable(e);
                    log.error(sm.getString("accessLogValve.renameFail", currentLogFile, newLogFile), e);
                }
            } else {
                log.error(sm.getString("accessLogValve.alreadyExists", currentLogFile, newLogFile));
            }
        }
        writer = null;
        dateStamp = "";
        currentLogFile = null;
    }


    /**
     * Log the specified message to the log file, switching files if the date has changed since the previous log call.
     *
     * @param message Message to be logged
     */

    @Override
    public void log(CharArrayWriter message) {

        rotate();

        /* In case something external rotated the file instead */
        if (checkExists) {
            synchronized (this) {
                if (currentLogFile != null && !currentLogFile.exists()) {
                    try {
                        close(false);
                    } catch (Throwable e) {
                        ExceptionUtils.handleThrowable(e);
                        log.info(sm.getString("accessLogValve.closeFail"), e);
                    }

                    /* Make sure date is correct */
                    dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis()));

                    open();
                }
            }
        }

        // Log this message
        try {
            message.write(System.lineSeparator());
            synchronized (this) {
                if (writer != null) {
                    message.writeTo(writer);
                    if (!buffered) {
                        writer.flush();
                    }
                }
            }
        } catch (IOException ioe) {
            log.warn(sm.getString("accessLogValve.writeFail", message.toString()), ioe);
        }
    }


    /**
     * Open the new log file for the date specified by <code>dateStamp</code>.
     */

    protected synchronized void open() {
        // Open the current log file
        // If no rotate - no need for dateStamp in fileName
        File pathname = getLogFile(rotatable && !renameOnRotate);

        Charset charset = null;
        if (encoding != null) {
            try {
                charset = B2CConverter.getCharset(encoding);
            } catch (UnsupportedEncodingException ex) {
                log.error(sm.getString("accessLogValve.unsupportedEncoding", encoding), ex);
            }
        }
        if (charset == null) {
            charset = StandardCharsets.UTF_8;
        }

        try {
            writer = new PrintWriter(
                    new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pathname, true), charset), 128000),
                    false);

            currentLogFile = pathname;
        } catch (IOException e) {
            writer = null;
            currentLogFile = null;
            log.error(sm.getString("accessLogValve.openFail", pathname, System.getProperty("user.name")), e);
        }
        // Rotating a log file will always trigger a new file to be opened so
        // when a new file is opened, check to see if any old files need to be
        // removed.
        checkForOldLogs = true;
    }

    /**
     * Start this component and implement the requirements of
     * {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error that prevents this component from being
     *                                   used
     */

    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // Initialize the Date formatters
        String format = getFileDateFormat();
        fileDateFormatter = new SimpleDateFormat(format, Locale.US);
        fileDateFormatter.setTimeZone(TimeZone.getDefault());
        dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis()));
        if (rotatable && renameOnRotate) {
            restore();
        }
        open();

        super.startInternal();
    }


    /**
     * Stop this component and implement the requirements of
     * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error that prevents this component from being
     *                                   used
     */

    @Override
    protected synchronized void stopInternal() throws LifecycleException {

        super.stopInternal();
        close(false);
    }
}

Messung V0.5
C=93 H=89 G=90

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.