From 018e5d0659fbac893dd49b1a5314f1293f300e30 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Tue, 14 May 2013 23:21:38 +0200 Subject: [PATCH] Adding Sylog as a logging engine --- lib/Cake/Log/Engine/SyslogLog.php | 158 ++++++++++++++++++ .../Test/Case/Log/Engine/SyslogLogTest.php | 95 +++++++++++ 2 files changed, 253 insertions(+) create mode 100644 lib/Cake/Log/Engine/SyslogLog.php create mode 100644 lib/Cake/Test/Case/Log/Engine/SyslogLogTest.php diff --git a/lib/Cake/Log/Engine/SyslogLog.php b/lib/Cake/Log/Engine/SyslogLog.php new file mode 100644 index 000000000..673aff71a --- /dev/null +++ b/lib/Cake/Log/Engine/SyslogLog.php @@ -0,0 +1,158 @@ + 'SyslogLog', + * 'types' => array('emergency', 'alert', 'critical', 'error'), + * 'format' => "%s: My-App - %s", + * 'prefix' => 'Web Server 01' + * )); + * }}} + * + * @var array + */ + protected $_defaults = array( + 'format' => '%s: %s', + 'flag' => LOG_ODELAY, + 'prefix' => '', + 'facility' => LOG_USER + ); + +/** + * + * Used to map the string names back to their LOG_* constants + * + * @var array + */ + protected $_priorityMap = array( + 'emergency' => LOG_EMERG, + 'alert' => LOG_ALERT, + 'critical' => LOG_CRIT, + 'error' => LOG_ERR, + 'warning' => LOG_WARNING, + 'notice' => LOG_NOTICE, + 'info' => LOG_INFO, + 'debug' => LOG_DEBUG + ); + +/** + * Whether the logger connection is open or not + * + * @var boolean + */ + protected $_open = false; + +/** + * Make sure the configuration contains the format parameter, by default it uses + * the error number and the type as a prefix to the message + * + * @param array $config + */ + public function __construct($config = array()) { + $config += $this->_defaults; + parent::__construct($config); + } + +/** + * Writes a message to syslog + * + * Map the $type back to a LOG_ constant value, split multi-line messages into multiple + * log messages, pass all messages through the format defined in the configuration + * + * @param string $type The type of log you are making. + * @param string $message The message you want to log. + * @return boolean success of write. + */ + public function write($type, $message) { + if (!$this->_open) { + $config = $this->_config; + $this->_open($config['prefix'], $config['flag'], $config['facility']); + $this->_open = true; + } + + $priority = LOG_DEBUG; + if (isset($this->_priorityMap[$type])) { + $priority = $this->_priorityMap[$type]; + } + + $messages = explode("\n", $message); + foreach ($messages as $message) { + $message = sprintf($this->_config['format'], $type, $message); + $this->_write($priority, $message); + } + + return true; + } + +/** + * Wrapper for openlog call + * + * @param int $priority + * @param sting $output + * @return void + */ + public function _open($ident, $options, $facility) { + openlog($ident, $options, $facility); + } + +/** + * Wrapper for syslog call + * + * @param int $priority + * @param sting $output + * @return bool + */ + protected function _write($priority, $output) { + return syslog($priority, $output); + } + +/** + * Closes the logger connection + * + * @return void + **/ + public function __destruct() { + closelog(); + } + +} diff --git a/lib/Cake/Test/Case/Log/Engine/SyslogLogTest.php b/lib/Cake/Test/Case/Log/Engine/SyslogLogTest.php new file mode 100644 index 000000000..e6faabfd9 --- /dev/null +++ b/lib/Cake/Test/Case/Log/Engine/SyslogLogTest.php @@ -0,0 +1,95 @@ + + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests + * @package Cake.Test.Case.Log.Engine + * @since CakePHP(tm) v 2.4 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ +App::uses('SyslogLog', 'Log/Engine'); + +/** + * SyslogLogTest class + * + * @package Cake.Test.Case.Log.Engine + */ +class SyslogLogTest extends CakeTestCase { + +/** + * Tests that the connection to the logger is open with the right arguments + * + * @return void + */ + public function testOpenLog() { + $log = $this->getMock('SyslogLog', array('_open', '_write')); + $log->expects($this->once())->method('_open')->with('', LOG_ODELAY, LOG_USER); + $log->write('debug', 'message'); + + $log = $this->getMock('SyslogLog', array('_open', '_write')); + $log->config(array( + 'prefix' => 'thing', + 'flag' => LOG_NDELAY, + 'facility' => LOG_MAIL, + 'format' => '%s: %s' + )); + $log->expects($this->once())->method('_open') + ->with('thing', LOG_NDELAY, LOG_MAIL); + $log->write('debug', 'message'); + } + +/** + * Tests that single lines are written to syslog + * + * @dataProvider typesProvider + * @return void + */ + public function testWriteOneLine($type, $expected) { + $log = $this->getMock('SyslogLog', array('_open', '_write')); + $log->expects($this->once())->method('_write')->with($expected, $type . ': Foo'); + $log->write($type, 'Foo'); + } + +/** + * Tests that multiple lines are split and logged separately + * + * @return void + */ + public function testWriteMultiLine() { + $log = $this->getMock('SyslogLog', array('_open', '_write')); + $log->expects($this->at(1))->method('_write')->with(LOG_DEBUG, 'debug: Foo'); + $log->expects($this->at(2))->method('_write')->with(LOG_DEBUG, 'debug: Bar'); + $log->expects($this->exactly(2))->method('_write'); + $log->write('debug', "Foo\nBar"); + } + +/** + * Data provider for the write function test + * + * @return array + */ + public function typesProvider() { + return array( + array('emergency', LOG_EMERG), + array('alert', LOG_ALERT), + array('critical', LOG_CRIT), + array('error', LOG_ERR), + array('warning', LOG_WARNING), + array('notice', LOG_NOTICE), + array('info', LOG_INFO), + array('debug', LOG_DEBUG) + ); + } + +} +