Hi all,

This is my first post to this list. I have created a
LoggerAppenderDailyRollingFile appender for a project that I'm working
on. This is needed there because I have a long-lived PHP process that
would otherwise not rotate the logfile. It is also possible to rotate
log files once every hour or even minute if needed, by setting the
'rotate' property appropriately. This is illustrated in the
configuration example below:

log4php.appender.logfile = LoggerAppenderDailyRollingFile
log4php.appender.logfile.layout = LoggerLayoutTTCC
log4php.appender.logfile.rotate = i
log4php.appender.logfile.datePattern = Ymd-Hi

The attached patch file is against 2.2.0/src/main/php. Would you
consider this appender useful for the general public and include in
the project?

Cheers,
Vik
diff -Nur log4php-2.2.0.orig/appenders/LoggerAppenderDailyRollingFile.php log4php-2.2.0/appenders/LoggerAppenderDailyRollingFile.php
--- log4php-2.2.0.orig/appenders/LoggerAppenderDailyRollingFile.php	1970-01-01 01:00:00.000000000 +0100
+++ log4php-2.2.0/appenders/LoggerAppenderDailyRollingFile.php	2012-01-13 14:01:35.000000000 +0100
@@ -0,0 +1,172 @@
+<?php
+/**
+ * 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 log4php
+ */
+
+/**
+ * An Appender that automatically creates a new logfile each day (by default),
+ * even for long-lived PHP processes.
+ *
+ * The file is rolled over once a day. That means, for each day a new file 
+ * is created. A formatted version of the date pattern is used as to create 
+ * the file name using the {@link PHP_MANUAL#sprintf} function.
+ *
+ * This appender uses a layout.
+ * 
+ * Configurable parameters for this appender are:
+ * - datePattern - The date format for the file name. Should be set before 
+ *                 $file. Default value: "Ymd".
+ * - file        - The path to the target log file. The filename should 
+ *                 contain a '%s' which will be substituted by the date.
+ * - append      - Sets if the appender should append to the end of the
+ *                 file or overwrite content ("true" or "false"). Default 
+ *                 value: true.
+ * - rotate      - The frequency of rotation. Should be a character accepted 
+ *                 by the {@link PHP_MANUAL#date} function. Default value: "d".
+ * 
+ * An example php file:
+ * 
+ * {@example ../../examples/php/appender_dailyfile.php 19}
+ *  
+ * An example configuration file:
+ * 
+ * {@example ../../examples/resources/appender_dailyfile.properties 18}
+ *
+ * The above will create a file like: daily_20090908.log
+ *
+ * @version $Revision: 1213283 $
+ * @package log4php
+ * @subpackage appenders
+ */
+class LoggerAppenderDailyRollingFile extends LoggerAppenderFile {
+
+	/**
+	 * Format date. 
+	 * It follows the {@link PHP_MANUAL#date()} formatting rules and <b>should always be set before {@link $file} param</b>.
+	 * @var string
+	 */
+	protected $datePattern = "Ymd";
+	private $filePattern;
+	private $fileDate = 0;
+	public $rotate = 'd'; // Frequency of rotation -- d is daily, h is hourly
+ 	
+	/**
+	 * Sets date format for the file name.
+	 * @param string $datePattern a regular date() string format
+	 */
+	public function setDatePattern($datePattern) {
+		$this->setString('datePattern', $datePattern);
+	}
+
+	/**
+	 * Sets the rotate frequency.
+	 * @param string $rotate a single character accepted as regular date() string format
+	 */
+	public function setRotate($rotate) {
+		$this->setString('rotate', $rotate);
+	}
+	
+	/**
+	 * @return string returns date format for the filename
+	 */
+	public function getDatePattern() {
+		return $this->datePattern;
+	}
+	
+	/** 
+	 * Similar to parent method, but but replaces "%s" in the file name with 
+	 * the current date in format specified by the 'datePattern' parameter.
+	 */ 
+	public function activateOptions() {
+		$fileName = $this->getFile();
+		$date = date($this->getDatePattern());
+		$fileName = sprintf($fileName, $date);
+		
+		if(!is_file($fileName)) {
+			$dir = dirname($fileName);
+			if(!is_dir($dir)) {
+				mkdir($dir, 0777, true);
+			}
+		}
+	
+		$this->fp = fopen($fileName, ($this->getAppend()? 'a':'w'));
+		if($this->fp) {
+			if(flock($this->fp, LOCK_EX)) {
+				if($this->getAppend()) {
+					fseek($this->fp, 0, SEEK_END);
+				}
+				fwrite($this->fp, $this->layout->getHeader());
+				flock($this->fp, LOCK_UN);
+				$this->closed = false;
+			} else {
+				// TODO: should we take some action in this case?
+				$this->closed = true;
+			}
+		} else {
+			$this->closed = true;
+		}
+	}
+
+        /**
+        * The File property takes a string value which should be the name of the file to append to.
+        * Sets and opens the file where the log output will go.
+        *
+        * @see LoggerAppenderFile::setFile()
+        */
+        public function setFile() {
+                $numargs = func_num_args();
+                $args = func_get_args();
+
+                if($numargs == 1 and is_string($args[0])) {
+                        // HACK: save first filename containing the pattern
+                        if(!$this->filePattern) $this->filePattern = $args[0];
+                        parent::setFile( sprintf((string)$args[0], date($this->getDatePattern())) );
+                } else if ($numargs == 2 and is_string($args[0]) and is_bool($args[1])) {
+                        // HACK: save first filename containing the pattern
+                        if(!$this->filePattern) $this->filePattern = $args[0];
+                        parent::setFile( sprintf((string)$args[0], date($this->getDatePattern())), $args[1] );
+                }
+                $this->setFileDate();
+        }
+
+        /**
+         * @param LoggerLoggingEvent $event
+         */
+        public function append(LoggerLoggingEvent $event) {
+                parent::append($event);
+                // not using getter to make comparison faster
+                if(idate($this->rotate) != $this->fileDate) {
+                        $this->setFile($this->filePattern);
+                        $this->activateOptions();
+                }
+        }
+
+	/**
+	 * @return string returns fileDate property for comparison.
+	 */
+        private function getFileDate() {
+                return $this->fileDate;
+        }
+
+	/**
+	 * Sets the fileDate property which we are comparing against.
+	 */
+        private function setFileDate() {
+                $this->fileDate = idate($this->rotate);
+        }
+}
diff -Nur log4php-2.2.0.orig/Logger.php log4php-2.2.0/Logger.php
--- log4php-2.2.0.orig/Logger.php	2011-12-17 11:48:12.000000000 +0100
+++ log4php-2.2.0/Logger.php	2012-01-13 12:11:31.000000000 +0100
@@ -65,6 +65,7 @@
 		'LoggerAppenderPDO' => '/appenders/LoggerAppenderPDO.php',
 		'LoggerAppenderConsole' => '/appenders/LoggerAppenderConsole.php',
 		'LoggerAppenderDailyFile' => '/appenders/LoggerAppenderDailyFile.php',
+		'LoggerAppenderDailyRollingFile' => '/appenders/LoggerAppenderDailyRollingFile.php',
 		'LoggerAppenderEcho' => '/appenders/LoggerAppenderEcho.php',
 		'LoggerAppenderFile' => '/appenders/LoggerAppenderFile.php',
 		'LoggerAppenderMail' => '/appenders/LoggerAppenderMail.php',

Reply via email to