You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ih...@apache.org on 2013/11/28 17:03:56 UTC
[26/43] LOG4PHP-121: Reorganized classes into namespaces
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Appenders/PhpAppender.php
----------------------------------------------------------------------
diff --git a/src/Appenders/PhpAppender.php b/src/Appenders/PhpAppender.php
new file mode 100644
index 0000000..287c56a
--- /dev/null
+++ b/src/Appenders/PhpAppender.php
@@ -0,0 +1,50 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Appenders;
+
+use Apache\Log4php\Level;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * PhpAppender logs events by creating a PHP user-level message using
+ * the PHP's trigger_error()function.
+ *
+ * This appender has no configurable parameters.
+ *
+ * Levels are mapped as follows:
+ *
+ * - <b>level < WARN</b> mapped to E_USER_NOTICE
+ * - <b>WARN <= level < ERROR</b> mapped to E_USER_WARNING
+ * - <b>level >= ERROR</b> mapped to E_USER_ERROR
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @link http://logging.apache.org/log4php/docs/appenders/php.html Appender documentation
+ */
+class PhpAppender extends AbstractAppender {
+
+ public function append(LoggingEvent $event) {
+ $level = $event->getLevel();
+ if($level->isGreaterOrEqual(Level::getLevelError())) {
+ trigger_error($this->layout->format($event), E_USER_ERROR);
+ } else if ($level->isGreaterOrEqual(Level::getLevelWarn())) {
+ trigger_error($this->layout->format($event), E_USER_WARNING);
+ } else {
+ trigger_error($this->layout->format($event), E_USER_NOTICE);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Appenders/RollingFileAppender.php
----------------------------------------------------------------------
diff --git a/src/Appenders/RollingFileAppender.php b/src/Appenders/RollingFileAppender.php
new file mode 100644
index 0000000..8d54a4a
--- /dev/null
+++ b/src/Appenders/RollingFileAppender.php
@@ -0,0 +1,303 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Appenders;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * RollingFileAppender writes logging events to a specified file. The
+ * file is rolled over after a specified size has been reached.
+ *
+ * This appender uses a layout.
+ *
+ * ## Configurable parameters: ##
+ *
+ * - **file** - Path to the target file.
+ * - **append** - If set to true, the appender will append to the file,
+ * otherwise the file contents will be overwritten.
+ * - **maxBackupIndex** - Maximum number of backup files to keep. Default is 1.
+ * - **maxFileSize** - Maximum allowed file size (in bytes) before rolling
+ * over. Suffixes "KB", "MB" and "GB" are allowed. 10KB = 10240 bytes, etc.
+ * Default is 10M.
+ * - **compress** - If set to true, rolled-over files will be compressed.
+ * Requires the zlib extension.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @link http://logging.apache.org/log4php/docs/appenders/rolling-file.html Appender documentation
+ */
+class RollingFileAppender extends FileAppender {
+
+ /** Compressing backup files is done in chunks, this determines how large. */
+ const COMPRESS_CHUNK_SIZE = 102400; // 100KB
+
+ /**
+ * The maximum size (in bytes) that the output file is allowed to reach
+ * before being rolled over to backup files.
+ *
+ * The default maximum file size is 10MB (10485760 bytes). Maximum value
+ * for this option may depend on the file system.
+ *
+ * @var integer
+ */
+ protected $maxFileSize = 10485760;
+
+ /**
+ * Set the maximum number of backup files to keep around.
+ *
+ * Determines how many backup files are kept before the oldest is erased.
+ * This option takes a positive integer value. If set to zero, then there
+ * will be no backup files and the log file will be truncated when it
+ * reaches <var>maxFileSize</var>.
+ *
+ * There is one backup file by default.
+ *
+ * @var integer
+ */
+ protected $maxBackupIndex = 1;
+
+ /**
+ * The <var>compress</var> parameter determindes the compression with zlib.
+ * If set to true, the rollover files are compressed and saved with the .gz extension.
+ * @var boolean
+ */
+ protected $compress = false;
+
+ /**
+ * Set to true in the constructor if PHP >= 5.3.0. In that case clearstatcache
+ * supports conditional clearing of statistics.
+ * @var boolean
+ * @see http://php.net/manual/en/function.clearstatcache.php
+ */
+ private $clearConditional = false;
+
+ /**
+ * Get the maximum size that the output file is allowed to reach
+ * before being rolled over to backup files.
+ * @return integer
+ */
+ public function getMaximumFileSize() {
+ return $this->maxFileSize;
+ }
+
+ public function __construct($name = '') {
+ parent::__construct($name);
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+ $this->clearConditional = true;
+ }
+ }
+
+ /**
+ * Implements the usual roll over behaviour.
+ *
+ * If MaxBackupIndex is positive, then files File.1, ..., File.MaxBackupIndex -1 are renamed to File.2, ..., File.MaxBackupIndex.
+ * Moreover, File is renamed File.1 and closed. A new File is created to receive further log output.
+ *
+ * If MaxBackupIndex is equal to zero, then the File is truncated with no backup files created.
+ *
+ * Rollover must be called while the file is locked so that it is safe for concurrent access.
+ *
+ * @throws LoggerException If any part of the rollover procedure fails.
+ */
+ private function rollOver() {
+ // If maxBackups <= 0, then there is no file renaming to be done.
+ if($this->maxBackupIndex > 0) {
+ // Delete the oldest file, to keep Windows happy.
+ $file = $this->file . '.' . $this->maxBackupIndex;
+
+ if (file_exists($file) && !unlink($file)) {
+ throw new LoggerException("Unable to delete oldest backup file from [$file].");
+ }
+
+ // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
+ $this->renameArchievedLogs($this->file);
+
+ // Backup the active file
+ $this->moveToBackup($this->file);
+ }
+
+ // Truncate the active file
+ ftruncate($this->fp, 0);
+ rewind($this->fp);
+ }
+
+ private function moveToBackup($source) {
+ if ($this->compress) {
+ $target = $source . '.1.gz';
+ $this->compressFile($source, $target);
+ } else {
+ $target = $source . '.1';
+ copy($source, $target);
+ }
+ }
+
+ private function compressFile($source, $target) {
+ $target = 'compress.zlib://' . $target;
+
+ $fin = fopen($source, 'rb');
+ if ($fin === false) {
+ throw new LoggerException("Unable to open file for reading: [$source].");
+ }
+
+ $fout = fopen($target, 'wb');
+ if ($fout === false) {
+ throw new LoggerException("Unable to open file for writing: [$target].");
+ }
+
+ while (!feof($fin)) {
+ $chunk = fread($fin, self::COMPRESS_CHUNK_SIZE);
+ if (false === fwrite($fout, $chunk)) {
+ throw new LoggerException("Failed writing to compressed file.");
+ }
+ }
+
+ fclose($fin);
+ fclose($fout);
+ }
+
+ private function renameArchievedLogs($fileName) {
+ for($i = $this->maxBackupIndex - 1; $i >= 1; $i--) {
+
+ $source = $fileName . "." . $i;
+ if ($this->compress) {
+ $source .= '.gz';
+ }
+
+ if(file_exists($source)) {
+ $target = $fileName . '.' . ($i + 1);
+ if ($this->compress) {
+ $target .= '.gz';
+ }
+
+ rename($source, $target);
+ }
+ }
+ }
+
+ /**
+ * Writes a string to the target file. Opens file if not already open.
+ * @param string $string Data to write.
+ */
+ protected function write($string) {
+ // Lazy file open
+ if(!isset($this->fp)) {
+ if ($this->openFile() === false) {
+ return; // Do not write if file open failed.
+ }
+ }
+
+ // Lock the file while writing and possible rolling over
+ if(flock($this->fp, LOCK_EX)) {
+
+ // Write to locked file
+ if(fwrite($this->fp, $string) === false) {
+ $this->warn("Failed writing to file. Closing appender.");
+ $this->closed = true;
+ }
+
+ // Stats cache must be cleared, otherwise filesize() returns cached results
+ // If supported (PHP 5.3+), clear only the state cache for the target file
+ if ($this->clearConditional) {
+ clearstatcache(true, $this->file);
+ } else {
+ clearstatcache();
+ }
+
+ // Rollover if needed
+ if (filesize($this->file) > $this->maxFileSize) {
+ try {
+ $this->rollOver();
+ } catch (LoggerException $ex) {
+ $this->warn("Rollover failed: " . $ex->getMessage() . " Closing appender.");
+ $this->closed = true;
+ }
+ }
+
+ flock($this->fp, LOCK_UN);
+ } else {
+ $this->warn("Failed locking file for writing. Closing appender.");
+ $this->closed = true;
+ }
+ }
+
+ public function activateOptions() {
+ parent::activateOptions();
+
+ if ($this->compress && !extension_loaded('zlib')) {
+ $this->warn("The 'zlib' extension is required for file compression. Disabling compression.");
+ $this->compression = false;
+ }
+ }
+
+ /**
+ * Set the 'maxBackupIndex' parameter.
+ * @param integer $maxBackupIndex
+ */
+ public function setMaxBackupIndex($maxBackupIndex) {
+ $this->setPositiveInteger('maxBackupIndex', $maxBackupIndex);
+ }
+
+ /**
+ * Returns the 'maxBackupIndex' parameter.
+ * @return integer
+ */
+ public function getMaxBackupIndex() {
+ return $this->maxBackupIndex;
+ }
+
+ /**
+ * Set the 'maxFileSize' parameter.
+ * @param mixed $maxFileSize
+ */
+ public function setMaxFileSize($maxFileSize) {
+ $this->setFileSize('maxFileSize', $maxFileSize);
+ }
+
+ /**
+ * Returns the 'maxFileSize' parameter.
+ * @return integer
+ */
+ public function getMaxFileSize() {
+ return $this->maxFileSize;
+ }
+
+ /**
+ * Set the 'maxFileSize' parameter (kept for backward compatibility).
+ * @param mixed $maxFileSize
+ * @deprecated Use setMaxFileSize() instead.
+ */
+ public function setMaximumFileSize($maxFileSize) {
+ $this->warn("The 'maximumFileSize' parameter is deprecated. Use 'maxFileSize' instead.");
+ return $this->setMaxFileSize($maxFileSize);
+ }
+
+ /**
+ * Sets the 'compress' parameter.
+ * @param boolean $compress
+ */
+ public function setCompress($compress) {
+ $this->setBoolean('compress', $compress);
+ }
+
+ /**
+ * Returns the 'compress' parameter.
+ * @param boolean
+ */
+ public function getCompress() {
+ return $this->compress;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Appenders/SocketAppender.php
----------------------------------------------------------------------
diff --git a/src/Appenders/SocketAppender.php b/src/Appenders/SocketAppender.php
new file mode 100644
index 0000000..024c91f
--- /dev/null
+++ b/src/Appenders/SocketAppender.php
@@ -0,0 +1,123 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Appenders;
+
+use Apache\Log4php\Layouts\SerializedLayout;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * SocketAppender appends to a network socket.
+ *
+ * ## Configurable parameters: ##
+ *
+ * - **remoteHost** - Target remote host.
+ * - **port** - Target port (optional, defaults to 4446).
+ * - **timeout** - Connection timeout in seconds (optional, defaults to
+ * 'default_socket_timeout' from php.ini)
+ *
+ * The socket will by default be opened in blocking mode.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @link http://logging.apache.org/log4php/docs/appenders/socket.html Appender documentation
+ */
+class SocketAppender extends AbstractAppender {
+
+ /**
+ * Target host.
+ * @see http://php.net/manual/en/function.fsockopen.php
+ */
+ protected $remoteHost;
+
+ /** Target port */
+ protected $port = 4446;
+
+ /** Connection timeout in ms. */
+ protected $timeout;
+
+ // ******************************************
+ // *** Appender methods ***
+ // ******************************************
+
+ /** Override the default layout to use serialized. */
+ public function getDefaultLayout() {
+ return new SerializedLayout();
+ }
+
+ public function activateOptions() {
+ if (empty($this->remoteHost)) {
+ $this->warn("Required parameter [remoteHost] not set. Closing appender.");
+ $this->closed = true;
+ return;
+ }
+
+ if (empty($this->timeout)) {
+ $this->timeout = ini_get("default_socket_timeout");
+ }
+
+ $this->closed = false;
+ }
+
+ public function append(LoggingEvent $event) {
+ $socket = fsockopen($this->remoteHost, $this->port, $errno, $errstr, $this->timeout);
+ if ($socket === false) {
+ $this->warn("Could not open socket to {$this->remoteHost}:{$this->port}. Closing appender.");
+ $this->closed = true;
+ return;
+ }
+
+ if (false === fwrite($socket, $this->layout->format($event))) {
+ $this->warn("Error writing to socket. Closing appender.");
+ $this->closed = true;
+ }
+ fclose($socket);
+ }
+
+ // ******************************************
+ // *** Accessor methods ***
+ // ******************************************
+
+ /** Sets the target host. */
+ public function setRemoteHost($hostname) {
+ $this->setString('remoteHost', $hostname);
+ }
+
+ /** Sets the target port */
+ public function setPort($port) {
+ $this->setPositiveInteger('port', $port);
+ }
+
+ /** Sets the timeout. */
+ public function setTimeout($timeout) {
+ $this->setPositiveInteger('timeout', $timeout);
+ }
+
+ /** Returns the target host. */
+ public function getRemoteHost() {
+ return $this->getRemoteHost();
+ }
+
+ /** Returns the target port. */
+ public function getPort() {
+ return $this->port;
+ }
+
+ /** Returns the timeout */
+ public function getTimeout() {
+ return $this->timeout;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Appenders/SyslogAppender.php
----------------------------------------------------------------------
diff --git a/src/Appenders/SyslogAppender.php b/src/Appenders/SyslogAppender.php
new file mode 100644
index 0000000..ae7351b
--- /dev/null
+++ b/src/Appenders/SyslogAppender.php
@@ -0,0 +1,304 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Appenders;
+
+use Apache\Log4php\Level;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * Log events to a system log using the PHP syslog() function.
+ *
+ * This appenders requires a layout.
+ *
+ * ## Configurable parameters: ##
+ *
+ * - **ident** - The ident of the syslog message.
+ * - **priority** - The priority for the syslog message (used when overriding
+ * priority).
+ * - **facility** - The facility for the syslog message
+ * - **overridePriority** - If set to true, the message priority will always
+ * use the value defined in {@link $priority}, otherwise the priority will
+ * be determined by the message's log level.
+ * - **option** - The option value for the syslog message.
+ *
+ * Recognised syslog options are:
+ *
+ * - CONS - if there is an error while sending data to the system logger, write directly to the system console
+ * - NDELAY - open the connection to the logger immediately
+ * - ODELAY - delay opening the connection until the first message is logged (default)
+ * - PERROR - print log message also to standard error
+ * - PID - include PID with each message
+ *
+ * Multiple options can be set by delimiting them with a pipe character,
+ * e.g.: "CONS|PID|PERROR".
+ *
+ * Recognised syslog priorities are:
+ *
+ * - EMERG
+ * - ALERT
+ * - CRIT
+ * - ERR
+ * - WARNING
+ * - NOTICE
+ * - INFO
+ * - DEBUG
+ *
+ * Levels are mapped as follows:
+ *
+ * - <b>FATAL</b> to LOG_ALERT
+ * - <b>ERROR</b> to LOG_ERR
+ * - <b>WARN</b> to LOG_WARNING
+ * - <b>INFO</b> to LOG_INFO
+ * - <b>DEBUG</b> to LOG_DEBUG
+ * - <b>TRACE</b> to LOG_DEBUG
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @link http://logging.apache.org/log4php/docs/appenders/syslog.html Appender documentation
+ */
+class SyslogAppender extends AbstractAppender {
+
+ /**
+ * The ident string is added to each message. Typically the name of your application.
+ *
+ * @var string
+ */
+ protected $ident = "Apache log4php";
+
+ /**
+ * The syslog priority to use when overriding priority. This setting is
+ * required if {@link overridePriority} is set to true.
+ *
+ * @var string
+ */
+ protected $priority;
+
+ /**
+ * The option used when opening the syslog connection.
+ *
+ * @var string
+ */
+ protected $option = 'PID|CONS';
+
+ /**
+ * The facility value indicates the source of the message.
+ *
+ * @var string
+ */
+ protected $facility = 'USER';
+
+ /**
+ * If set to true, the message priority will always use the value defined
+ * in {@link $priority}, otherwise the priority will be determined by the
+ * message's log level.
+ *
+ * @var string
+ */
+ protected $overridePriority = false;
+
+ /**
+ * Holds the int value of the {@link $priority}.
+ * @var int
+ */
+ private $intPriority;
+
+ /**
+ * Holds the int value of the {@link $facility}.
+ * @var int
+ */
+ private $intFacility;
+
+ /**
+ * Holds the int value of the {@link $option}.
+ * @var int
+ */
+ private $intOption;
+
+ /**
+ * Sets the {@link $ident}.
+ *
+ * @param string $ident
+ */
+ public function setIdent($ident) {
+ $this->ident = $ident;
+ }
+
+ /**
+ * Sets the {@link $priority}.
+ *
+ * @param string $priority
+ */
+ public function setPriority($priority) {
+ $this->priority = $priority;
+ }
+
+ /**
+ * Sets the {@link $facility}.
+ *
+ * @param string $facility
+ */
+ public function setFacility($facility) {
+ $this->facility = $facility;
+ }
+
+ /**
+ * Sets the {@link $overridePriority}.
+ *
+ * @param string $overridePriority
+ */
+ public function setOverridePriority($overridePriority) {
+ $this->overridePriority = $overridePriority;
+ }
+
+ /**
+ * Sets the 'option' parameter.
+ *
+ * @param string $option
+ */
+ public function setOption($option) {
+ $this->option = $option;
+ }
+
+ /**
+ * Returns the 'ident' parameter.
+ *
+ * @return string $ident
+ */
+ public function getIdent() {
+ return $this->ident;
+ }
+
+ /**
+ * Returns the 'priority' parameter.
+ *
+ * @return string
+ */
+ public function getPriority() {
+ return $this->priority;
+ }
+
+ /**
+ * Returns the 'facility' parameter.
+ *
+ * @return string
+ */
+ public function getFacility() {
+ return $this->facility;
+ }
+
+ /**
+ * Returns the 'overridePriority' parameter.
+ *
+ * @return string
+ */
+ public function getOverridePriority() {
+ return $this->overridePriority;
+ }
+
+ /**
+ * Returns the 'option' parameter.
+ *
+ * @return string
+ */
+ public function getOption() {
+ return $this->option;
+ }
+
+
+ public function activateOptions() {
+ $this->intPriority = $this->parsePriority();
+ $this->intOption = $this->parseOption();
+ $this->intFacility = $this->parseFacility();
+
+ $this->closed = false;
+ }
+
+ public function close() {
+ if($this->closed != true) {
+ closelog();
+ $this->closed = true;
+ }
+ }
+
+ /**
+ * Appends the event to syslog.
+ *
+ * Log is opened and closed each time because if it is not closed, it
+ * can cause the Apache httpd server to log to whatever ident/facility
+ * was used in openlog().
+ *
+ * @see http://www.php.net/manual/en/function.syslog.php#97843
+ */
+ public function append(LoggingEvent $event) {
+ $priority = $this->getSyslogPriority($event->getLevel());
+ $message = $this->layout->format($event);
+
+ openlog($this->ident, $this->intOption, $this->intFacility);
+ syslog($priority, $message);
+ closelog();
+ }
+
+ /** Determines which syslog priority to use based on the given level. */
+ private function getSyslogPriority(Level $level) {
+ if($this->overridePriority) {
+ return $this->intPriority;
+ }
+ return $level->getSyslogEquivalent();
+ }
+
+ /** Parses a syslog option string and returns the correspodning int value. */
+ private function parseOption() {
+ $value = 0;
+ $options = explode('|', $this->option);
+
+ foreach($options as $option) {
+ if (!empty($option)) {
+ $constant = "LOG_" . trim($option);
+ if (defined($constant)) {
+ $value |= constant($constant);
+ } else {
+ trigger_error("log4php: Invalid syslog option provided: $option. Whole option string: {$this->option}.", E_USER_WARNING);
+ }
+ }
+ }
+ return $value;
+ }
+
+ /** Parses the facility string and returns the corresponding int value. */
+ private function parseFacility() {
+ if (!empty($this->facility)) {
+ $constant = "LOG_" . trim($this->facility);
+ if (defined($constant)) {
+ return constant($constant);
+ } else {
+ trigger_error("log4php: Invalid syslog facility provided: {$this->facility}.", E_USER_WARNING);
+ }
+ }
+ }
+
+ /** Parses the priority string and returns the corresponding int value. */
+ private function parsePriority() {
+ if (!empty($this->priority)) {
+ $constant = "LOG_" . trim($this->priority);
+ if (defined($constant)) {
+ return constant($constant);
+ } else {
+ trigger_error("log4php: Invalid syslog priority provided: {$this->priority}.", E_USER_WARNING);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Autoloader.php
----------------------------------------------------------------------
diff --git a/src/Autoloader.php b/src/Autoloader.php
new file mode 100644
index 0000000..fe6b8d3
--- /dev/null
+++ b/src/Autoloader.php
@@ -0,0 +1,53 @@
+<?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.
+ */
+
+namespace Apache\Log4php;
+
+/**
+ * PSR-4 compliant autoloader implementation.
+ */
+class Autoloader
+{
+ const BASE_NAMESPACE = 'Apache\\Log4php\\';
+
+ public function autoload($class)
+ {
+ // Base directory for the namespace prefix
+ $baseDir = __DIR__ . '/../src/';
+
+ // Skip classes which are not in base namespace
+ $len = strlen(self::BASE_NAMESPACE);
+ if (strncmp(self::BASE_NAMESPACE, $class, $len) !== 0) {
+ return;
+ }
+
+ // Locate the class in base dir, based on namespace
+ $classPath = str_replace('\\', '/', substr($class, $len));
+ $file = $baseDir . $classPath . '.php';
+
+ // If the file exists, require it
+ if (file_exists($file)) {
+ require $file;
+ }
+ }
+
+ public function register()
+ {
+ spl_autoload_register(array($this, 'autoload'));
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configurable.php
----------------------------------------------------------------------
diff --git a/src/Configurable.php b/src/Configurable.php
new file mode 100644
index 0000000..352aa23
--- /dev/null
+++ b/src/Configurable.php
@@ -0,0 +1,118 @@
+<?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.
+*/
+
+namespace Apache\Log4php;
+
+use Apache\Log4php\Helpers\OptionConverter;
+
+use Exception;
+
+/**
+ * A base class from which all classes which have configurable properties are
+ * extended. Provides a generic setter with integrated validation.
+ *
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+abstract class Configurable {
+
+ /** Setter function for boolean type. */
+ protected function setBoolean($property, $value) {
+ try {
+ $this->$property = OptionConverter::toBooleanEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a boolean value. Property not changed.");
+ }
+ }
+
+ /** Setter function for integer type. */
+ protected function setInteger($property, $value) {
+ try {
+ $this->$property = OptionConverter::toIntegerEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected an integer. Property not changed.");
+ }
+ }
+
+ /** Setter function for Level values. */
+ protected function setLevel($property, $value) {
+ try {
+ $this->$property = OptionConverter::toLevelEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a level value. Property not changed.");
+ }
+ }
+
+ /** Setter function for integer type. */
+ protected function setPositiveInteger($property, $value) {
+ try {
+ $this->$property = OptionConverter::toPositiveIntegerEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a positive integer. Property not changed.");
+ }
+ }
+
+ /** Setter for file size. */
+ protected function setFileSize($property, $value) {
+ try {
+ $this->$property = OptionConverter::toFileSizeEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a file size value. Property not changed.");
+ }
+ }
+
+ /** Setter function for numeric type. */
+ protected function setNumeric($property, $value) {
+ try {
+ $this->$property = OptionConverter::toNumericEx($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a number. Property not changed.");
+ }
+ }
+
+ /** Setter function for string type. */
+ protected function setString($property, $value, $nullable = false) {
+ if ($value === null) {
+ if($nullable) {
+ $this->$property= null;
+ } else {
+ $this->warn("Null value given for '$property' property. Expected a string. Property not changed.");
+ }
+ } else {
+ try {
+ $value = OptionConverter::toStringEx($value);
+ $this->$property = OptionConverter::substConstants($value);
+ } catch (Exception $ex) {
+ $value = var_export($value, true);
+ $this->warn("Invalid value given for '$property' property: [$value]. Expected a string. Property not changed.");
+ }
+ }
+ }
+
+ /** Triggers a warning. */
+ protected function warn($message) {
+ $class = get_class($this);
+ trigger_error("log4php: $class: $message", E_USER_WARNING);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/ConfiguratorInterface.php
----------------------------------------------------------------------
diff --git a/src/Configuration/ConfiguratorInterface.php b/src/Configuration/ConfiguratorInterface.php
new file mode 100644
index 0000000..a4a8e21
--- /dev/null
+++ b/src/Configuration/ConfiguratorInterface.php
@@ -0,0 +1,41 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration;
+
+use Apache\Log4php\Hierarchy;
+
+/**
+ * Interface for logger configurators.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+interface ConfiguratorInterface
+{
+ /**
+ * Configures log4php based on the given configuration.
+ *
+ * All configurators implementations must implement this interface.
+ *
+ * @param Hierarchy $hierarchy The hierarchy on which to perform
+ * the configuration.
+ * @param mixed $input Either path to the config file or the
+ * configuration as an array.
+ */
+ public function configure(Hierarchy $hierarchy, $input = null);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/DefaultConfigurator.php
----------------------------------------------------------------------
diff --git a/src/Configuration/DefaultConfigurator.php b/src/Configuration/DefaultConfigurator.php
new file mode 100644
index 0000000..9e4e6bd
--- /dev/null
+++ b/src/Configuration/DefaultConfigurator.php
@@ -0,0 +1,512 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration;
+
+use Apache\Log4php\Appenders\AbstractAppender;
+use Apache\Log4php\Filters\AbstractFilter;
+use Apache\Log4php\Helpers\OptionConverter;
+use Apache\Log4php\Hierarchy;
+use Apache\Log4php\Layouts\AbstractLayout;
+use Apache\Log4php\Level;
+use Apache\Log4php\Logger;
+use Apache\Log4php\LoggerException;
+
+/**
+ * Default implementation of the logger configurator.
+ *
+ * Configures log4php based on a provided configuration file or array.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+class DefaultConfigurator implements ConfiguratorInterface
+{
+ /** XML configuration file format. */
+ const FORMAT_XML = 'xml';
+
+ /** PHP configuration file format. */
+ const FORMAT_PHP = 'php';
+
+ /** INI (properties) configuration file format. */
+ const FORMAT_INI = 'ini';
+
+ /** Defines which adapter should be used for parsing which format. */
+ private $adapters = array(
+ self::FORMAT_XML => 'XmlAdapter',
+ self::FORMAT_INI => 'IniAdapter',
+ self::FORMAT_PHP => 'PhpAdapter',
+ );
+
+ /** Default configuration; used if no configuration file is provided. */
+ private static $defaultConfiguration = array(
+ 'threshold' => 'ALL',
+ 'rootLogger' => array(
+ 'level' => 'DEBUG',
+ 'appenders' => array('default'),
+ ),
+ 'appenders' => array(
+ 'default' => array(
+ 'class' => '\\Apache\\Log4php\\Appenders\\EchoAppender'
+ ),
+ ),
+ );
+
+ /** Holds the appenders before they are linked to loggers. */
+ private $appenders = array();
+
+ /**
+ * Configures log4php based on the given configuration. The input can
+ * either be a path to the config file, or a PHP array holding the
+ * configuration.
+ *
+ * If no configuration is given, or if the given configuration cannot be
+ * parsed for whatever reason, a warning will be issued, and log4php
+ * will use the default configuration contained in
+ * {@link $defaultConfiguration}.
+ *
+ * @param Hierarchy $hierarchy The hierarchy on which to perform
+ * the configuration.
+ * @param string|array $input Either path to the config file or the
+ * configuration as an array. If not set, default configuration
+ * will be used.
+ */
+ public function configure(Hierarchy $hierarchy, $input = null) {
+ $config = $this->parse($input);
+ $this->doConfigure($hierarchy, $config);
+ }
+
+ /**
+ * Parses the given configuration and returns the parsed configuration
+ * as a PHP array. Does not perform any configuration.
+ *
+ * If no configuration is given, or if the given configuration cannot be
+ * parsed for whatever reason, a warning will be issued, and the default
+ * configuration will be returned ({@link $defaultConfiguration}).
+ *
+ * @param string|array $input Either path to the config file or the
+ * configuration as an array. If not set, default configuration
+ * will be used.
+ * @return array The parsed configuration.
+ */
+ public function parse($input) {
+ // No input - use default configuration
+ if (!isset($input)) {
+ $config = self::$defaultConfiguration;
+ }
+
+ // Array input - contains configuration within the array
+ else if (is_array($input)) {
+ $config = $input;
+ }
+
+ // String input - contains path to configuration file
+ else if (is_string($input)) {
+ try {
+ $config = $this->parseFile($input);
+ } catch (LoggerException $e) {
+ $this->warn("Configuration failed. " . $e->getMessage() . " Using default configuration.");
+ $config = self::$defaultConfiguration;
+ }
+ }
+
+ // Anything else is an error
+ else {
+ $this->warn("Invalid configuration param given. Reverting to default configuration.");
+ $config = self::$defaultConfiguration;
+ }
+
+ return $config;
+ }
+
+ /**
+ * Returns the default log4php configuration.
+ * @return array
+ */
+ public static function getDefaultConfiguration() {
+ return self::$defaultConfiguration;
+ }
+
+ /**
+ * Loads the configuration file from the given URL, determines which
+ * adapter to use, converts the configuration to a PHP array and
+ * returns it.
+ *
+ * @param string $url Path to the config file.
+ * @return The configuration from the config file, as a PHP array.
+ * @throws LoggerException If the configuration file cannot be loaded, or
+ * if the parsing fails.
+ */
+ private function parseFile($url) {
+
+ if (!file_exists($url)) {
+ throw new LoggerException("File not found at [$url].");
+ }
+
+ $type = $this->getConfigType($url);
+ $adapterClass = "Apache\\Log4php\\Configuration\\Adapters\\" . $this->adapters[$type];
+
+ $adapter = new $adapterClass();
+ return $adapter->convert($url);
+ }
+
+ /** Determines configuration file type based on the file extension. */
+ private function getConfigType($url) {
+ $info = pathinfo($url);
+ $ext = strtolower($info['extension']);
+
+ switch($ext) {
+ case 'xml':
+ return self::FORMAT_XML;
+
+ case 'ini':
+ case 'properties':
+ return self::FORMAT_INI;
+
+ case 'php':
+ return self::FORMAT_PHP;
+
+ default:
+ throw new LoggerException("Unsupported configuration file extension: $ext");
+ }
+ }
+
+ /**
+ * Constructs the logger hierarchy based on configuration.
+ *
+ * @param Hierarchy $hierarchy
+ * @param array $config
+ */
+ private function doConfigure(Hierarchy $hierarchy, $config) {
+ if (isset($config['threshold'])) {
+ $threshold = Level::toLevel($config['threshold']);
+ if (isset($threshold)) {
+ $hierarchy->setThreshold($threshold);
+ } else {
+ $this->warn("Invalid threshold value [{$config['threshold']}] specified. Ignoring threshold definition.");
+ }
+ }
+
+ // Configure appenders and add them to the appender pool
+ if (isset($config['appenders']) && is_array($config['appenders'])) {
+ foreach($config['appenders'] as $name => $appenderConfig) {
+ $this->configureAppender($name, $appenderConfig);
+ }
+ }
+
+ // Configure root logger
+ if (isset($config['rootLogger'])) {
+ $this->configureRootLogger($hierarchy, $config['rootLogger']);
+ }
+
+ // Configure loggers
+ if (isset($config['loggers']) && is_array($config['loggers'])) {
+ foreach($config['loggers'] as $loggerName => $loggerConfig) {
+ $this->configureOtherLogger($hierarchy, $loggerName, $loggerConfig);
+ }
+ }
+
+ // Configure renderers
+ if (isset($config['renderers']) && is_array($config['renderers'])) {
+ foreach($config['renderers'] as $rendererConfig) {
+ $this->configureRenderer($hierarchy, $rendererConfig);
+ }
+ }
+
+ if (isset($config['defaultRenderer'])) {
+ $this->configureDefaultRenderer($hierarchy, $config['defaultRenderer']);
+ }
+ }
+
+ private function configureRenderer(Hierarchy $hierarchy, $config) {
+ if (empty($config['renderingClass'])) {
+ $this->warn("Rendering class not specified. Skipping renderer definition.");
+ return;
+ }
+
+ if (empty($config['renderedClass'])) {
+ $this->warn("Rendered class not specified. Skipping renderer definition.");
+ return;
+ }
+
+ // Error handling performed by RendererMap
+ $hierarchy->getRendererMap()->addRenderer($config['renderedClass'], $config['renderingClass']);
+ }
+
+ private function configureDefaultRenderer(Hierarchy $hierarchy, $class) {
+ if (empty($class)) {
+ $this->warn("Rendering class not specified. Skipping default renderer definition.");
+ return;
+ }
+
+ // Error handling performed by RendererMap
+ $hierarchy->getRendererMap()->setDefaultRenderer($class);
+ }
+
+ /**
+ * Configures an appender based on given config and saves it to
+ * {@link $appenders} array so it can be later linked to loggers.
+ * @param string $name Appender name.
+ * @param array $config Appender configuration options.
+ */
+ private function configureAppender($name, $config) {
+
+ // TODO: add this check to other places where it might be useful
+ if (!is_array($config)) {
+ $type = gettype($config);
+ $this->warn("Invalid configuration provided for appender [$name]. Expected an array, found <$type>. Skipping appender definition.");
+ return;
+ }
+
+ // Parse appender class
+ $class = $config['class'];
+ if (empty($class)) {
+ $this->warn("No class given for appender [$name]. Skipping appender definition.");
+ return;
+ }
+
+ // Instantiate the appender
+ if (class_exists($class)) {
+ $appender = new $class($name);
+ } else {
+ // Try the default namespace
+ $nsClass = "\\Apache\\Log4php\\Appenders\\$class";
+ if (class_exists($nsClass)) {
+ $appender = new $nsClass($name);
+ }
+ }
+
+ if (!isset($appender)) {
+ $this->warn("Invalid class [$class] given for appender [$name]. Class does not exist. Skipping appender definition.");
+ return;
+ }
+
+ if (!($appender instanceof AbstractAppender)) {
+ $this->warn("Invalid class [$class] given for appender [$name]. Not a valid Appender class. Skipping appender definition.");
+ return;
+ }
+
+ // Parse the appender threshold
+ if (isset($config['threshold'])) {
+ $threshold = Level::toLevel($config['threshold']);
+ if ($threshold instanceof Level) {
+ $appender->setThreshold($threshold);
+ } else {
+ $this->warn("Invalid threshold value [{$config['threshold']}] specified for appender [$name]. Ignoring threshold definition.");
+ }
+ }
+
+ // Parse the appender layout
+ if ($appender->requiresLayout() && isset($config['layout'])) {
+ $this->createAppenderLayout($appender, $config['layout']);
+ }
+
+ // Parse filters
+ if (isset($config['filters']) && is_array($config['filters'])) {
+ foreach($config['filters'] as $filterConfig) {
+ $this->createAppenderFilter($appender, $filterConfig);
+ }
+ }
+
+ // Set options if any
+ if (isset($config['params'])) {
+ $this->setOptions($appender, $config['params']);
+ }
+
+ // Activate and save for later linking to loggers
+ $appender->activateOptions();
+ $this->appenders[$name] = $appender;
+ }
+
+ /**
+ * Parses layout config, creates the layout and links it to the appender.
+ * @param AbstractAppender $appender
+ * @param array $config Layout configuration.
+ */
+ private function createAppenderLayout(AbstractAppender $appender, $config) {
+ $name = $appender->getName();
+ $class = $config['class'];
+ if (empty($class)) {
+ $this->warn("Layout class not specified for appender [$name]. Reverting to default layout.");
+ return;
+ }
+
+ if (class_exists($class)) {
+ $layout = new $class();
+ } else {
+ $nsClass = "Apache\\Log4php\\Layouts\\$class";
+ if (class_exists($nsClass)) {
+ $layout = new $nsClass();
+ }
+ }
+
+ if (!isset($layout)) {
+ $this->warn("Nonexistant layout class [$class] specified for appender [$name]. Reverting to default layout.");
+ return;
+ }
+
+
+ if (!($layout instanceof AbstractLayout)) {
+ $this->warn("Invalid layout class [$class] sepcified for appender [$name]. Reverting to default layout.");
+ return;
+ }
+
+ if (isset($config['params'])) {
+ $this->setOptions($layout, $config['params']);
+ }
+
+ $layout->activateOptions();
+ $appender->setLayout($layout);
+ }
+
+ /**
+ * Parses filter config, creates the filter and adds it to the appender's
+ * filter chain.
+ * @param Appender $appender
+ * @param array $config Filter configuration.
+ */
+ private function createAppenderFilter(AbstractAppender $appender, $config) {
+ $name = $appender->getName();
+ $class = $config['class'];
+
+ if (class_exists($class)) {
+ $filter = new $class();
+ } else {
+ $nsClass = "Apache\\Log4php\\Filters\\$class";
+ if (class_exists($nsClass)) {
+ $filter = new $nsClass();
+ }
+ }
+
+ if (!isset($filter)) {
+ $this->warn("Nonexistant filter class [$class] specified on appender [$name]. Skipping filter definition.");
+ return;
+ }
+
+ if (!($filter instanceof AbstractFilter)) {
+ $this->warn("Invalid filter class [$class] sepcified on appender [$name]. Skipping filter definition.");
+ return;
+ }
+
+ if (isset($config['params'])) {
+ $this->setOptions($filter, $config['params']);
+ }
+
+ $filter->activateOptions();
+ $appender->addFilter($filter);
+ }
+
+ /**
+ * Configures the root logger
+ * @see configureLogger()
+ */
+ private function configureRootLogger(Hierarchy $hierarchy, $config) {
+ $logger = $hierarchy->getRootLogger();
+ $this->configureLogger($logger, $config);
+ }
+
+ /**
+ * Configures a logger which is not root.
+ * @see configureLogger()
+ */
+ private function configureOtherLogger(Hierarchy $hierarchy, $name, $config) {
+ // Get logger from hierarchy (this creates it if it doesn't already exist)
+ $logger = $hierarchy->getLogger($name);
+ $this->configureLogger($logger, $config);
+ }
+
+ /**
+ * Configures a logger.
+ *
+ * @param Logger $logger The logger to configure
+ * @param array $config Logger configuration options.
+ */
+ private function configureLogger(Logger $logger, $config) {
+ $loggerName = $logger->getName();
+
+ // Set logger level
+ if (isset($config['level'])) {
+ $level = Level::toLevel($config['level']);
+ if (isset($level)) {
+ $logger->setLevel($level);
+ } else {
+ $this->warn("Invalid level value [{$config['level']}] specified for logger [$loggerName]. Ignoring level definition.");
+ }
+ }
+
+ // Link appenders to logger
+ if (isset($config['appenders'])) {
+ foreach($config['appenders'] as $appenderName) {
+ if (isset($this->appenders[$appenderName])) {
+ $logger->addAppender($this->appenders[$appenderName]);
+ } else {
+ $this->warn("Nonexistnant appender [$appenderName] linked to logger [$loggerName].");
+ }
+ }
+ }
+
+ // Set logger additivity
+ if (isset($config['additivity'])) {
+ try {
+ $additivity = OptionConverter::toBooleanEx($config['additivity'], null);
+ $logger->setAdditivity($additivity);
+ } catch (LoggerException $ex) {
+ $this->warn("Invalid additivity value [{$config['additivity']}] specified for logger [$loggerName]. Ignoring additivity setting.");
+ }
+ }
+ }
+
+ /**
+ * Helper method which applies given options to an object which has setters
+ * for these options (such as appenders, layouts, etc.).
+ *
+ * For example, if options are:
+ * <code>
+ * array(
+ * 'file' => '/tmp/myfile.log',
+ * 'append' => true
+ * )
+ * </code>
+ *
+ * This method will call:
+ * <code>
+ * $object->setFile('/tmp/myfile.log')
+ * $object->setAppend(true)
+ * </code>
+ *
+ * If required setters do not exist, it will produce a warning.
+ *
+ * @param mixed $object The object to configure.
+ * @param unknown_type $options
+ */
+ private function setOptions($object, $options) {
+ foreach($options as $name => $value) {
+ $setter = "set$name";
+ if (method_exists($object, $setter)) {
+ $object->$setter($value);
+ } else {
+ $class = get_class($object);
+ $this->warn("Nonexistant option [$name] specified on [$class]. Skipping.");
+ }
+ }
+ }
+
+ /** Helper method to simplify error reporting. */
+ private function warn($message) {
+ trigger_error("log4php: $message", E_USER_WARNING);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/adapters/AdapterInterface.php
----------------------------------------------------------------------
diff --git a/src/Configuration/adapters/AdapterInterface.php b/src/Configuration/adapters/AdapterInterface.php
new file mode 100644
index 0000000..f0fea69
--- /dev/null
+++ b/src/Configuration/adapters/AdapterInterface.php
@@ -0,0 +1,35 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration\Adapters;
+
+/**
+ * The interface for configurator adapters.
+ *
+ * Adapters convert configuration in several formats such as XML, ini and PHP
+ * file to a PHP array.
+ *
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+interface AdapterInterface
+{
+ /** Converts the configuration file to PHP format usable by the configurator. */
+ public function convert($input);
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/adapters/IniAdapter.php
----------------------------------------------------------------------
diff --git a/src/Configuration/adapters/IniAdapter.php b/src/Configuration/adapters/IniAdapter.php
new file mode 100644
index 0000000..61c003b
--- /dev/null
+++ b/src/Configuration/adapters/IniAdapter.php
@@ -0,0 +1,294 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration\Adapters;
+
+use Apache\Log4php\LoggerException;
+
+/**
+ * Converts ini configuration files to a PHP array.
+ *
+ * These used to be called "properties" files (inherited from log4j), and that
+ * file extension is still supported.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+class IniAdapter implements AdapterInterface {
+
+ /** Name to assign to the root logger. */
+ const ROOT_LOGGER_NAME = "root";
+
+ /** Prefix used for defining logger additivity. */
+ const ADDITIVITY_PREFIX = "log4php.additivity.";
+
+ /** Prefix used for defining logger threshold. */
+ const THRESHOLD_PREFIX = "log4php.threshold";
+
+ /** Prefix used for defining the root logger. */
+ const ROOT_LOGGER_PREFIX = "log4php.rootLogger";
+
+ /** Prefix used for defining a logger. */
+ const LOGGER_PREFIX = "log4php.logger.";
+
+ /** Prefix used for defining an appender. */
+ const APPENDER_PREFIX = "log4php.appender.";
+
+ /** Prefix used for defining a renderer. */
+ const RENDERER_PREFIX = "log4php.renderer.";
+
+ /** Holds the configuration. */
+ private $config = array();
+
+ /**
+ * Loads and parses the INI configuration file.
+ *
+ * @param string $url Path to the config file.
+ * @throws LoggerException
+ */
+ private function load($url) {
+ if (!file_exists($url)) {
+ throw new LoggerException("File [$url] does not exist.");
+ }
+
+ $properties = @parse_ini_file($url, true);
+ if ($properties === false) {
+ $error = error_get_last();
+ throw new LoggerException("Error parsing configuration file: {$error['message']}");
+ }
+
+ return $properties;
+ }
+
+ /**
+ * Converts the provided INI configuration file to a PHP array config.
+ *
+ * @param string $path Path to the config file.
+ * @throws LoggerException If the file cannot be loaded or parsed.
+ */
+ public function convert($path) {
+ // Load the configuration
+ $properties = $this->load($path);
+
+ // Parse threshold
+ if (isset($properties[self::THRESHOLD_PREFIX])) {
+ $this->config['threshold'] = $properties[self::THRESHOLD_PREFIX];
+ }
+
+ // Parse root logger
+ if (isset($properties[self::ROOT_LOGGER_PREFIX])) {
+ $this->parseLogger($properties[self::ROOT_LOGGER_PREFIX], self::ROOT_LOGGER_NAME);
+ }
+
+ $appenders = array();
+
+ foreach($properties as $key => $value) {
+ // Parse loggers
+ if ($this->beginsWith($key, self::LOGGER_PREFIX)) {
+ $name = substr($key, strlen(self::LOGGER_PREFIX));
+ $this->parseLogger($value, $name);
+ }
+
+ // Parse additivity
+ if ($this->beginsWith($key, self::ADDITIVITY_PREFIX)) {
+ $name = substr($key, strlen(self::ADDITIVITY_PREFIX));
+ $this->config['loggers'][$name]['additivity'] = $value;
+ }
+
+ // Parse appenders
+ else if ($this->beginsWith($key, self::APPENDER_PREFIX)) {
+ $this->parseAppender($key, $value);
+ }
+
+ // Parse renderers
+ else if ($this->beginsWith($key, self::RENDERER_PREFIX)) {
+ $this->parseRenderer($key, $value);
+ }
+ }
+
+ return $this->config;
+ }
+
+
+ /**
+ * Parses a logger definition.
+ *
+ * Loggers are defined in the following manner:
+ * <pre>
+ * log4php.logger.<name> = [<level>], [<appender-ref>, <appender-ref>, ...]
+ * </pre>
+ *
+ * @param string $value The configuration value (level and appender-refs).
+ * @param string $name Logger name.
+ */
+ private function parseLogger($value, $name) {
+ // Value is divided by commas
+ $parts = explode(',', $value);
+ if (empty($value) || empty($parts)) {
+ return;
+ }
+
+ // The first value is the logger level
+ $level = array_shift($parts);
+
+ // The remaining values are appender references
+ $appenders = array();
+ while($appender = array_shift($parts)) {
+ $appender = trim($appender);
+ if (!empty($appender)) {
+ $appenders[] = trim($appender);
+ }
+ }
+
+ // Find the target configuration
+ if ($name == self::ROOT_LOGGER_NAME) {
+ $this->config['rootLogger']['level'] = trim($level);
+ $this->config['rootLogger']['appenders'] = $appenders;
+ } else {
+ $this->config['loggers'][$name]['level'] = trim($level);
+ $this->config['loggers'][$name]['appenders'] = $appenders;
+ }
+ }
+
+ /**
+ * Parses an configuration line pertaining to an appender.
+ *
+ * Parses the following patterns:
+ *
+ * Appender class:
+ * <pre>
+ * log4php.appender.<name> = <class>
+ * </pre>
+ *
+ * Appender parameter:
+ * <pre>
+ * log4php.appender.<name>.<param> = <value>
+ * </pre>
+ *
+ * Appender threshold:
+ * <pre>
+ * log4php.appender.<name>.threshold = <level>
+ * </pre>
+ *
+ * Appender layout:
+ * <pre>
+ * log4php.appender.<name>.layout = <layoutClass>
+ * </pre>
+ *
+ * Layout parameter:
+ * <pre>
+ * log4php.appender.<name>.layout.<param> = <value>
+ * </pre>
+ *
+ * For example, a full appender config might look like:
+ * <pre>
+ * log4php.appender.myAppender = ConsoleAppender
+ * log4php.appender.myAppender.threshold = info
+ * log4php.appender.myAppender.target = stdout
+ * log4php.appender.myAppender.layout = PatternLayout
+ * log4php.appender.myAppender.layout.conversionPattern = "%d %c: %m%n"
+ * </pre>
+ *
+ * After parsing all these options, the following configuration can be
+ * found under $this->config['appenders']['myAppender']:
+ * <pre>
+ * array(
+ * 'class' => ConsoleAppender,
+ * 'threshold' => info,
+ * 'params' => array(
+ * 'target' => 'stdout'
+ * ),
+ * 'layout' => array(
+ * 'class' => 'ConsoleAppender',
+ * 'params' => array(
+ * 'conversionPattern' => '%d %c: %m%n'
+ * )
+ * )
+ * )
+ * </pre>
+ *
+ * @param string $key
+ * @param string $value
+ */
+ private function parseAppender($key, $value) {
+
+ // Remove the appender prefix from key
+ $subKey = substr($key, strlen(self::APPENDER_PREFIX));
+
+ // Divide the string by dots
+ $parts = explode('.', $subKey);
+ $count = count($parts);
+
+ // The first part is always the appender name
+ $name = trim($parts[0]);
+
+ // Only one part - this line defines the appender class
+ if ($count == 1) {
+ $this->config['appenders'][$name]['class'] = $value;
+ return;
+ }
+
+ // Two parts - either a parameter, a threshold or layout class
+ else if ($count == 2) {
+
+ if ($parts[1] == 'layout') {
+ $this->config['appenders'][$name]['layout']['class'] = $value;
+ return;
+ } else if ($parts[1] == 'threshold') {
+ $this->config['appenders'][$name]['threshold'] = $value;
+ return;
+ } else {
+ $this->config['appenders'][$name]['params'][$parts[1]] = $value;
+ return;
+ }
+ }
+
+ // Three parts - this can only be a layout parameter
+ else if ($count == 3) {
+ if ($parts[1] == 'layout') {
+ $this->config['appenders'][$name]['layout']['params'][$parts[2]] = $value;
+ return;
+ }
+ }
+
+ trigger_error("log4php: Don't know how to parse the following line: \"$key = $value\". Skipping.");
+ }
+
+ /**
+ * Parses a renderer definition.
+ *
+ * Renderers are defined as:
+ * <pre>
+ * log4php.renderer.<renderedClass> = <renderingClass>
+ * </pre>
+ *
+ * @param string $key log4php.renderer.<renderedClass>
+ * @param string $value <renderingClass>
+ */
+ private function parseRenderer($key, $value) {
+ // Remove the appender prefix from key
+ $renderedClass = substr($key, strlen(self::APPENDER_PREFIX));
+ $renderingClass = $value;
+
+ $this->config['renderers'][] = compact('renderedClass', 'renderingClass');
+ }
+
+ /** Helper method. Returns true if $str begins with $sub. */
+ private function beginsWith($str, $sub) {
+ return (strncmp($str, $sub, strlen($sub)) == 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/adapters/PhpAdapter.php
----------------------------------------------------------------------
diff --git a/src/Configuration/adapters/PhpAdapter.php b/src/Configuration/adapters/PhpAdapter.php
new file mode 100644
index 0000000..71d245b
--- /dev/null
+++ b/src/Configuration/adapters/PhpAdapter.php
@@ -0,0 +1,82 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration\Adapters;
+
+use Apache\Log4php\LoggerException;
+
+/**
+ * Converts PHP configuration files to a PHP array.
+ *
+ * The file should only hold the PHP config array preceded by "return".
+ *
+ * Example PHP config file:
+ * <code>
+ * <?php
+ * return array(
+ * 'rootLogger' => array(
+ * 'level' => 'info',
+ * 'appenders' => array('default')
+ * ),
+ * 'appenders' => array(
+ * 'default' => array(
+ * 'class' => 'EchoAppender',
+ * 'layout' => array(
+ * 'class' => 'SimpleLayout'
+ * )
+ * )
+ * )
+ * )
+ * ?>
+ * </code>
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+class PhpAdapter implements AdapterInterface
+{
+ public function convert($url) {
+ if (!file_exists($url)) {
+ throw new LoggerException("File [$url] does not exist.");
+ }
+
+ // Load the config file
+ $data = @file_get_contents($url);
+ if ($data === false) {
+ $error = error_get_last();
+ throw new LoggerException("Error loading config file: {$error['message']}");
+ }
+
+ $config = @eval('?>' . $data);
+
+ if ($config === false) {
+ $error = error_get_last();
+ throw new LoggerException("Error parsing configuration: " . $error['message']);
+ }
+
+ if (empty($config)) {
+ throw new LoggerException("Invalid configuration: empty configuration array.");
+ }
+
+ if (!is_array($config)) {
+ throw new LoggerException("Invalid configuration: not an array.");
+ }
+
+ return $config;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Configuration/adapters/XmlAdapter.php
----------------------------------------------------------------------
diff --git a/src/Configuration/adapters/XmlAdapter.php b/src/Configuration/adapters/XmlAdapter.php
new file mode 100644
index 0000000..d7495b8
--- /dev/null
+++ b/src/Configuration/adapters/XmlAdapter.php
@@ -0,0 +1,277 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Configuration\Adapters;
+
+use Apache\Log4php\LoggerException;
+
+/**
+ * Converts XML configuration files to a PHP array.
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @since 2.2
+ */
+class XmlAdapter implements AdapterInterface
+{
+ /** Path to the XML schema used for validation. */
+ const SCHEMA_PATH = '/../xml/log4php.xsd';
+
+ private $config = array(
+ 'appenders' => array(),
+ 'loggers' => array(),
+ 'renderers' => array(),
+ );
+
+ public function convert($url) {
+ $xml = $this->loadXML($url);
+
+ $this->parseConfiguration($xml);
+
+ // Parse the <root> node
+ if (isset($xml->root)) {
+ $this->parseRootLogger($xml->root);
+ }
+
+ // Process <logger> nodes
+ foreach($xml->logger as $logger) {
+ $this->parseLogger($logger);
+ }
+
+ // Process <appender> nodes
+ foreach($xml->appender as $appender) {
+ $this->parseAppender($appender);
+ }
+
+ // Process <renderer> nodes
+ foreach($xml->renderer as $rendererNode) {
+ $this->parseRenderer($rendererNode);
+ }
+
+ // Process <defaultRenderer> node
+ foreach($xml->defaultRenderer as $rendererNode) {
+ $this->parseDefaultRenderer($rendererNode);
+ }
+
+ return $this->config;
+ }
+
+ /**
+ * Loads and validates the XML.
+ * @param string $url Input XML.
+ */
+ private function loadXML($url) {
+ if (!file_exists($url)) {
+ throw new LoggerException("File [$url] does not exist.");
+ }
+
+ libxml_clear_errors();
+ $oldValue = libxml_use_internal_errors(true);
+
+ // Load XML
+ $xml = @simplexml_load_file($url);
+ if ($xml === false) {
+
+ $errorStr = "";
+ foreach(libxml_get_errors() as $error) {
+ $errorStr .= $error->message;
+ }
+
+ throw new LoggerException("Error loading configuration file: " . trim($errorStr));
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($oldValue);
+
+ return $xml;
+ }
+
+ /**
+ * Parses the <configuration> node.
+ */
+ private function parseConfiguration(\SimpleXMLElement $xml) {
+ $attributes = $xml->attributes();
+ if (isset($attributes['threshold'])) {
+ $this->config['threshold'] = (string) $attributes['threshold'];
+ }
+ }
+
+ /** Parses an <appender> node. */
+ private function parseAppender(\SimpleXMLElement $node) {
+ $name = $this->getAttributeValue($node, 'name');
+ if (empty($name)) {
+ $this->warn("An <appender> node is missing the required 'name' attribute. Skipping appender definition.");
+ return;
+ }
+
+ $appender = array();
+ $appender['class'] = $this->getAttributeValue($node, 'class');
+
+ if (isset($node['threshold'])) {
+ $appender['threshold'] = $this->getAttributeValue($node, 'threshold');
+ }
+
+ if (isset($node->layout)) {
+ $appender['layout']= $this->parseLayout($node->layout, $name);
+ }
+
+ if (count($node->param) > 0) {
+ $appender['params'] = $this->parseParameters($node);
+ }
+
+ foreach($node->filter as $filterNode) {
+ $appender['filters'][] = $this->parseFilter($filterNode);
+ }
+
+ $this->config['appenders'][$name] = $appender;
+ }
+
+ /** Parses a <layout> node. */
+ private function parseLayout(\SimpleXMLElement $node, $appenderName) {
+ $layout = array();
+ $layout['class'] = $this->getAttributeValue($node, 'class');
+
+ if (count($node->param) > 0) {
+ $layout['params'] = $this->parseParameters($node);
+ }
+
+ return $layout;
+ }
+
+ /** Parses any <param> child nodes returning them in an array. */
+ private function parseParameters($paramsNode) {
+ $params = array();
+
+ foreach($paramsNode->param as $paramNode) {
+ if (empty($paramNode['name'])) {
+ $this->warn("A <param> node is missing the required 'name' attribute. Skipping parameter.");
+ continue;
+ }
+
+ $name = $this->getAttributeValue($paramNode, 'name');
+ $value = $this->getAttributeValue($paramNode, 'value');
+
+ $params[$name] = $value;
+ }
+
+ return $params;
+ }
+
+ /** Parses a <root> node. */
+ private function parseRootLogger(\SimpleXMLElement $node) {
+ $logger = array();
+
+ if (isset($node->level)) {
+ $logger['level'] = $this->getAttributeValue($node->level, 'value');
+ }
+
+ $logger['appenders'] = $this->parseAppenderReferences($node);
+
+ $this->config['rootLogger'] = $logger;
+ }
+
+ /** Parses a <logger> node. */
+ private function parseLogger(\SimpleXMLElement $node) {
+ $logger = array();
+
+ $name = $this->getAttributeValue($node, 'name');
+ if (empty($name)) {
+ $this->warn("A <logger> node is missing the required 'name' attribute. Skipping logger definition.");
+ return;
+ }
+
+ if (isset($node->level)) {
+ $logger['level'] = $this->getAttributeValue($node->level, 'value');
+ }
+
+ if (isset($node['additivity'])) {
+ $logger['additivity'] = $this->getAttributeValue($node, 'additivity');
+ }
+
+ $logger['appenders'] = $this->parseAppenderReferences($node);
+
+ // Check for duplicate loggers
+ if (isset($this->config['loggers'][$name])) {
+ $this->warn("Duplicate logger definition [$name]. Overwriting.");
+ }
+
+ $this->config['loggers'][$name] = $logger;
+ }
+
+ /**
+ * Parses a <logger> node for appender references and returns them in an array.
+ *
+ * Previous versions supported appender-ref, as well as appender_ref so both
+ * are parsed for backward compatibility.
+ */
+ private function parseAppenderReferences(\SimpleXMLElement $node) {
+ $refs = array();
+ foreach($node->appender_ref as $ref) {
+ $refs[] = $this->getAttributeValue($ref, 'ref');
+ }
+
+ foreach($node->{'appender-ref'} as $ref) {
+ $refs[] = $this->getAttributeValue($ref, 'ref');
+ }
+
+ return $refs;
+ }
+
+ /** Parses a <filter> node. */
+ private function parseFilter($filterNode) {
+ $filter = array();
+ $filter['class'] = $this->getAttributeValue($filterNode, 'class');
+
+ if (count($filterNode->param) > 0) {
+ $filter['params'] = $this->parseParameters($filterNode);
+ }
+
+ return $filter;
+ }
+
+ /** Parses a <renderer> node. */
+ private function parseRenderer(\SimpleXMLElement $node) {
+ $renderedClass = $this->getAttributeValue($node, 'renderedClass');
+ $renderingClass = $this->getAttributeValue($node, 'renderingClass');
+
+ $this->config['renderers'][] = compact('renderedClass', 'renderingClass');
+ }
+
+ /** Parses a <defaultRenderer> node. */
+ private function parseDefaultRenderer(\SimpleXMLElement $node) {
+ $renderingClass = $this->getAttributeValue($node, 'renderingClass');
+
+ // Warn on duplicates
+ if(isset($this->config['defaultRenderer'])) {
+ $this->warn("Duplicate <defaultRenderer> node. Overwriting.");
+ }
+
+ $this->config['defaultRenderer'] = $renderingClass;
+ }
+
+ // ******************************************
+ // ** Helper methods **
+ // ******************************************
+
+ private function getAttributeValue(\SimpleXMLElement $node, $name) {
+ return isset($node[$name]) ? (string) $node[$name] : null;
+ }
+
+ private function warn($message) {
+ trigger_error("log4php: " . $message, E_USER_WARNING);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Filters/AbstractFilter.php
----------------------------------------------------------------------
diff --git a/src/Filters/AbstractFilter.php b/src/Filters/AbstractFilter.php
new file mode 100644
index 0000000..81663e3
--- /dev/null
+++ b/src/Filters/AbstractFilter.php
@@ -0,0 +1,126 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Filters;
+
+use Apache\Log4php\Configurable;
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * Users should extend this class to implement customized logging
+ * event filtering. Note that {@link LoggerCategory} and {@link Appender},
+ * the parent class of all standard
+ * appenders, have built-in filtering rules. It is suggested that you
+ * first use and understand the built-in rules before rushing to write
+ * your own custom filters.
+ *
+ * <p>This abstract class assumes and also imposes that filters be
+ * organized in a linear chain. The {@link #decide
+ * decide(LoggingEvent)} method of each filter is called sequentially,
+ * in the order of their addition to the chain.
+ *
+ * <p>The {@link decide()} method must return one
+ * of the integer constants {@link AbstractFilter::DENY},
+ * {@link AbstractFilter::NEUTRAL} or {@link AbstractFilter::ACCEPT}.
+ *
+ * <p>If the value {@link AbstractFilter::DENY} is returned, then the log event is
+ * dropped immediately without consulting with the remaining
+ * filters.
+ *
+ * <p>If the value {@link AbstractFilter::NEUTRAL} is returned, then the next filter
+ * in the chain is consulted. If there are no more filters in the
+ * chain, then the log event is logged. Thus, in the presence of no
+ * filters, the default behaviour is to log all logging events.
+ *
+ * <p>If the value {@link AbstractFilter::ACCEPT} is returned, then the log
+ * event is logged without consulting the remaining filters.
+ *
+ * <p>The philosophy of log4php filters is largely inspired from the
+ * Linux ipchains.
+ */
+abstract class AbstractFilter extends Configurable {
+
+ /**
+ * The log event must be logged immediately without consulting with
+ * the remaining filters, if any, in the chain.
+ */
+ const ACCEPT = 1;
+
+ /**
+ * This filter is neutral with respect to the log event. The
+ * remaining filters, if any, should be consulted for a final decision.
+ */
+ const NEUTRAL = 0;
+
+ /**
+ * The log event must be dropped immediately without consulting
+ * with the remaining filters, if any, in the chain.
+ */
+ const DENY = -1;
+
+ /**
+ * @var AbstractFilter Points to the next {@link AbstractFilter} in the filter chain.
+ */
+ protected $next;
+
+ /**
+ * Usually filters options become active when set. We provide a
+ * default do-nothing implementation for convenience.
+ */
+ public function activateOptions() {
+ }
+
+ /**
+ * Decide what to do.
+ * <p>If the decision is {@link AbstractFilter::DENY}, then the event will be
+ * dropped. If the decision is {@link AbstractFilter::NEUTRAL}, then the next
+ * filter, if any, will be invoked. If the decision is {@link AbstractFilter::ACCEPT} then
+ * the event will be logged without consulting with other filters in
+ * the chain.
+ *
+ * @param LoggingEvent $event The {@link LoggingEvent} to decide upon.
+ * @return integer {@link AbstractFilter::NEUTRAL} or {@link AbstractFilter::DENY}|{@link AbstractFilter::ACCEPT}
+ */
+ public function decide(LoggingEvent $event) {
+ return self::NEUTRAL;
+ }
+
+ /**
+ * Adds a new filter to the filter chain this filter is a part of.
+ * If this filter has already and follow up filter, the param filter
+ * is passed on until it is the last filter in chain.
+ *
+ * @param $filter - the filter to add to this chain
+ */
+ public function addNext($filter) {
+ if($this->next !== null) {
+ $this->next->addNext($filter);
+ } else {
+ $this->next = $filter;
+ }
+ }
+
+ /**
+ * Returns the next filter in this chain
+ * @return the next filter
+ */
+ public function getNext() {
+ return $this->next;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Filters/DenyAllFilter.php
----------------------------------------------------------------------
diff --git a/src/Filters/DenyAllFilter.php b/src/Filters/DenyAllFilter.php
new file mode 100644
index 0000000..1d34357
--- /dev/null
+++ b/src/Filters/DenyAllFilter.php
@@ -0,0 +1,45 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Filters;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * This filter drops all logging events.
+ *
+ * You can add this filter to the end of a filter chain to
+ * switch from the default "accept all unless instructed otherwise"
+ * filtering behaviour to a "deny all unless instructed otherwise"
+ * behaviour.
+ *
+ * @since 0.3
+ */
+class DenyAllFilter extends AbstractFilter {
+
+ /**
+ * Always returns the integer constant {@link AbstractFilter::DENY}
+ * regardless of the {@link LoggingEvent} parameter.
+ *
+ * @param LoggingEvent $event The {@link LoggingEvent} to filter.
+ * @return AbstractFilter::DENY Always returns {@link AbstractFilter::DENY}
+ */
+ public function decide(LoggingEvent $event) {
+ return AbstractFilter::DENY;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Filters/LevelMatchFilter.php
----------------------------------------------------------------------
diff --git a/src/Filters/LevelMatchFilter.php b/src/Filters/LevelMatchFilter.php
new file mode 100644
index 0000000..4573c4c
--- /dev/null
+++ b/src/Filters/LevelMatchFilter.php
@@ -0,0 +1,98 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Filters;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * This is a very simple filter based on level matching.
+ *
+ * <p>The filter admits two options <b><var>LevelToMatch</var></b> and
+ * <b><var>AcceptOnMatch</var></b>. If there is an exact match between the value
+ * of the <b><var>LevelToMatch</var></b> option and the level of the
+ * {@link LoggingEvent}, then the {@link decide()} method returns
+ * {@link AbstractFilter::ACCEPT} in case the <b><var>AcceptOnMatch</var></b>
+ * option value is set to <i>true</i>, if it is <i>false</i> then
+ * {@link AbstractFilter::DENY} is returned. If there is no match,
+ * {@link AbstractFilter::NEUTRAL} is returned.</p>
+ *
+ * <p>
+ * An example for this filter:
+ *
+ * {@example ../../examples/php/filter_levelmatch.php 19}
+ *
+ * <p>
+ * The corresponding XML file:
+ *
+ * {@example ../../examples/resources/filter_levelmatch.xml 18}
+ * @since 0.6
+ */
+class LevelMatchFilter extends AbstractFilter {
+
+ /**
+ * Indicates if this event should be accepted or denied on match
+ * @var boolean
+ */
+ protected $acceptOnMatch = true;
+
+ /**
+ * The level, when to match
+ * @var Level
+ */
+ protected $levelToMatch;
+
+ /**
+ * @param boolean $acceptOnMatch
+ */
+ public function setAcceptOnMatch($acceptOnMatch) {
+ $this->setBoolean('acceptOnMatch', $acceptOnMatch);
+ }
+
+ /**
+ * @param string $l the level to match
+ */
+ public function setLevelToMatch($level) {
+ $this->setLevel('levelToMatch', $level);
+ }
+
+ /**
+ * Return the decision of this filter.
+ *
+ * Returns {@link AbstractFilter::NEUTRAL} if the <b><var>LevelToMatch</var></b>
+ * option is not set or if there is not match. Otherwise, if there is a
+ * match, then the returned decision is {@link AbstractFilter::ACCEPT} if the
+ * <b><var>AcceptOnMatch</var></b> property is set to <i>true</i>. The
+ * returned decision is {@link AbstractFilter::DENY} if the
+ * <b><var>AcceptOnMatch</var></b> property is set to <i>false</i>.
+ *
+ * @param LoggingEvent $event
+ * @return integer
+ */
+ public function decide(LoggingEvent $event) {
+ if($this->levelToMatch === null) {
+ return AbstractFilter::NEUTRAL;
+ }
+
+ if($this->levelToMatch->equals($event->getLevel())) {
+ return $this->acceptOnMatch ? AbstractFilter::ACCEPT : AbstractFilter::DENY;
+ } else {
+ return AbstractFilter::NEUTRAL;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Filters/LevelRangeFilter.php
----------------------------------------------------------------------
diff --git a/src/Filters/LevelRangeFilter.php b/src/Filters/LevelRangeFilter.php
new file mode 100644
index 0000000..d30f5ae
--- /dev/null
+++ b/src/Filters/LevelRangeFilter.php
@@ -0,0 +1,136 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Filters;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * This is a very simple filter based on level matching, which can be
+ * used to reject messages with priorities outside a certain range.
+ *
+ * <p>The filter admits three options <b><var>LevelMin</var></b>, <b><var>LevelMax</var></b>
+ * and <b><var>AcceptOnMatch</var></b>.</p>
+ *
+ * <p>If the level of the {@link LoggingEvent} is not between Min and Max
+ * (inclusive), then {@link AbstractFilter::DENY} is returned.</p>
+ *
+ * <p>If the Logging event level is within the specified range, then if
+ * <b><var>AcceptOnMatch</var></b> is <i>true</i>,
+ * {@link AbstractFilter::ACCEPT} is returned, and if
+ * <b><var>AcceptOnMatch</var></b> is <i>false</i>,
+ * {@link AbstractFilter::NEUTRAL} is returned.</p>
+ *
+ * <p>If <b><var>LevelMin</var></b> is not defined, then there is no
+ * minimum acceptable level (i.e. a level is never rejected for
+ * being too "low"/unimportant). If <b><var>LevelMax</var></b> is not
+ * defined, then there is no maximum acceptable level (ie a
+ * level is never rejected for being too "high"/important).</p>
+ *
+ * <p>Refer to the {@link Appender::setThreshold()} method
+ * available to <b>all</b> appenders extending {@link Appender}
+ * for a more convenient way to filter out events by level.</p>
+ *
+ * <p>
+ * An example for this filter:
+ *
+ * {@example ../../examples/php/filter_levelrange.php 19}
+ *
+ * <p>
+ * The corresponding XML file:
+ *
+ * {@example ../../examples/resources/filter_levelrange.xml 18}
+ *
+ * @author Simon Kitching
+ * @author based on the org.apache.log4j.varia.LevelRangeFilte Java code by Ceki Gülcü
+ * @since 0.6
+ */
+class LevelRangeFilter extends AbstractFilter {
+
+ /**
+ * @var boolean
+ */
+ protected $acceptOnMatch = true;
+
+ /**
+ * @var Level
+ */
+ protected $levelMin;
+
+ /**
+ * @var Level
+ */
+ protected $levelMax;
+
+ /**
+ * @param boolean $acceptOnMatch
+ */
+ public function setAcceptOnMatch($acceptOnMatch) {
+ $this->setBoolean('acceptOnMatch', $acceptOnMatch);
+ }
+
+ /**
+ * @param string $l the level min to match
+ */
+ public function setLevelMin($level) {
+ $this->setLevel('levelMin', $level);
+ }
+
+ /**
+ * @param string $l the level max to match
+ */
+ public function setLevelMax($level) {
+ $this->setLevel('levelMax', $level);
+ }
+
+ /**
+ * Return the decision of this filter.
+ *
+ * @param LoggingEvent $event
+ * @return integer
+ */
+ public function decide(LoggingEvent $event) {
+ $level = $event->getLevel();
+
+ if($this->levelMin !== null) {
+ if($level->isGreaterOrEqual($this->levelMin) == false) {
+ // level of event is less than minimum
+ return AbstractFilter::DENY;
+ }
+ }
+
+ if($this->levelMax !== null) {
+ if($level->toInt() > $this->levelMax->toInt()) {
+ // level of event is greater than maximum
+ // Alas, there is no Level.isGreater method. and using
+ // a combo of isGreaterOrEqual && !Equal seems worse than
+ // checking the int values of the level objects..
+ return AbstractFilter::DENY;
+ }
+ }
+
+ if($this->acceptOnMatch) {
+ // this filter set up to bypass later filters and always return
+ // accept if level in range
+ return AbstractFilter::ACCEPT;
+ } else {
+ // event is ok for this filter; allow later filters to have a look..
+ return AbstractFilter::NEUTRAL;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/79ed2d0d/src/Filters/StringMatchFilter.php
----------------------------------------------------------------------
diff --git a/src/Filters/StringMatchFilter.php b/src/Filters/StringMatchFilter.php
new file mode 100644
index 0000000..152c9c9
--- /dev/null
+++ b/src/Filters/StringMatchFilter.php
@@ -0,0 +1,87 @@
+<?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.
+ */
+
+namespace Apache\Log4php\Filters;
+
+use Apache\Log4php\LoggingEvent;
+
+/**
+ * This is a very simple filter based on string matching.
+ *
+ * <p>The filter admits two options {@link $stringToMatch} and
+ * {@link $acceptOnMatch}. If there is a match (using {@link PHP_MANUAL#strpos}
+ * between the value of the {@link $stringToMatch} option and the message
+ * of the {@link LoggingEvent},
+ * then the {@link decide()} method returns {@link AbstractFilter::ACCEPT} if
+ * the <b>AcceptOnMatch</b> option value is true, if it is false then
+ * {@link AbstractFilter::DENY} is returned. If there is no match, {@link AbstractFilter::NEUTRAL}
+ * is returned.</p>
+ *
+ * <p>
+ * An example for this filter:
+ *
+ * {@example ../../examples/php/filter_stringmatch.php 19}
+ *
+ * <p>
+ * The corresponding XML file:
+ *
+ * {@example ../../examples/resources/filter_stringmatch.xml 18}
+ * @since 0.3
+ */
+class StringMatchFilter extends AbstractFilter {
+
+ /**
+ * @var boolean
+ */
+ protected $acceptOnMatch = true;
+
+ /**
+ * @var string
+ */
+ protected $stringToMatch;
+
+ /**
+ * @param mixed $acceptOnMatch a boolean or a string ('true' or 'false')
+ */
+ public function setAcceptOnMatch($acceptOnMatch) {
+ $this->setBoolean('acceptOnMatch', $acceptOnMatch);
+ }
+
+ /**
+ * @param string $s the string to match
+ */
+ public function setStringToMatch($string) {
+ $this->setString('stringToMatch', $string);
+ }
+
+ /**
+ * @return integer a {@link LOGGER_FILTER_NEUTRAL} is there is no string match.
+ */
+ public function decide(LoggingEvent $event) {
+ $msg = $event->getRenderedMessage();
+
+ if($msg === null or $this->stringToMatch === null) {
+ return AbstractFilter::NEUTRAL;
+ }
+
+ if(strpos($msg, $this->stringToMatch) !== false ) {
+ return ($this->acceptOnMatch) ? AbstractFilter::ACCEPT : AbstractFilter::DENY;
+ }
+ return AbstractFilter::NEUTRAL;
+ }
+}