/* * 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.synapse.transport.http.access; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.commons.util.MiscellaneousUtil; /** * Class that logs the Http Accesses to the access log files. Code segment borrowed from * Apache Tomcat's org.apache.catalina.valves.AccessLogValve with thanks. */ public class AccessLogger { /** The name of the system property used to specify/override the nhttp properties location */ public static final String NHTTP_PROPERTIES = "nhttp.properties"; //property name of nhttp log directory public static final String NHTTP_LOG_DIRECTORY = "nhttp.log.directory"; public final static String ACCESS_LOG_ID = "org.apache.synapse.transport.nhttp.access"; private static Log log = LogFactory.getLog(ACCESS_LOG_ID); public AccessLogger(final Log log) { super(); this.initOpen(); AccessLogger.log = log; buffered = true; checkExists = false; } /** * A date formatter to format a Date into a date in the given file format */ protected SimpleDateFormat fileDateFormatter = new SimpleDateFormat(AccessConstants.getFileDateFormat()); /** * The PrintWriter to which we are currently logging, if any. */ protected PrintWriter writer; /** * 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 = ""; /** * Instant when the log daily rotation was last checked. */ private volatile long rotationLastChecked = 0L; /** * Buffered logging. */ private boolean buffered = true; /** * Do we check for log file existence? Helpful if an external * agent renames the log file so we can automatically recreate it. */ private boolean checkExists = false; /** * The current log file we are writing to. Helpful when checkExists * is true. */ protected File currentLogFile = null; /** * Can the log file be rotated. */ protected boolean isRotatable = true; /** * 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 */ public void log(String message) { if (isRotatable) { // 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(); dateStamp = tsDate; open(); } } } } } /* In case something external rotated the file instead */ if (checkExists) { synchronized (this) { if (currentLogFile != null && !currentLogFile.exists()) { try { close(); } catch (Throwable e) { handleThrowable(e); log.info("Access Log file Close failed"); } /* Make sure date is correct */ dateStamp = fileDateFormatter.format( new Date(System.currentTimeMillis())); open(); } } } // Log this message synchronized (this) { if (writer != null) { writer.println(message); if (!buffered) { writer.flush(); } } } } protected synchronized void initOpen() { /* Make sure date is correct */ dateStamp = fileDateFormatter.format( new Date(System.currentTimeMillis())); this.open(); } /** * Open the new log file for the date specified by <code>dateStamp</code>. */ protected synchronized void open() { // Create the directory if necessary File dir; Properties synapseProps = MiscellaneousUtil.loadProperties(NHTTP_PROPERTIES); String nhttpLogDir = synapseProps.getProperty(NHTTP_LOG_DIRECTORY); if (nhttpLogDir != null) { dir = new File(nhttpLogDir); } else { dir = new File(AccessConstants.getDirectory()); } if (!dir.exists()) { if (!dir.mkdirs()) { log.error("Access Log Open Directory Failed"); } } // Open the current log file try { String pathname; // If no rotate - no need for dateStamp in fileName if (isRotatable) { pathname = dir.getAbsolutePath() + File.separator + AccessConstants.getPrefix() + dateStamp + AccessConstants.getSuffix(); } else { pathname = dir.getAbsolutePath() + File.separator + AccessConstants.getPrefix() + AccessConstants.getSuffix(); } writer = new PrintWriter(new BufferedWriter(new FileWriter( pathname, true), 128000), true); currentLogFile = new File(pathname); } catch (IOException e) { log.warn("Unable to open the print writer", e); writer = null; currentLogFile = null; } } /** * Close the currently open log file (if any) */ synchronized void close() { if (writer == null) { return; } writer.flush(); writer.close(); writer = null; dateStamp = ""; currentLogFile = null; } /** * Checks whether the supplied Throwable is one that needs to be * re-thrown and swallows all others. * * @param t the Throwable to check */ public static void handleThrowable(Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } // All other instances of Throwable will be silently swallowed } }