Merge pull request #4430 from sminnee/logging-refactor

Replace Zend log with Monolog; rely more on PSR-3
This commit is contained in:
Damian Mooyman 2015-09-01 11:41:05 +12:00
commit f3f0315cc1
45 changed files with 899 additions and 4240 deletions

45
_config/logging.yml Normal file
View File

@ -0,0 +1,45 @@
---
Name: logging
---
Injector:
ErrorHandler:
class: SilverStripe\Framework\Logging\MonologErrorHandler
properties:
Logger: %$Logger
Logger:
type: singleton
class: Monolog\Logger
constructor:
- "error-log"
calls:
DisplayErrorHandler: [ pushHandler, [ %$DisplayErrorHandler ] ]
---
Name: dev-logging
Only:
environment: dev
---
Injector:
DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler
constructor:
- "notice"
properties:
Formatter: %$SilverStripe\Framework\Logging\DetailedErrorFormatter
---
Name: live-logging
Except:
environment: dev
---
Injector:
DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler
constructor:
- "error"
properties:
Formatter: %$FriendlyErrorFormatter
FriendlyErrorFormatter:
class: SilverStripe\Framework\Logging\DebugViewFriendlyErrorFormatter
properties:
Title: "There has been an error"
Body: "The website server has not been able to respond to your request"

View File

@ -17,7 +17,8 @@
], ],
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"composer/installers": "~1.0" "composer/installers": "~1.0",
"monolog/monolog": "~1.11"
}, },
"require-dev": { "require-dev": {
"phpunit/PHPUnit": "~3.7" "phpunit/PHPUnit": "~3.7"

View File

@ -50,6 +50,9 @@
* @subpackage core * @subpackage core
*/ */
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
/* /*
* _ss_environment.php handler * _ss_environment.php handler
*/ */
@ -139,7 +142,12 @@ if(defined('SS_USE_BASIC_AUTH') && SS_USE_BASIC_AUTH) {
} }
if(defined('SS_ERROR_LOG')) { if(defined('SS_ERROR_LOG')) {
SS_Log::add_writer(new SS_LogFileWriter(BASE_PATH . '/' . SS_ERROR_LOG), SS_Log::WARN, '<='); $logger = Injector::inst()->get('Logger');
if($logger instanceof Logger) {
$logger->pushHandler(new StreamHandler(BASE_PATH . '/' . SS_ERROR_LOG, Logger::WARN));
} else {
user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
}
} }
// Allow database adapters to handle their own configuration // Allow database adapters to handle their own configuration

View File

@ -271,7 +271,10 @@ EOT
// an error, and the response doesn't have any body yet that might contain // an error, and the response doesn't have any body yet that might contain
// a more specific error description. // a more specific error description.
if(Director::isLive() && $this->isError() && !$this->body) { if(Director::isLive() && $this->isError() && !$this->body) {
Debug::friendlyError($this->statusCode, $this->getStatusDescription()); $formatter = Injector::get('FriendlyErrorFormatter');
$formatter->setStatusCode($this->statusCode);
echo $formatter->format(array());
} else { } else {
echo $this->body; echo $this->body;
} }

View File

@ -70,9 +70,8 @@ require_once 'view/TemplateGlobalProvider.php';
require_once 'control/Director.php'; require_once 'control/Director.php';
require_once 'dev/Debug.php'; require_once 'dev/Debug.php';
require_once 'dev/DebugView.php'; require_once 'dev/DebugView.php';
require_once 'dev/CliDebugView.php';
require_once 'dev/Backtrace.php'; require_once 'dev/Backtrace.php';
require_once 'dev/ZendLog.php';
require_once 'dev/Log.php';
require_once 'filesystem/FileFinder.php'; require_once 'filesystem/FileFinder.php';
require_once 'core/manifest/ManifestCache.php'; require_once 'core/manifest/ManifestCache.php';
require_once 'core/manifest/ClassLoader.php'; require_once 'core/manifest/ClassLoader.php';
@ -136,8 +135,9 @@ if(Director::isLive()) {
/** /**
* Load error handlers * Load error handlers
*/ */
Debug::loadErrorHandlers();
$errorHandler = Injector::inst()->get('ErrorHandler');
$errorHandler->start();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS // HELPER FUNCTIONS

View File

@ -9,49 +9,60 @@
* @todo Perhaps DebugView should be an interface / ABC, implemented by HTMLDebugView and CliDebugView? * @todo Perhaps DebugView should be an interface / ABC, implemented by HTMLDebugView and CliDebugView?
*/ */
class CliDebugView extends DebugView { class CliDebugView extends DebugView
{
/** /**
* Render HTML header for development views * Render HTML header for development views
*/ */
public function writeHeader($httpRequest = null) { public function renderHeader($httpRequest = null) {
} }
/** /**
* Render HTML footer for development views * Render HTML footer for development views
*/ */
public function writeFooter() { public function renderFooter() {
} }
/** /**
* Write information about the error to the screen * Write information about the error to the screen
*/ */
public function writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext) { public function renderError($httpRequest, $errno, $errstr, $errfile, $errline) {
$errorType = self::$error_types[$errno]; if(!isset(self::$error_types[$errno])) {
echo SS_Cli::text("ERROR [" . $errorType['title'] . "]: $errstr\nIN $httpRequest\n", "red", null, true); $errorTypeTitle = "UNKNOWN TYPE, ERRNO $errno";
echo SS_Cli::text("Line $errline in $errfile\n\n", "red"); } else {
$errorTypeTitle = self::$error_types[$errno]['title'];
}
$output = SS_Cli::text("ERROR [" . $errorTypeTitle . "]: $errstr\nIN $httpRequest\n", "red", null, true);
$output .= SS_Cli::text("Line $errline in $errfile\n\n", "red");
return $output;
} }
/** /**
* Write a fragment of the a source file * Write a fragment of the a source file
* @param $lines An array of file lines; the keys should be the original line numbers * @param $lines An array of file lines; the keys should be the original line numbers
*/ */
public function writeSourceFragment($lines, $errline) { public function renderSourceFragment($lines, $errline) {
echo "Source\n======\n"; $output = "Source\n======\n";
foreach($lines as $offset => $line) { foreach($lines as $offset => $line) {
echo ($offset == $errline) ? "* " : " "; $output .= ($offset == $errline) ? "* " : " ";
echo str_pad("$offset:",5); $output .= str_pad("$offset:", 5);
echo wordwrap($line, self::config()->columns, "\n "); $output .= wordwrap($line, self::config()->columns, "\n ");
} }
echo "\n"; $output .= "\n";
return $output;
} }
/** /**
* Write a backtrace * Write a backtrace
*/ */
public function writeTrace($trace = null) { public function renderTrace($trace = null) {
echo "Trace\n=====\n"; $output = "Trace\n=====\n";
echo SS_Backtrace::get_rendered_backtrace($trace ? $trace : debug_backtrace(), true); $output .= SS_Backtrace::get_rendered_backtrace($trace ? $trace : debug_backtrace(), true);
return $output;
} }
/** /**
@ -60,26 +71,30 @@ class CliDebugView extends DebugView {
* @param string $title * @param string $title
* @param string $title * @param string $title
*/ */
public function writeInfo($title, $subtitle, $description=false) { public function renderInfo($title, $subtitle, $description=false) {
echo wordwrap(strtoupper($title),self::config()->columns) . "\n"; $output = wordwrap(strtoupper($title), self::config()->columns) . "\n";
echo wordwrap($subtitle,self::config()->columns) . "\n"; $output .= wordwrap($subtitle, self::config()->columns) . "\n";
echo str_repeat('-',min(self::config()->columns,max(strlen($title),strlen($subtitle)))) . "\n"; $output .= str_repeat('-', min(self::config()->columns, max(strlen($title), strlen($subtitle)))) . "\n";
echo wordwrap($description,self::config()->columns) . "\n\n"; $output .= wordwrap($description, self::config()->columns) . "\n\n";
return $output;
} }
public function writeVariable($val, $caller) { public function renderVariable($val, $caller) {
echo PHP_EOL; $output = PHP_EOL;
echo SS_Cli::text(str_repeat('=', self::config()->columns), 'green'); $output .= SS_Cli::text(str_repeat('=', self::config()->columns), 'green');
echo PHP_EOL; $output .= PHP_EOL;
echo SS_Cli::text($this->formatCaller($caller), 'blue', null, true); $output .= SS_Cli::text($this->formatCaller($caller), 'blue', null, true);
echo PHP_EOL.PHP_EOL; $output .= PHP_EOL.PHP_EOL;
if (is_string($val)) { if (is_string($val)) {
print_r(wordwrap($val, self::config()->columns)); $output .= wordwrap($val, self::config()->columns);
} else { } else {
print_r($val); $output .= var_export($val, true);
} }
echo PHP_EOL; $output .= PHP_EOL;
echo SS_Cli::text(str_repeat('=', self::config()->columns), 'green'); $output .= SS_Cli::text(str_repeat('=', self::config()->columns), 'green');
echo PHP_EOL; $output .= PHP_EOL;
return $output;
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* Supports debugging and core error handling. * Supports debugging and core error handling.
* *
@ -24,28 +25,6 @@
*/ */
class Debug { class Debug {
/**
* @config
* @var String indicating the file where errors are logged.
* Filename is relative to the site root.
* The named file will have a terse log sent to it, and the full log (an
* encoded file containing backtraces and things) will go to a file of a similar
* name, but with the suffix ".full" added.
*/
private static $log_errors_to = null;
/**
* @config
* @var string The header of the message shown to users on the live site when a fatal error occurs.
*/
private static $friendly_error_header = 'There has been an error';
/**
* @config
* @var string The body of the message shown to users on the live site when a fatal error occurs.
*/
private static $friendly_error_detail = 'The website server has not been able to respond to your request.';
/** /**
* Show the contents of val in a debug-friendly way. * Show the contents of val in a debug-friendly way.
* Debug::show() is intended to be equivalent to dprintr() * Debug::show() is intended to be equivalent to dprintr()
@ -169,204 +148,6 @@ class Debug {
} }
} }
// Keep track of how many headers have been sent
private static $headerCount = 0;
/**
* Send a debug message in an HTTP header. Only works if you are
* on Dev, and headers have not yet been sent.
*
* @param string $msg
* @param string $prefix (optional)
* @return void
*/
public static function header($msg, $prefix = null) {
if (Director::isDev() && !headers_sent()) {
self::$headerCount++;
header('SS-'.self::$headerCount.($prefix?'-'.$prefix:'').': '.$msg);
}
}
/**
* Log to a standard text file output.
*
* @param $message string to output
*/
public static function log($message) {
if (defined('BASE_PATH')) {
$path = BASE_PATH;
}
else {
$path = dirname(__FILE__) . '/../..';
}
$file = $path . '/debug.log';
$now = date('r');
$content = "\n\n== $now ==\n$message\n";
file_put_contents($file, $content, FILE_APPEND);
}
/**
* Load error handlers into environment.
* Caution: The error levels default to E_ALL is the site is in dev-mode (set in main.php).
*/
public static function loadErrorHandlers() {
set_error_handler('errorHandler', error_reporting());
set_exception_handler('exceptionHandler');
}
public static function noticeHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() == 0) return;
ini_set('display_errors', 0);
// Send out the error details to the logger for writing
SS_Log::log(
array(
'errno' => $errno,
'errstr' => $errstr,
'errfile' => $errfile,
'errline' => $errline,
'errcontext' => $errcontext
),
SS_Log::NOTICE
);
if(Director::isDev()) {
return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice");
} else {
return false;
}
}
/**
* Handle a non-fatal warning error thrown by PHP interpreter.
*
* @param unknown_type $errno
* @param unknown_type $errstr
* @param unknown_type $errfile
* @param unknown_type $errline
* @param unknown_type $errcontext
*/
public static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() == 0) return;
ini_set('display_errors', 0);
// Send out the error details to the logger for writing
SS_Log::log(
array(
'errno' => $errno,
'errstr' => $errstr,
'errfile' => $errfile,
'errline' => $errline,
'errcontext' => $errcontext
),
SS_Log::WARN
);
if(Director::isDev()) {
return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning");
} else {
return false;
}
}
/**
* Handle a fatal error, depending on the mode of the site (ie: Dev, Test, or Live).
*
* Runtime execution dies immediately once the error is generated.
*
* @param unknown_type $errno
* @param unknown_type $errstr
* @param unknown_type $errfile
* @param unknown_type $errline
* @param unknown_type $errcontext
*/
public static function fatalHandler($errno, $errstr, $errfile, $errline, $errcontext) {
ini_set('display_errors', 0);
// Send out the error details to the logger for writing
SS_Log::log(
array(
'errno' => $errno,
'errstr' => $errstr,
'errfile' => $errfile,
'errline' => $errline,
'errcontext' => $errcontext
),
SS_Log::ERR
);
if(Director::isDev() || Director::is_cli()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
} else {
self::friendlyError();
}
return false;
}
/**
* Render a user-facing error page, using the default HTML error template
* rendered by {@link ErrorPage} if it exists. Doesn't use the standard {@link SS_HTTPResponse} class
* the keep dependencies minimal.
*
* @uses ErrorPage
*
* @param int $statusCode HTTP Status Code (Default: 500)
* @param string $friendlyErrorMessage User-focused error message. Should not contain code pointers
* or "tech-speak". Used in the HTTP Header and ajax responses.
* @param string $friendlyErrorDetail Detailed user-focused message. Is just used if no {@link ErrorPage} is found
* for this specific status code.
* @return string HTML error message for non-ajax requests, plaintext for ajax-request.
*/
public static function friendlyError($statusCode=500, $friendlyErrorMessage=null, $friendlyErrorDetail=null) {
if(!$friendlyErrorMessage) {
$friendlyErrorMessage = Config::inst()->get('Debug', 'friendly_error_header');
}
if(!$friendlyErrorDetail) {
$friendlyErrorDetail = Config::inst()->get('Debug', 'friendly_error_detail');
}
if(!headers_sent()) {
// Ensure the error message complies with the HTTP 1.1 spec
$msg = strip_tags(str_replace(array("\n", "\r"), '', $friendlyErrorMessage));
if(Controller::has_curr()) {
$response = Controller::curr()->getResponse();
$response->setStatusCode($statusCode, $msg);
} else {
header($_SERVER['SERVER_PROTOCOL'] . " $statusCode $msg");
}
}
if(Director::is_ajax()) {
echo $friendlyErrorMessage;
} else {
if(class_exists('ErrorPage')){
$errorFilePath = ErrorPage::get_filepath_for_errorcode(
$statusCode,
class_exists('Translatable') ? Translatable::get_current_locale() : null
);
if(file_exists($errorFilePath)) {
$content = file_get_contents($errorFilePath);
if(!headers_sent()) header('Content-Type: text/html');
// $BaseURL is left dynamic in error-###.html, so that multi-domain sites don't get broken
echo str_replace('$BaseURL', Director::absoluteBaseURL(), $content);
}
} else {
$renderer = new DebugView();
$renderer->writeHeader();
$renderer->writeInfo("Website Error", $friendlyErrorMessage, $friendlyErrorDetail);
if(Email::config()->admin_email) {
$mailto = Email::obfuscate(Email::config()->admin_email);
$renderer->writeParagraph('Contact an administrator: ' . $mailto . '');
}
$renderer->writeFooter();
}
}
return false;
}
/** /**
* Create an instance of an appropriate DebugView object. * Create an instance of an appropriate DebugView object.
* *
@ -379,84 +160,6 @@ class Debug {
return Injector::inst()->get($service); return Injector::inst()->get($service);
} }
/**
* Render a developer facing error page, showing the stack trace and details
* of the code where the error occured.
*
* @param unknown_type $errno
* @param unknown_type $errstr
* @param unknown_type $errfile
* @param unknown_type $errline
* @param unknown_type $errcontext
*/
public static function showError($errno, $errstr, $errfile, $errline, $errcontext, $errtype) {
if(!headers_sent()) {
$errText = "$errtype at line $errline of $errfile";
$errText = str_replace(array("\n","\r")," ",$errText);
if(!headers_sent()) header($_SERVER['SERVER_PROTOCOL'] . " 500 $errText");
// if error is displayed through ajax with CliDebugView, use plaintext output
if(Director::is_ajax()) {
header('Content-Type: text/plain');
}
}
$reporter = self::create_debug_view();
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
$httpRequest = null;
if(isset($_SERVER['REQUEST_URI'])) {
$httpRequest = $_SERVER['REQUEST_URI'];
} elseif(isset($_REQUEST['url'])) {
$httpRequest = $_REQUEST['url'];
}
if(isset($_SERVER['REQUEST_METHOD'])) $httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
$reporter->writeHeader($httpRequest);
$reporter->writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext);
if(file_exists($errfile)) {
$lines = file($errfile);
// Make the array 1-based
array_unshift($lines,"");
unset($lines[0]);
$offset = $errline-10;
$lines = array_slice($lines, $offset, 16, true);
$reporter->writeSourceFragment($lines, $errline);
}
$reporter->writeTrace(($errcontext ? $errcontext : debug_backtrace()));
$reporter->writeFooter();
return false;
}
/**
* Utility method to render a snippet of PHP source code, from selected file
* and highlighting the given line number.
*
* @param string $errfile
* @param int $errline
*/
public static function showLines($errfile, $errline) {
$lines = file($errfile);
$offset = $errline-10;
$lines = array_slice($lines, $offset, 16);
echo '<pre>';
$offset++;
foreach($lines as $line) {
$line = htmlentities($line, ENT_COMPAT, 'UTF-8');
if ($offset == $errline) {
echo "<span>$offset</span> <span class=\"error\">$line</span>";
} else {
echo "<span>$offset</span> $line";
}
$offset++;
}
echo '</pre>';
}
/** /**
* Check if the user has permissions to run URL debug tools, * Check if the user has permissions to run URL debug tools,
* else redirect them to log in. * else redirect them to log in.
@ -501,65 +204,3 @@ class Debug {
die(); die();
} }
} }
/**
* Generic callback, to catch uncaught exceptions when they bubble up to the top of the call chain.
*
* @ignore
* @param Exception $exception
*/
function exceptionHandler($exception) {
$errno = E_USER_ERROR;
$type = get_class($exception);
$message = "Uncaught " . $type . ": " . $exception->getMessage();
$file = $exception->getFile();
$line = $exception->getLine();
$context = $exception->getTrace();
Debug::fatalHandler($errno, $message, $file, $line, $context);
exit(1);
}
/**
* Generic callback to catch standard PHP runtime errors thrown by the interpreter
* or manually triggered with the user_error function. Any unknown error codes are treated as
* fatal errors.
* Caution: The error levels default to E_ALL if the site is in dev-mode (set in main.php).
*
* @ignore
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
*/
function errorHandler($errno, $errstr, $errfile, $errline) {
switch($errno) {
case E_NOTICE:
case E_USER_NOTICE:
case E_DEPRECATED:
case E_USER_DEPRECATED:
case E_STRICT:
return Debug::noticeHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
case E_WARNING:
case E_CORE_WARNING:
case E_USER_WARNING:
case E_RECOVERABLE_ERROR:
return Debug::warningHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
default:
Debug::fatalHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
exit(1);
}
}

View File

@ -11,7 +11,8 @@
* @package framework * @package framework
* @subpackage dev * @subpackage dev
*/ */
class DebugView extends Object { class DebugView extends Object
{
/** /**
* Column size to wrap long strings to * Column size to wrap long strings to
@ -22,6 +23,38 @@ class DebugView extends Object {
private static $columns = 100; private static $columns = 100;
protected static $error_types = array( protected static $error_types = array(
0 => array(
'title' => 'Emergency',
'class' => 'error'
),
1 => array(
'title' => 'Alert',
'class' => 'error'
),
2 => array(
'title' => 'Critical',
'class' => 'error'
),
3 => array(
'title' => 'Error',
'class' => 'error'
),
4 => array(
'title' => 'Warning',
'class' => 'warning'
),
5 => array(
'title' => 'Notice',
'class' => 'notice'
),
6 => array(
'title' => 'Information',
'class' => 'info'
),
7=> array(
'title' => 'Debug',
'class' => 'debug'
),
E_USER_ERROR => array( E_USER_ERROR => array(
'title' => 'User Error', 'title' => 'User Error',
'class' => 'error' 'class' => 'error'
@ -100,9 +133,66 @@ class DebugView extends Object {
} }
/** /**
* Render HTML header for development views * @deprecated 4.0.0:5.0.0 Use renderHeader() instead
*/ */
public function writeHeader() { public function writeHeader() {
Deprecation::notice('4.0', 'Use renderHeader() instead');
echo $this->renderHeader();
}
/**
* @deprecated 4.0.0:5.0.0 Use renderInfo() instead
*/
public function writeInfo($title, $subtitle, $description=false) {
Deprecation::notice('4.0', 'Use renderInfo() instead');
echo $this->renderInfo($title, $subtitle, $description);
}
/**
* @deprecated 4.0.0:5.0.0 Use renderFooter() instead
*/
public function writeFooter() {
Deprecation::notice('4.0', 'Use renderFooter() instead');
echo $this->renderFooter();
}
/**
* @deprecated 4.0.0:5.0.0 Use renderError() instead
*/
public function writeError($httpRequest, $errno, $errstr, $errfile, $errline) {
Deprecation::notice('4.0', 'Use renderError() instead');
echo $this->renderError($httpRequest, $errno, $errstr, $errfile, $errline);
}
/**
* @deprecated 4.0.0:5.0.0 Use renderSourceFragment() instead
*/
public function writeSourceFragment($lines, $errline) {
Deprecation::notice('4.0', 'Use renderSourceFragment() instead');
echo $this->renderSourceFragment($lines, $errline);
}
/**
* @deprecated 4.0.0:5.0.0 Use renderTrace() instead
*/
public function writeTrace($trace) {
Deprecation::notice('4.0', 'Use renderTrace() instead');
echo $this->renderTrace($trace);
}
/**
* @deprecated 4.0.0:5.0.0 Use renderVariable() instead
*/
public function writeVariable($val, $caller) {
Deprecation::notice('4.0', 'Use renderVariable() instead');
echo $this->renderVariable($val, $caller);
}
/**
* Render HTML header for development views
* @return string
*/
public function renderHeader() {
$url = htmlentities( $url = htmlentities(
$_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'],
ENT_COMPAT, ENT_COMPAT,
@ -115,41 +205,55 @@ class DebugView extends Object {
'css/debug.css' 'css/debug.css'
); );
echo '<!DOCTYPE html><html><head><title>' . $url . '</title>'; $output = '<!DOCTYPE html><html><head><title>' . $url . '</title>';
echo '<link rel="stylesheet" type="text/css" href="'. $debugCSS .'" />'; $output .= '<link rel="stylesheet" type="text/css" href="'. $debugCSS .'" />';
echo '</head>'; $output .= '</head>';
echo '<body>'; $output .= '<body>';
return $output;
} }
/** /**
* Render the information header for the view * Render the information header for the view
* *
* @param string $title * @param string $title The main title
* @param string $title * @param string $subtitle The subtitle
* @param string|false $description The description to show
* @return string
*/ */
public function writeInfo($title, $subtitle, $description=false) { public function renderInfo($title, $subtitle, $description=false) {
echo '<div class="info">'; $output = '<div class="info">';
echo "<h1>" . Convert::raw2xml($title) . "</h1>"; $output .= "<h1>" . Convert::raw2xml($title) . "</h1>";
if($subtitle) echo "<h3>" . Convert::raw2xml($subtitle) . "</h3>"; if($subtitle) $output .= "<h3>" . Convert::raw2xml($subtitle) . "</h3>";
if ($description) { if ($description) {
echo "<p>$description</p>"; $output .= "<p>$description</p>";
} else { } else {
echo $this->Breadcrumbs(); $output .= $this->Breadcrumbs();
} }
echo '</div>'; $output .= '</div>';
return $output;
} }
/** /**
* Render HTML footer for development views * Render HTML footer for development views
* @return string
*/ */
public function writeFooter() { public function renderFooter() {
echo "</body></html>"; return "</body></html>";
} }
/** /**
* Write information about the error to the screen * Render an error.
*
* @param string $httpRequest the kind of request
* @param int $errno Codenumber of the error
* @param string $errstr The error message
* @param string $errfile The name of the soruce code file where the error occurred
* @param int $errline The line number on which the error occured
* @return string
*/ */
public function writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext) { public function renderError($httpRequest, $errno, $errstr, $errfile, $errline) {
$errorType = isset(self::$error_types[$errno]) ? self::$error_types[$errno] : self::$unknown_error; $errorType = isset(self::$error_types[$errno]) ? self::$error_types[$errno] : self::$unknown_error;
$httpRequestEnt = htmlentities($httpRequest, ENT_COMPAT, 'UTF-8'); $httpRequestEnt = htmlentities($httpRequest, ENT_COMPAT, 'UTF-8');
if (ini_get('html_errors')) { if (ini_get('html_errors')) {
@ -157,51 +261,66 @@ class DebugView extends Object {
} else { } else {
$errstr = Convert::raw2xml($errstr); $errstr = Convert::raw2xml($errstr);
} }
echo '<div class="info ' . $errorType['class'] . '">'; $output = '<div class="info ' . $errorType['class'] . '">';
echo "<h1>[" . $errorType['title'] . '] ' . $errstr . "</h1>"; $output .= "<h1>[" . $errorType['title'] . '] ' . $errstr . "</h1>";
echo "<h3>$httpRequestEnt</h3>"; $output .= "<h3>$httpRequestEnt</h3>";
echo "<p>Line <strong>$errline</strong> in <strong>$errfile</strong></p>"; $output .= "<p>Line <strong>$errline</strong> in <strong>$errfile</strong></p>";
echo '</div>'; $output .= '</div>';
return $output;
} }
/** /**
* Write a fragment of the a source file * Render a fragment of the a source file
* @param $lines An array of file lines; the keys should be the original line numbers *
* @param array $lines An array of file lines; the keys should be the original line numbers
* @param int errLine The line of the error
* @return string
*/ */
public function writeSourceFragment($lines, $errline) { public function renderSourceFragment($lines, $errline) {
echo '<div class="trace"><h3>Source</h3>'; $output = '<div class="trace"><h3>Source</h3>';
echo '<pre>'; $output .= '<pre>';
foreach($lines as $offset => $line) { foreach($lines as $offset => $line) {
$line = htmlentities($line, ENT_COMPAT, 'UTF-8'); $line = htmlentities($line, ENT_COMPAT, 'UTF-8');
if ($offset == $errline) { if ($offset == $errline) {
echo "<span>$offset</span> <span class=\"error\">$line</span>"; $output .= "<span>$offset</span> <span class=\"error\">$line</span>";
} else { } else {
echo "<span>$offset</span> $line"; $output .= "<span>$offset</span> $line";
} }
} }
echo '</pre>'; $output .= '</pre>';
return $output;
} }
/** /**
* Write a backtrace * Render a call track
*
* @param array $trace The debug_backtrace() array
* @return string
*/ */
public function writeTrace($trace) { public function renderTrace($trace) {
echo '<h3>Trace</h3>'; $output = '<h3>Trace</h3>';
echo SS_Backtrace::get_rendered_backtrace($trace); $output .= SS_Backtrace::get_rendered_backtrace($trace);
echo '</div>'; $output .= '</div>';
return $output;
} }
/** /**
* @param string $text * Render an arbitrary paragraph.
*
* @param string $text The HTML-escaped text to render
* @return string
*/ */
public function writeParagraph($text) { public function renderParagraph($text) {
echo '<p class="info">' . $text . '</p>'; return '<p class="info">' . $text . '</p>';
} }
/** /**
* Formats the caller of a method * Formats the caller of a method
* *
* @param array $caller * @param array $caller
* @return string * @return string
*/ */
protected function formatCaller($caller) { protected function formatCaller($caller) {
@ -215,14 +334,17 @@ class DebugView extends Object {
/** /**
* Outputs a variable in a user presentable way * Outputs a variable in a user presentable way
* *
* @param object $val * @param object $val
* @param array $caller Caller information * @param array $caller Caller information
* @return string
*/ */
public function writeVariable($val, $caller) { public function renderVariable($val, $caller) {
echo '<pre style="background-color:#ccc;padding:5px;font-size:14px;line-height:18px;">'; $output = '<pre style="background-color:#ccc;padding:5px;font-size:14px;line-height:18px;">';
echo "<span style=\"font-size: 12px;color:#666;\">" . $this->formatCaller($caller). " - </span>\n"; $output .= "<span style=\"font-size: 12px;color:#666;\">" . $this->formatCaller($caller). " - </span>\n";
if (is_string($val)) print_r(wordwrap($val, self::config()->columns)); if (is_string($val)) $output .= wordwrap($val, self::config()->columns);
else print_r($val); else $output .= var_export($val, true);
echo '</pre>'; $output .= '</pre>';
return $output;
} }
} }

View File

@ -1,185 +0,0 @@
<?php
require_once 'Zend/Log.php';
/**
* Wrapper class for a logging handler like {@link Zend_Log}
* which takes a message (or a map of context variables) and
* sends it to one or more {@link Zend_Log_Writer_Abstract}
* subclasses for output.
*
* These priorities are currently supported:
* - SS_Log::ERR
* - SS_Log::WARN
* - SS_Log::NOTICE
*
* You can add an error writer by calling {@link SS_Log::add_writer()}
*
* Example usage of logging errors by email notification:
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::ERR);
* </code>
*
* Example usage of logging errors by file:
* <code>
* SS_Log::add_writer(new SS_LogFileWriter('/var/log/silverstripe/errors.log'), SS_Log::ERR);
* </code>
*
* Example usage of logging at warnings and errors by setting the priority to '<=':
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::WARN, '<=');
* </code>
*
* Each writer object can be assigned a formatter. The formatter is
* responsible for formatting the message before giving it to the writer.
* {@link SS_LogErrorEmailFormatter} is such an example that formats errors
* into HTML for human readability in an email client.
*
* Formatters are added to writers like this:
* <code>
* $logEmailWriter = new SS_LogEmailWriter('my@email.com');
* $myEmailFormatter = new MyLogEmailFormatter();
* $logEmailWriter->setFormatter($myEmailFormatter);
* </code>
*
* @package framework
* @subpackage dev
*/
class SS_Log {
const ERR = Zend_Log::ERR;
const WARN = Zend_Log::WARN;
const NOTICE = Zend_Log::NOTICE;
const INFO = Zend_Log::INFO;
const DEBUG = Zend_Log::DEBUG;
/**
* Logger class to use.
* @see SS_Log::get_logger()
* @var string
*/
public static $logger_class = 'SS_ZendLog';
/**
* @see SS_Log::get_logger()
* @var object
*/
protected static $logger;
/**
* @var array Logs additional context from PHP's superglobals.
* Caution: Depends on logger implementation (mainly targeted at {@link SS_LogEmailWriter}).
* @see http://framework.zend.com/manual/en/zend.log.overview.html#zend.log.overview.understanding-fields
*/
protected static $log_globals = array(
'_SERVER' => array(
'HTTP_ACCEPT',
'HTTP_ACCEPT_CHARSET',
'HTTP_ACCEPT_ENCODING',
'HTTP_ACCEPT_LANGUAGE',
'HTTP_REFERRER',
'HTTP_USER_AGENT',
'HTTPS',
'REMOTE_ADDR',
),
);
/**
* Get the logger currently in use, or create a new one if it doesn't exist.
*
* @return object
*/
public static function get_logger() {
if(!static::$logger) {
// Create default logger
static::$logger = new static::$logger_class;
// Add default context (shouldn't change until the actual log event happens)
foreach(static::$log_globals as $globalName => $keys) {
foreach($keys as $key) {
$val = isset($GLOBALS[$globalName][$key]) ? $GLOBALS[$globalName][$key] : null;
static::$logger->setEventItem(sprintf('$%s[\'%s\']', $globalName, $key), $val);
}
}
}
return static::$logger;
}
/**
* Get all writers in use by the logger.
* @return array Collection of Zend_Log_Writer_Abstract instances
*/
public static function get_writers() {
return static::get_logger()->getWriters();
}
/**
* Remove all writers currently in use.
*/
public static function clear_writers() {
static::get_logger()->clearWriters();
}
/**
* Remove a writer instance from the logger.
* @param object $writer Zend_Log_Writer_Abstract instance
*/
public static function remove_writer($writer) {
static::get_logger()->removeWriter($writer);
}
/**
* Add a writer instance to the logger.
* @param object $writer Zend_Log_Writer_Abstract instance
* @param const $priority Priority. Possible values: SS_Log::ERR, SS_Log::WARN or SS_Log::NOTICE
* @param $comparison Priority comparison operator. Acts on the integer values of the error
* levels, where more serious errors are lower numbers. By default this is "=", which means only
* the given priority will be logged. Set to "<=" if you want to track errors of *at least*
* the given priority.
*/
public static function add_writer($writer, $priority = null, $comparison = '=') {
if($priority) $writer->addFilter(new Zend_Log_Filter_Priority($priority, $comparison));
static::get_logger()->addWriter($writer);
}
/**
* Dispatch a message by priority level.
*
* The message parameter can be either a string (a simple error
* message), or an array of variables. The latter is useful for passing
* along a list of debug information for the writer to handle, such as
* error code, error line, error context (backtrace).
*
* @param mixed $message Exception object or array of error context variables
* @param const $priority Priority. Possible values: SS_Log::ERR, SS_Log::WARN or SS_Log::NOTICE
* @param mixed $extras Extra information to log in event
*/
public static function log($message, $priority, $extras = null) {
if($message instanceof Exception) {
$message = array(
'errno' => '',
'errstr' => $message->getMessage(),
'errfile' => $message->getFile(),
'errline' => $message->getLine(),
'errcontext' => $message->getTrace()
);
} elseif(is_string($message)) {
$trace = SS_Backtrace::filtered_backtrace();
$lastTrace = $trace[0];
$message = array(
'errno' => '',
'errstr' => $message,
'errfile' => isset($lastTrace['file']) ? $lastTrace['file'] : null,
'errline' => isset($lastTrace['line']) ? $lastTrace['line'] : null,
'errcontext' => $trace
);
}
try {
static::get_logger()->log($message, $priority, $extras);
} catch(Exception $e) {
// @todo How do we handle exceptions thrown from Zend_Log?
// For example, an exception is thrown if no writers are added
}
}
}

View File

@ -1,94 +0,0 @@
<?php
require_once 'Zend/Log/Writer/Abstract.php';
/**
* Sends an error message to an email.
*
* @see SS_Log for more information on using writers.
*
* @package framework
* @subpackage dev
*/
class SS_LogEmailWriter extends Zend_Log_Writer_Abstract {
/**
* @config
* @var $send_from Email address to send log information from
*/
private static $send_from = 'errors@silverstripe.com';
protected $emailAddress;
protected $customSmtpServer;
public function __construct($emailAddress, $customSmtpServer = false) {
$this->emailAddress = $emailAddress;
$this->customSmtpServer = $customSmtpServer;
}
public static function factory($emailAddress, $customSmtpServer = false) {
return new SS_LogEmailWriter($emailAddress, $customSmtpServer);
}
/**
* @deprecated 4.0 Use the "SS_LogEmailWriter.send_from" config setting instead
*/
public static function set_send_from($address) {
Deprecation::notice('4.0', 'Use the "SS_LogEmailWriter.send_from" config setting instead');
Config::inst()->update('SS_LogEmailWriter', 'send_from', $address);
}
/**
* @deprecated 4.0 Use the "SS_LogEmailWriter.send_from" config setting instead
*/
public static function get_send_from() {
Deprecation::notice('4.0', 'Use the "SS_LogEmailWriter.send_from" config setting instead');
return Config::inst()->get('SS_LogEmailWriter', 'send_from');
}
/**
* Send an email to the email address set in
* this writer.
*/
public function _write($event) {
// If no formatter set up, use the default
if(!$this->_formatter) {
$formatter = new SS_LogErrorEmailFormatter();
$this->setFormatter($formatter);
}
$formattedData = $this->_formatter->format($event);
$subject = $formattedData['subject'];
$data = $formattedData['data'];
$from = Config::inst()->get('SS_LogEmailWriter', 'send_from');
// override the SMTP server with a custom one if required
$originalSMTP = ini_get('SMTP');
if($this->customSmtpServer) ini_set('SMTP', $this->customSmtpServer);
// Use plain mail() implementation to avoid complexity of Mailer implementation.
// Only use built-in mailer when we're in test mode (to allow introspection)
$mailer = Email::mailer();
if($mailer instanceof TestMailer) {
$mailer->sendHTML(
$this->emailAddress,
null,
$subject,
$data,
null,
"Content-type: text/html\nFrom: " . $from
);
} else {
mail(
$this->emailAddress,
$subject,
$data,
"Content-type: text/html\nFrom: " . $from
);
}
// reset the SMTP server to the original
if($this->customSmtpServer) ini_set('SMTP', $originalSMTP);
}
}

View File

@ -1,80 +0,0 @@
<?php
require_once 'Zend/Log/Formatter/Interface.php';
/**
* Formats SS error emails with a basic layout.
*
* @package framework
* @subpackage dev
*/
class SS_LogErrorEmailFormatter implements Zend_Log_Formatter_Interface {
public function format($event) {
switch($event['priorityName']) {
case 'ERR':
$errorType = 'Error';
$colour = 'red';
break;
case 'WARN':
$errorType = 'Warning';
$colour = 'orange';
break;
case 'NOTICE':
$errorType = 'Notice';
$colour = 'grey';
break;
default:
$errorType = $event['priorityName'];
$colour = 'grey';
}
if(!is_array($event['message'])) {
return false;
}
$errno = $event['message']['errno'];
$errstr = $event['message']['errstr'];
$errfile = $event['message']['errfile'];
$errline = $event['message']['errline'];
$errcontext = $event['message']['errcontext'];
$data = '';
$data .= '<style type="text/css">html, body, table {font-family: sans-serif; font-size: 12px;}</style>';
$data .= "<div style=\"border: 5px $colour solid;\">\n";
$data .= "<p style=\"color: white; background-color: $colour; margin: 0\">[$errorType] ";
$data .= nl2br(htmlspecialchars($errstr))."<br />$errfile:$errline\n<br />\n<br />\n</p>\n";
// Render the provided backtrace
$data .= SS_Backtrace::get_rendered_backtrace($errcontext);
// Compile extra data
$blacklist = array('message', 'timestamp', 'priority', 'priorityName');
$extras = array_diff_key($event, array_combine($blacklist, $blacklist));
if($extras) {
$data .= "<h3>Details</h3>\n";
$data .= "<table class=\"extras\">\n";
foreach($extras as $k => $v) {
if(is_array($v)) $v = var_export($v, true);
$data .= sprintf(
"<tr><td><strong>%s</strong></td><td><pre>%s</pre></td></tr>\n", $k, $v);
}
$data .= "</table>\n";
}
$data .= "</div>\n";
$relfile = Director::makeRelative($errfile);
if($relfile && $relfile[0] == '/') $relfile = substr($relfile, 1);
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null;
$subject = "[$errorType] in $relfile:{$errline} (http://{$host}{$uri})";
return array(
'subject' => $subject,
'data' => $data
);
}
}

View File

@ -1,43 +0,0 @@
<?php
require_once 'Zend/Log/Formatter/Interface.php';
/**
* Formats SS error entries in an error file log.
* Format: [d-M-Y h:i:s] <type> at <file> line <line>: <errormessage> <url>
* @package framework
* @subpackage dev
*/
class SS_LogErrorFileFormatter implements Zend_Log_Formatter_Interface {
public function format($event) {
$errno = $event['message']['errno'];
$errstr = $event['message']['errstr'];
$errfile = $event['message']['errfile'];
$errline = $event['message']['errline'];
$errcontext = $event['message']['errcontext'];
switch($event['priorityName']) {
case 'ERR':
$errtype = 'Error';
break;
case 'WARN':
$errtype = 'Warning';
break;
case 'NOTICE':
$errtype = 'Notice';
break;
default:
$errtype = $event['priorityName'];
}
$urlSuffix = '';
$relfile = Director::makeRelative($errfile);
if(strlen($relfile) && $relfile[0] == '/') $relfile = substr($relfile, 1);
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] && isset($_SERVER['REQUEST_URI'])) {
$urlSuffix = " (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])";
}
return '[' . date('d-M-Y H:i:s') . "] $errtype at $relfile line $errline: $errstr$urlSuffix" . PHP_EOL;
}
}

View File

@ -1,65 +0,0 @@
<?php
require_once 'Zend/Log/Writer/Abstract.php';
/**
* Writes an error message to a file.
*
* Note: You need to make sure your web server is able
* to write to the file path that you specify to write
* logs to.
*
* @uses error_log() built-in PHP function.
* @see SS_Log for more information on using writers.
*
* @package framework
* @subpackage dev
*/
class SS_LogFileWriter extends Zend_Log_Writer_Abstract {
/**
* The path to the file that errors will be stored in.
* For example, "/var/logs/silverstripe/errors.log".
*
* @var string
*/
protected $path;
/**
* Message type to pass to error_log()
* @see http://us3.php.net/manual/en/function.error-log.php
* @var int
*/
protected $messageType;
/**
* Extra headers to pass to error_log()
* @see http://us3.php.net/manual/en/function.error-log.php
* @var string
*/
protected $extraHeaders;
public function __construct($path, $messageType = 3, $extraHeaders = '') {
$this->path = $path;
$this->messageType = $messageType;
$this->extraHeaders = $extraHeaders;
}
public static function factory($path, $messageType = 3, $extraHeaders = '') {
return new SS_LogFileWriter($path, $messageType, $extraHeaders);
}
/**
* Write the log message to the file path set
* in this writer.
*/
public function _write($event) {
if(!$this->_formatter) {
$formatter = new SS_LogErrorFileFormatter();
$this->setFormatter($formatter);
}
$message = $this->_formatter->format($event);
if(!file_exists(dirname($this->path))) mkdir(dirname($this->path), 0755, true);
error_log($message, $this->messageType, $this->path, $this->extraHeaders);
}
}

View File

@ -1,51 +0,0 @@
<?php
require_once 'Zend/Log/Writer/Abstract.php';
/**
* Sends an error message to the system log whenever an
* error occurs.
*
* @see SS_Log for more information on using writers
* @uses Zend_Log_Writer_Abstract
* @package framework
* @subpackage dev
*/
class SS_SysLogWriter extends Zend_Log_Writer_Abstract {
/**
* @param string $ident Identity of log, defaults to "Silverstripe_log" if null
* @param $options Option constants, passed to openlog()
* @param $facility Type of program logging the message, passed to openlog()
*/
public function __construct($ident = null, $options = null, $facility = LOG_LOCAL0) {
if(!$ident) $ident = 'SilverStripe_log';
if(!$options) $options = LOG_PID | LOG_PERROR;
openlog($ident, $options, $facility);
}
/**
* Close the log when this object is destroyed.
*/
public function __destruct() {
closelog();
}
/**
* @param $option See {@link __construct}
* @return SS_SysLogWriter
*/
static public function factory($config) {
return new SS_SysLogWriter(null, $config);
}
/**
* Write to the system log with the event details.
* @param array $event Error details
*/
public function _write($event) {
// If no formatter set up, use default then log the event
if(!$this->_formatter) $this->setFormatter(new SS_LogErrorFileFormatter());
syslog($event['priority'], $this->_formatter->format($event));
}
}

View File

@ -1,43 +0,0 @@
<?php
require_once 'Zend/Log.php';
/**
* Extensions to Zend_Log to make it work nicer
* with {@link SS_Log}.
*
* Please refer to {@link SS_Log} for information on
* setting up logging for your projects.
*
* @package framework
* @subpackage dev
*/
class SS_ZendLog extends Zend_Log {
/**
* Get all writers in this logger.
* @return array of Zend_Log_Writer_Abstract instances
*/
public function getWriters() {
return $this->_writers;
}
/**
* Remove a writer instance that exists in this logger.
* @param object Zend_Log_Writer_Abstract instance
*/
public function removeWriter($writer) {
foreach($this->_writers as $index => $existingWriter) {
if($existingWriter == $writer) {
unset($this->_writers[$index]);
}
}
}
/**
* Clear all writers in this logger.
*/
public function clearWriters() {
$this->_writers = array();
}
}

View File

@ -1,26 +1,79 @@
title: Error Handling title: Logging and Error Handling
summary: Trap, fire and report user exceptions, warnings and errors. summary: Trap, fire and report diagnostic logs, user exceptions, warnings and errors.
# Error Handling # Logging and Error Handling
SilverStripe has its own error trapping and handling support. On development sites, SilverStripe will deal harshly with SilverStripe uses Monolog for both error handling and logging. It comes with two default configurations: one for
any warnings or errors: a full call-stack is shown and execution stops for anything, giving you early warning of a development environments, and another for test or live environments. On development environments, SilverStripe will
potential issue to handle. deal harshly with any warnings or errors: a full call-stack is shown and execution stops for anything, giving you early
warning of a potential issue to handle.
## Triggering the error handler. ## Raising errors and logging diagnostic information.
You should use [user_error](http://www.php.net/user_error) to throw errors where appropriate. For informational and debug logs, you can use the Logger directly. The Logger is a PSR-3 compatible LoggerInterface and
can be accessed via the `Injector`:
:::php :::php
if(true == false) { Injector::inst()->get('Logger')->info('User has logged in: ID #' . Member::currentUserID());
user_error("I have an error problem", E_USER_ERROR); Injector::inst()->get('Logger')->debug('Query executed: ' . $sql);
Although you can raise more important levels of alerts in this way, we recommend using PHP's native error systems for
these instead.
For notice-level and warning-level issues, you should use [user_error](http://www.php.net/user_error) to throw errors
where appropriate. These will not halt execution but will send a message to the
:::php
function delete() {
if($this->alreadyDelete) {
user_error("Delete called on already deleted object", E_USER_NOTICE);
return;
}
...
}
function getRelatedObject() {
if(!$this->RelatedObjectID) {
user_error("Can't find a related object", E_USER_WARNING);
return null;
}
...
} }
if(0 / 0) { For errors that should halt execution, you should use Exceptions. Normally, Exceptions will halt the flow of executuion,
user_error("This time I am warning you", E_USER_WARNING); but they can be caught with a try/catch clause.
:::php
throw new \LogicException("Query failed: " . $sql);
### Accessing the logger via dependency injection.
It can quite verbose to call `Injector::inst()->get('Logger')` all the time. More importantly, it also means that you're
coupling your code to global state, which is a bad design practise. A better approach is to use depedency injection to
pass the logger in for you. The [Injector](../extending/Injector) can help with this. The most straightforward is to
specify a `dependencies` config setting, like this:
:::php
class MyController {
private static $dependencies = array(
'logger' => '%$Logger',
);
// This will be set automatically, as long as MyController is instantiated via Injector
public $logger;
function init() {
$this->logger->debug("MyController::init() called");
parent::init();
}
} }
## Error Levels In other contexts, such as testing or batch processing, logger can be set to a different value by the code calling
MyController.
### Error Levels
* **E_USER_WARNING:** Err on the side of over-reporting warnings. Throwing warnings provides a means of ensuring that * **E_USER_WARNING:** Err on the side of over-reporting warnings. Throwing warnings provides a means of ensuring that
developers know: developers know:
@ -31,24 +84,115 @@ developers know:
* **E_USER_ERROR:** Throwing one of these errors is going to take down the production site. So you should only throw * **E_USER_ERROR:** Throwing one of these errors is going to take down the production site. So you should only throw
E_USER_ERROR if it's going to be **dangerous** or **impossible** to continue with the request. E_USER_ERROR if it's going to be **dangerous** or **impossible** to continue with the request.
## Configuring error logging
## Filesystem Logs You can configure your logging using Monolog handlers. The handlers should be provided int the `Logger.handlers`
configuration setting. Below we have a couple of common examples, but Monolog comes with [many different handlers](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#handlers)
for you to try.
You can indicate a log file relative to the site root. ### Sending emails
**mysite/_config.php** To send emails, you can use Monolog's [NativeMailerHandler](https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/NativeMailerHandler.php#L74), like this:
:::php Injector:
if(!Director::isDev()) { Logger:
// log errors and warnings calls:
SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors-warnings.log'), SS_Log::WARN, '<='); MailHandler: [ pushHandler, [ %$MailHandler ] ]
MailHandler:
// or just errors class: Monolog\Handler\NativeMailerHandler
SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors.log'), SS_Log::ERR); constructor:
- me@example.com
// or notices (e.g. for Deprecation Notifications) - There was an error on your test site
SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors-notices.log'), SS_Log::NOTICE); - me@example.com
} - error
properties:
ContentType: text/html
Formatter: %$SilverStripe\Framework\Logging\DetailedErrorFormatter
The first section 4 lines passes a new handler to `Logger::pushHandler()` from the named service `MailHandler`. The
next 10 lines define what the service is.
The calls key, `MailHandler`, can be anything you like: its main purpose is to let other configuration disable it
(see below).
### Logging to a file
To log to a file, you can use Monolog's [StreamHandler](https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/StreamHandler.php#L74), like this:
Injector:
Logger:
calls:
LogFileHandler: [ pushHandler, [ %$LogFileHandler ] ]
LogFileHandler:
class: Monolog\Handler\StreamHandler
constructor:
- "../silverstripe.log"
- "info"
The log file will be relative to the framework/ path, so "../silverstripe.log" will create a file in your project root.
### Disabling the default handler
You can disable a handler by removing its pushHandlers call from the calls option of the Logger service definition.
The handler key of the default handler is `DisplayErrorHandler`, so you can disable it like this:
Injector:
Logger:
calls:
DisplayErrorHandler: %%remove%%
### Setting a different configuration for dev
In order to set different logging configuration on different environment types, we rely on the environment-specific
configuration features that the config system proviers. For example, here we have different configuration for dev and
non-dev.
---
Name: dev-errors
Only:
environment: dev
---
Injector:
Logger:
calls:
- [ pushHandler, [ %$DisplayErrorHandler ]]
DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler
constructor:
- "notice"
properties:
Formatter: %$SilverStripe\Framework\Logging\DetailedErrorFormatter
---
Name: live-errors
Except:
environment: dev
---
Injector:
Logger:
calls:
- [ pushHandler, [ %$LogFileHandler ]]
- [ pushHandler, [ %$DisplayErrorHandler ]]
LogFileHander:
class: Monolog\Handler\StreamHandler
constructor:
- "../silverstripe.log"
- "notice"
properties:
Formatter: %$Monolog\Formatter\HtmlFormatter
ContentType: text/html
DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler
constructor:
- "error"
properties:
Formatter: %$FriendlyErrorFormatter
FriendlyErrorFormatter:
class: SilverStripe\Framework\Logging\DebugViewFriendlyErrorFormatter
properties:
Title: "There has been an error"
Body: "The website server has not been able to respond to your request"
<div class="info" markdown="1"> <div class="info" markdown="1">
In addition to SilverStripe-integrated logging, it is advisable to fall back to PHPs native logging functionality. A In addition to SilverStripe-integrated logging, it is advisable to fall back to PHPs native logging functionality. A
@ -71,6 +215,48 @@ You can send both fatal errors and warnings in your code to a specified email-ad
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR); SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
} }
## API Documentation
* [api:SS_Log] ## Replacing default implementations
For most application, Monolog and its default error handler should be fine, as you can get a lot of flexibility simply
by changing that handlers that are used. However, some situations will call for replacing the default components with
others.
### Replacing the logger
Monolog comes by default with SilverStripe, but you may use another PSR-3 compliant logger, if you wish. To do this,
set the `Injector.Logger` configuration parameter, providing a new injector definition. For example:
Injector:
ErrorHandler:
class: Logging\Logger
constructor:
- 'alternative-logger'
If you do this, you will need to supply your own handlers, and the `Logger.handlers` configuration parameter will
be ignored.
### Replacing the error handler
The class `SilverStripe\Framework\Logging\MonologLoader` is responsible for loading performing Monolog-specific
configuration. It does a number of things:
* Create a `Monolog\ErrorHandler` object.
* Register the registered service `Logger` against it, to start the error handler.
* If `Logger` has a `pushHandler()` method, pass every object defined by `ErrorHandler.handlers` into it, one at a time.
This error handler is flexible enough to work with any PSR-3 logging implementation, but sometimes you will want to use
another. To replace this, you should registered a new service, `ErrorHandlerLoader`. For example:
Injector:
ErrorHandlerLoader:
class: MyApp\CustomErrorHandlerLoader
You should register something `Callable`, for example a class with an `__invoke()` method.
## Differences from SilverStripe 3
In SilverStripe 3, logging was based on the Zend Log module. Customisations were added using `SS_Log::add_writer()`.
This function no longer works, and any Zend Log writers will need to be replaced with Monolog handlers. Fortunately,
a range of handlers are available, both in the core package and in add-ons. See the
[Monolog documentation](https://github.com/Seldaek/monolog/blob/master/doc/01-usage.md) for more information.

View File

@ -2114,12 +2114,12 @@ class i18n extends Object implements TemplateGlobalProvider, Flushable {
$placeholder = '{'.$variable.'}'; $placeholder = '{'.$variable.'}';
$returnValue = str_replace($placeholder, $injection, $returnValue, $count); $returnValue = str_replace($placeholder, $injection, $returnValue, $count);
if(!$count) { if(!$count) {
SS_Log::log(sprintf( Injector::inst()->get('Logger')->log('notice', sprintf(
"Couldn't find placeholder '%s' in translation string '%s' (id: '%s')", "Couldn't find placeholder '%s' in translation string '%s' (id: '%s')",
$placeholder, $placeholder,
$returnValue, $returnValue,
$entity $entity
), SS_Log::NOTICE); ));
} }
} }
} }

View File

@ -0,0 +1,90 @@
<?php
namespace SilverStripe\Framework\Logging;
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Formatter\FormatterInterface;
/**
* Produce a friendly error message
*/
class DebugViewFriendlyErrorFormatter implements FormatterInterface
{
protected $statusCode = 500;
protected $friendlyErrorMessage = 'Error';
protected $friendlyErrorDetail;
public function getStatusCode() {
return $this->statusCode;
}
public function setStatusCode($statusCode) {
$this->statusCode = $statusCode;
}
public function getTitle($title) {
return $this->friendlyErrorMessage;
}
public function setTitle($title) {
$this->friendlyErrorMessage = $title;
}
public function getBody($title) {
return $this->friendlyErrorDetail;
}
public function setBody($body) {
$this->friendlyErrorDetail = $body;
}
public function format(array $record)
{
return $this->output();
}
public function formatBatch(array $records) {
return $this->output();
}
public function output() {
// TODO: Refactor into a content-type option
if(\Director::is_ajax()) {
return $this->friendlyErrorMessage;
} else {
// TODO: Refactor this into CMS
if(class_exists('ErrorPage')){
$errorFilePath = \ErrorPage::get_filepath_for_errorcode(
$this->statusCode,
class_exists('Translatable') ? \Translatable::get_current_locale() : null
);
if(file_exists($errorFilePath)) {
$content = file_get_contents($errorFilePath);
if(!headers_sent()) {
header('Content-Type: text/html');
}
// $BaseURL is left dynamic in error-###.html, so that multi-domain sites don't get broken
return str_replace('$BaseURL', \Director::absoluteBaseURL(), $content);
}
}
$renderer = \Debug::create_debug_view();
$output = $renderer->renderHeader();
$output .= $renderer->renderInfo("Website Error", $this->friendlyErrorMessage, $this->friendlyErrorDetail);
if(\Email::config()->admin_email) {
$mailto = \Email::obfuscate(\Email::config()->admin_email);
$output .= $renderer->renderParagraph('Contact an administrator: ' . $mailto . '');
}
$output .= $renderer->renderFooter();
return $output;
}
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace SilverStripe\Framework\Logging;
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Formatter\FormatterInterface;
/**
* Monolog-compatible error handler that will output a detailed error message to the screen.
*/
class DetailedErrorFormatter implements FormatterInterface
{
public function format(array $record)
{
if(isset($record['context']['exception'])) {
$exception = $record['context']['exception'];
$context = array(
'code' => $exception->getCode(),
'message' => 'Uncaught ' . get_class($exception) . ': ' . $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace(),
);
} else {
$context = $record['context'];
foreach(array('code','message','file','line') as $key) {
if(!isset($context[$key])) {
$context[$key] = isset($record[$key]) ? $record[$key] : null;
}
}
$trace = debug_backtrace();
// Filter out monolog plumbing from the trace
// If the context file & line isn't found in the trace, then the trace is most likely
// call to the fatal error handler and is not useful, so exclude it entirely
$i = $this->findInTrace($trace, $context['file'], $context['line']);
if($i !== null) {
$context['trace'] = array_slice($trace, $i);
} else {
$context['trace'] = null;
}
}
return $this->output(
$context['code'],
$context['message'],
$context['file'],
$context['line'],
$context['trace']
);
}
public function formatBatch(array $records) {
return implode("\n", array_map(array($this, 'format'), $records));
}
/**
* Find a call on the given file & line in the trace
* @param array $trace The result of debug_backtrace()
* @param string $file The filename to look for
* @param string $line The line number to look for
* @return int|null The matching row number, if found, or null if not found
*/
protected function findInTrace(array $trace, $file, $line) {
foreach($trace as $i => $call) {
if(isset($call['file']) && isset($call['line']) && $call['file'] == $file && $call['line'] == $line) {
return $i;
}
}
return null;
}
/**
* Render a developer facing error page, showing the stack trace and details
* of the code where the error occured.
*
* @param int $errno
* @param str $errstr
* @param str $errfile
* @param int $errline
* @param array $errcontext
*/
protected function output($errno, $errstr, $errfile, $errline, $errcontext) {
$reporter = \Debug::create_debug_view();
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
$httpRequest = null;
if(isset($_SERVER['REQUEST_URI'])) {
$httpRequest = $_SERVER['REQUEST_URI'];
} elseif(isset($_REQUEST['url'])) {
$httpRequest = $_REQUEST['url'];
}
if(isset($_SERVER['REQUEST_METHOD'])) {
$httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
}
$output = $reporter->renderHeader($httpRequest);
$output .= $reporter->renderError($httpRequest, $errno, $errstr, $errfile, $errline);
if(file_exists($errfile)) {
$lines = file($errfile);
// Make the array 1-based
array_unshift($lines, "");
unset($lines[0]);
$offset = $errline-10;
$lines = array_slice($lines, $offset, 16, true);
$output .= $reporter->renderSourceFragment($lines, $errline);
}
$output .= $reporter->renderTrace($errcontext);
$output .= $reporter->renderFooter();
return $output;
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace SilverStripe\Framework\Logging;
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
/**
* Output the error to the browser, with the given HTTP status code.
* We recommend that you use a formatter that generates HTML with this.
*/
class HTTPOutputHandler extends AbstractProcessingHandler
{
private $contentType = "text/html";
private $statusCode = 500;
/**
* Get the mime type to use when displaying this error.
*/
public function getContentType() {
return $this->contentType;
}
/**
* Set the mime type to use when displaying this error.
* Default text/html
*/
public function setContentType($contentType) {
$this->contentType = $contentType;
}
/**
* Get the HTTP status code to use when displaying this error.
*/
public function getStatusCode() {
return $this->statusCode;
}
/**
* Set the HTTP status code to use when displaying this error.
* Default 500
*/
public function setStatusCode($statusCode) {
$this->statusCode = $statusCode;
}
protected function write(array $record) {
ini_set('display_errors', 0);
// TODO: This coupling isn't ideal
// See https://github.com/silverstripe/silverstripe-framework/issues/4484
if(\Controller::has_curr()) {
$response = \Controller::curr()->getResponse();
} else {
$response = new SS_HTTPResponse();
}
// If headers have been sent then these won't be used, and may throw errors that we wont' want to see.
if(!headers_sent()) {
$response->setStatusCode($this->statusCode);
$response->addHeader("Content-Type", $this->contentType);
} else {
// To supress errors aboot errors
$response->setStatusCode(200);
}
$response->setBody($record['formatted']);
$response->output();
return false === $this->bubble;
}
}

89
logging/Log.php Normal file
View File

@ -0,0 +1,89 @@
<?php
/**
* Wrapper class for a logging handler like {@link Zend_Log}
* which takes a message (or a map of context variables) and
* sends it to one or more {@link Zend_Log_Writer_Abstract}
* subclasses for output.
*
* These priorities are currently supported:
* - SS_Log::ERR
* - SS_Log::WARN
* - SS_Log::NOTICE
*
* You can add an error writer by calling {@link SS_Log::add_writer()}
*
* Example usage of logging errors by email notification:
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::ERR);
* </code>
*
* Example usage of logging errors by file:
* <code>
* SS_Log::add_writer(new SS_LogFileWriter('/var/log/silverstripe/errors.log'), SS_Log::ERR);
* </code>
*
* Example usage of logging at warnings and errors by setting the priority to '<=':
* <code>
* SS_Log::add_writer(new SS_LogEmailWriter('my@email.com'), SS_Log::WARN, '<=');
* </code>
*
* Each writer object can be assigned a formatter. The formatter is
* responsible for formatting the message before giving it to the writer.
* {@link SS_LogErrorEmailFormatter} is such an example that formats errors
* into HTML for human readability in an email client.
*
* Formatters are added to writers like this:
* <code>
* $logEmailWriter = new SS_LogEmailWriter('my@email.com');
* $myEmailFormatter = new MyLogEmailFormatter();
* $logEmailWriter->setFormatter($myEmailFormatter);
* </code>
*
* @package framework
* @subpackage dev
*/
class SS_Log
{
const ERR = 'error';
const WARN = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
/**
* Get the logger currently in use, or create a new one if it doesn't exist.
*
* @return Psr\Log\LoggerInterface
*/
public static function get_logger() {
Deprecation::notice('4.0', 'Use Injector::inst()->get(\'Logger\') instead');
return Injector::inst()->get('Logger');
}
public static function add_writer($writer) {
throw new \InvalidArgumentException("SS_Log::add_writer() on longer works. Please use a Monolog Handler "
."instead, and add list of handlers in the Logger.handlers configuration parameter.");
}
/**
* Dispatch a message by priority level.
*
* The message parameter can be either a string (a simple error
* message), or an array of variables. The latter is useful for passing
* along a list of debug information for the writer to handle, such as
* error code, error line, error context (backtrace).
*
* @param mixed $message Exception object or array of error context variables
* @param const $priority Priority. Possible values: SS_Log::ERR, SS_Log::WARN or SS_Log::NOTICE
* @param mixed $extras Extra information to log in event
*
* @deprecated 4.0.0:5.0.0 Use Injector::inst()->get('Logger')->log($priority, $message) instead
*/
public static function log($message, $priority, $extras = null) {
Deprecation::notice('4.0', 'Use Injector::inst()->get(\'Logger\')->log($priority, $message) instead');
Injector::inst()->get('Logger')->log($priority, $message);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace SilverStripe\Framework\Logging;
use Psr\Log\LoggerInterface;
use Monolog\ErrorHandler;
/**
* Simple adaptor to start Monolog\ErrorHandler
*/
class MonologErrorHandler
{
private $logger;
/**
* Set the PSR-3 logger to send errors & exceptions to
*/
function setLogger(LoggerInterface $logger) {
$this->logger = $logger;
}
function start() {
if(!$this->logger) {
throw new \InvalidArgumentException("No Logger property passed to MonologErrorHandler."
. "Is your Injector config correct?");
}
ErrorHandler::register($this->logger);
}
}

View File

@ -1,138 +0,0 @@
<?php
/**
* @package framework
* @subpackage tests
*/
class SS_LogTest extends SapphireTest {
protected $testEmailWriter;
public function setUp() {
parent::setUp();
SS_Log::clear_writers();
}
public function tearDown() {
parent::tearDown();
SS_Log::clear_writers();
}
public function testExistingWriter() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
$testFileWriter = new SS_LogFileWriter('../test.log');
SS_Log::add_writer($testEmailWriter, SS_Log::ERR);
SS_Log::add_writer($testFileWriter, SS_Log::WARN);
$writers = SS_Log::get_writers();
$this->assertEquals(2, count($writers));
}
public function testRemoveWriter() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
$testFileWriter = new SS_LogFileWriter('../test.log');
SS_Log::add_writer($testEmailWriter, SS_Log::ERR);
SS_Log::add_writer($testFileWriter, SS_Log::WARN);
SS_Log::remove_writer($testEmailWriter);
$writers = SS_Log::get_writers();
$this->assertEquals(1, count($writers));
SS_Log::remove_writer($testFileWriter);
$writers = SS_Log::get_writers();
$this->assertEquals(0, count($writers));
}
public function testEmailWriter() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
SS_Log::add_writer($testEmailWriter, SS_Log::ERR);
SS_Log::log('Email test', SS_Log::ERR, array('my-string' => 'test', 'my-array' => array('one' => 1)));
$this->assertEmailSent('test@test.com');
$email = $this->findEmail('test@test.com');
$this->assertContains('[Error] Email test', $email['htmlContent']);
$parser = new CSSContentParser($email['htmlContent']);
$extras = $parser->getBySelector('table.extras');
$extraRows = $extras[0]->tr;
$this->assertContains('my-string', $extraRows[count($extraRows)-2]->td[0]->asXML(), 'Contains extra data key');
$this->assertContains('test', $extraRows[count($extraRows)-2]->td[1]->asXML(), 'Contains extra data value');
$this->assertContains('my-array', $extraRows[count($extraRows)-1]->td[0]->asXML(), 'Contains extra data key');
$this->assertContains(
"array('one'=&gt;1,)",
str_replace(array("\r", "\n", " "), '', $extraRows[count($extraRows)-1]->td[1]->asXML()),
'Serializes arrays correctly'
);
}
public function testEmailWriterDebugPriority() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
SS_Log::add_writer($testEmailWriter, SS_Log::DEBUG);
SS_Log::log('Test something', SS_Log::DEBUG, array('my-string' => 'test', 'my-array' => array('one' => 1)));
$this->assertEmailSent('test@test.com');
$email = $this->findEmail('test@test.com');
$this->assertContains('[DEBUG] Test something', $email['htmlContent']);
}
public function testEmailWriterInfoPriority() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
SS_Log::add_writer($testEmailWriter, SS_Log::INFO);
SS_Log::log('Test something', SS_Log::INFO, array('my-string' => 'test', 'my-array' => array('one' => 1)));
$this->assertEmailSent('test@test.com');
$email = $this->findEmail('test@test.com');
$this->assertContains('[INFO] Test something', $email['htmlContent']);
}
protected function exceptionGeneratorThrower() {
throw new Exception("thrown from SS_LogTest::testExceptionGeneratorTop");
}
protected function exceptionGenerator() {
$this->exceptionGeneratorThrower();
}
public function testEmailException() {
$testEmailWriter = new SS_LogEmailWriter('test@test.com');
SS_Log::add_writer($testEmailWriter, SS_Log::ERR);
// Trigger exception handling mechanism
try {
$this->exceptionGenerator();
} catch(Exception $exception) {
// Mimics exceptionHandler, but without the exit(1)
SS_Log::log(
array(
'errno' => E_USER_ERROR,
'errstr' => ("Uncaught " . get_class($exception) . ": " . $exception->getMessage()),
'errfile' => $exception->getFile(),
'errline' => $exception->getLine(),
'errcontext' => $exception->getTrace()
),
SS_Log::ERR
);
}
// Ensure email is sent
$this->assertEmailSent('test@test.com');
// Begin parsing of email body
$email = $this->findEmail('test@test.com');
$parser = new CSSContentParser($email['htmlContent']);
// Check that the first three lines of the stacktrace are correct
$stacktrace = $parser->getByXpath('//body/div[1]/ul[1]');
$this->assertContains('<b>SS_LogTest-&gt;exceptionGeneratorThrower()</b>', $stacktrace[0]->li[0]->asXML());
$this->assertContains('<b>SS_LogTest-&gt;exceptionGenerator()</b>', $stacktrace[0]->li[1]->asXML());
$this->assertContains('<b>SS_LogTest-&gt;testEmailException()</b>', $stacktrace[0]->li[2]->asXML());
}
public function testSubclassedLogger() {
$this->assertTrue(SS_Log::get_logger() !== SS_LogTest_NewLogger::get_logger());
}
}
class SS_LogTest_NewLogger extends SS_Log {
protected static $logger;
}

View File

@ -1,624 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Log.php 23783 2011-03-01 21:47:35Z intiilapa $
*/
/**
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Log.php 23783 2011-03-01 21:47:35Z intiilapa $
*/
class Zend_Log
{
const EMERG = 0; // Emergency: system is unusable
const ALERT = 1; // Alert: action must be taken immediately
const CRIT = 2; // Critical: critical conditions
const ERR = 3; // Error: error conditions
const WARN = 4; // Warning: warning conditions
const NOTICE = 5; // Notice: normal but significant condition
const INFO = 6; // Informational: informational messages
const DEBUG = 7; // Debug: debug messages
/**
* @var array of priorities where the keys are the
* priority numbers and the values are the priority names
*/
protected $_priorities = array();
/**
* @var array of Zend_Log_Writer_Abstract
*/
protected $_writers = array();
/**
* @var array of Zend_Log_Filter_Interface
*/
protected $_filters = array();
/**
* @var array of extra log event
*/
protected $_extras = array();
/**
*
* @var string
*/
protected $_defaultWriterNamespace = 'Zend_Log_Writer';
/**
*
* @var string
*/
protected $_defaultFilterNamespace = 'Zend_Log_Filter';
/**
*
* @var string
*/
protected $_defaultFormatterNamespace = 'Zend_Log_Formatter';
/**
*
* @var callback
*/
protected $_origErrorHandler = null;
/**
*
* @var boolean
*/
protected $_registeredErrorHandler = false;
/**
*
* @var array|boolean
*/
protected $_errorHandlerMap = false;
/**
*
* @var string
*/
protected $_timestampFormat = 'c';
/**
* Class constructor. Create a new logger
*
* @param Zend_Log_Writer_Abstract|null $writer default writer
* @return void
*/
public function __construct(Zend_Log_Writer_Abstract $writer = null)
{
$r = new ReflectionClass($this);
$this->_priorities = array_flip($r->getConstants());
if ($writer !== null) {
$this->addWriter($writer);
}
}
/**
* Factory to construct the logger and one or more writers
* based on the configuration array
*
* @param array|Zend_Config Array or instance of Zend_Config
* @return Zend_Log
* @throws Zend_Log_Exception
*/
static public function factory($config = array())
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config) || empty($config)) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Configuration must be an array or instance of Zend_Config');
}
$log = new self;
if (array_key_exists('timestampFormat', $config)) {
if (null != $config['timestampFormat'] && '' != $config['timestampFormat']) {
$log->setTimestampFormat($config['timestampFormat']);
}
unset($config['timestampFormat']);
}
if (!is_array(current($config))) {
$log->addWriter(current($config));
} else {
foreach($config as $writer) {
$log->addWriter($writer);
}
}
return $log;
}
/**
* Construct a writer object based on a configuration array
*
* @param array $spec config array with writer spec
* @return Zend_Log_Writer_Abstract
* @throws Zend_Log_Exception
*/
protected function _constructWriterFromConfig($config)
{
$writer = $this->_constructFromConfig('writer', $config, $this->_defaultWriterNamespace);
if (!$writer instanceof Zend_Log_Writer_Abstract) {
$writerName = is_object($writer)
? get_class($writer)
: 'The specified writer';
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception("{$writerName} does not extend Zend_Log_Writer_Abstract!");
}
if (isset($config['filterName'])) {
$filter = $this->_constructFilterFromConfig($config);
$writer->addFilter($filter);
}
if (isset($config['formatterName'])) {
$formatter = $this->_constructFormatterFromConfig($config);
$writer->setFormatter($formatter);
}
return $writer;
}
/**
* Construct filter object from configuration array or Zend_Config object
*
* @param array|Zend_Config $config Zend_Config or Array
* @return Zend_Log_Filter_Interface
* @throws Zend_Log_Exception
*/
protected function _constructFilterFromConfig($config)
{
$filter = $this->_constructFromConfig('filter', $config, $this->_defaultFilterNamespace);
if (!$filter instanceof Zend_Log_Filter_Interface) {
$filterName = is_object($filter)
? get_class($filter)
: 'The specified filter';
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception("{$filterName} does not implement Zend_Log_Filter_Interface");
}
return $filter;
}
/**
* Construct formatter object from configuration array or Zend_Config object
*
* @param array|Zend_Config $config Zend_Config or Array
* @return Zend_Log_Formatter_Interface
* @throws Zend_Log_Exception
*/
protected function _constructFormatterFromConfig($config)
{
$formatter = $this->_constructFromConfig('formatter', $config, $this->_defaultFormatterNamespace);
if (!$formatter instanceof Zend_Log_Formatter_Interface) {
$formatterName = is_object($formatter)
? get_class($formatter)
: 'The specified formatter';
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception($formatterName . ' does not implement Zend_Log_Formatter_Interface');
}
return $formatter;
}
/**
* Construct a filter or writer from config
*
* @param string $type 'writer' of 'filter'
* @param mixed $config Zend_Config or Array
* @param string $namespace
* @return object
* @throws Zend_Log_Exception
*/
protected function _constructFromConfig($type, $config, $namespace)
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config) || empty($config)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception(
'Configuration must be an array or instance of Zend_Config'
);
}
$params = isset($config[ $type .'Params' ]) ? $config[ $type .'Params' ] : array();
$className = $this->getClassName($config, $type, $namespace);
if (!class_exists($className)) {
require_once 'Zend/Loader.php';
Zend_Loader::loadClass($className);
}
$reflection = new ReflectionClass($className);
if (!$reflection->implementsInterface('Zend_Log_FactoryInterface')) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception(
$className . ' does not implement Zend_Log_FactoryInterface and can not be constructed from config.'
);
}
return call_user_func(array($className, 'factory'), $params);
}
/**
* Get the writer or filter full classname
*
* @param array $config
* @param string $type filter|writer
* @param string $defaultNamespace
* @return string full classname
* @throws Zend_Log_Exception
*/
protected function getClassName($config, $type, $defaultNamespace)
{
if (!isset($config[ $type . 'Name' ])) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception("Specify {$type}Name in the configuration array");
}
$className = $config[ $type . 'Name' ];
$namespace = $defaultNamespace;
if (isset($config[ $type . 'Namespace' ])) {
$namespace = $config[ $type . 'Namespace' ];
}
$fullClassName = $namespace . '_' . $className;
return $fullClassName;
}
/**
* Packs message and priority into Event array
*
* @param string $message Message to log
* @param integer $priority Priority of message
* @return array Event array
*/
protected function _packEvent($message, $priority)
{
return array_merge(array(
'timestamp' => date($this->_timestampFormat),
'message' => $message,
'priority' => $priority,
'priorityName' => $this->_priorities[$priority]
),
$this->_extras
);
}
/**
* Class destructor. Shutdown log writers
*
* @return void
*/
public function __destruct()
{
foreach($this->_writers as $writer) {
$writer->shutdown();
}
}
/**
* Undefined method handler allows a shortcut:
* $log->priorityName('message')
* instead of
* $log->log('message', Zend_Log::PRIORITY_NAME)
*
* @param string $method priority name
* @param string $params message to log
* @return void
* @throws Zend_Log_Exception
*/
public function __call($method, $params)
{
$priority = strtoupper($method);
if (($priority = array_search($priority, $this->_priorities)) !== false) {
switch (count($params)) {
case 0:
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Missing log message');
case 1:
$message = array_shift($params);
$extras = null;
break;
default:
$message = array_shift($params);
$extras = array_shift($params);
break;
}
$this->log($message, $priority, $extras);
} else {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Bad log priority');
}
}
/**
* Log a message at a priority
*
* @param string $message Message to log
* @param integer $priority Priority of message
* @param mixed $extras Extra information to log in event
* @return void
* @throws Zend_Log_Exception
*/
public function log($message, $priority, $extras = null)
{
// sanity checks
if (empty($this->_writers)) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('No writers were added');
}
if (! isset($this->_priorities[$priority])) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Bad log priority');
}
// pack into event required by filters and writers
$event = $this->_packEvent($message, $priority);
// Check to see if any extra information was passed
if (!empty($extras)) {
$info = array();
if (is_array($extras)) {
foreach ($extras as $key => $value) {
if (is_string($key)) {
$event[$key] = $value;
} else {
$info[] = $value;
}
}
} else {
$info = $extras;
}
if (!empty($info)) {
$event['info'] = $info;
}
}
// abort if rejected by the global filters
foreach ($this->_filters as $filter) {
if (! $filter->accept($event)) {
return;
}
}
// send to each writer
foreach ($this->_writers as $writer) {
$writer->write($event);
}
}
/**
* Add a custom priority
*
* @param string $name Name of priority
* @param integer $priority Numeric priority
* @throws Zend_Log_Exception
*/
public function addPriority($name, $priority)
{
// Priority names must be uppercase for predictability.
$name = strtoupper($name);
if (isset($this->_priorities[$priority])
|| false !== array_search($name, $this->_priorities)) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Existing priorities cannot be overwritten');
}
$this->_priorities[$priority] = $name;
return $this;
}
/**
* Add a filter that will be applied before all log writers.
* Before a message will be received by any of the writers, it
* must be accepted by all filters added with this method.
*
* @param int|Zend_Config|array|Zend_Log_Filter_Interface $filter
* @return Zend_Log
* @throws Zend_Log_Exception
*/
public function addFilter($filter)
{
if (is_int($filter)) {
/** @see Zend_Log_Filter_Priority */
require_once 'Zend/Log/Filter/Priority.php';
$filter = new Zend_Log_Filter_Priority($filter);
} elseif ($filter instanceof Zend_Config || is_array($filter)) {
$filter = $this->_constructFilterFromConfig($filter);
} elseif(! $filter instanceof Zend_Log_Filter_Interface) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Invalid filter provided');
}
$this->_filters[] = $filter;
return $this;
}
/**
* Add a writer. A writer is responsible for taking a log
* message and writing it out to storage.
*
* @param mixed $writer Zend_Log_Writer_Abstract or Config array
* @return Zend_Log
*/
public function addWriter($writer)
{
if (is_array($writer) || $writer instanceof Zend_Config) {
$writer = $this->_constructWriterFromConfig($writer);
}
if (!$writer instanceof Zend_Log_Writer_Abstract) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception(
'Writer must be an instance of Zend_Log_Writer_Abstract'
. ' or you should pass a configuration array'
);
}
$this->_writers[] = $writer;
return $this;
}
/**
* Set an extra item to pass to the log writers.
*
* @param string $name Name of the field
* @param string $value Value of the field
* @return Zend_Log
*/
public function setEventItem($name, $value)
{
$this->_extras = array_merge($this->_extras, array($name => $value));
return $this;
}
/**
* Register Logging system as an error handler to log php errors
* Note: it still calls the original error handler if set_error_handler is able to return it.
*
* Errors will be mapped as:
* E_NOTICE, E_USER_NOTICE => NOTICE
* E_WARNING, E_CORE_WARNING, E_USER_WARNING => WARN
* E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR => ERR
* E_DEPRECATED, E_STRICT, E_USER_DEPRECATED => DEBUG
* (unknown/other) => INFO
*
* @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler
*
* @return Zend_Log
*/
public function registerErrorHandler()
{
// Only register once. Avoids loop issues if it gets registered twice.
if ($this->_registeredErrorHandler) {
return $this;
}
$this->_origErrorHandler = set_error_handler(array($this, 'errorHandler'));
// Contruct a default map of phpErrors to Zend_Log priorities.
// Some of the errors are uncatchable, but are included for completeness
$this->_errorHandlerMap = array(
E_NOTICE => Zend_Log::NOTICE,
E_USER_NOTICE => Zend_Log::NOTICE,
E_WARNING => Zend_Log::WARN,
E_CORE_WARNING => Zend_Log::WARN,
E_USER_WARNING => Zend_Log::WARN,
E_ERROR => Zend_Log::ERR,
E_USER_ERROR => Zend_Log::ERR,
E_CORE_ERROR => Zend_Log::ERR,
E_RECOVERABLE_ERROR => Zend_Log::ERR,
E_STRICT => Zend_Log::DEBUG,
);
// PHP 5.3.0+
if (defined('E_DEPRECATED')) {
$this->_errorHandlerMap['E_DEPRECATED'] = Zend_Log::DEBUG;
}
if (defined('E_USER_DEPRECATED')) {
$this->_errorHandlerMap['E_USER_DEPRECATED'] = Zend_Log::DEBUG;
}
$this->_registeredErrorHandler = true;
return $this;
}
/**
* Error Handler will convert error into log message, and then call the original error handler
*
* @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
* @return boolean
*/
public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
{
$errorLevel = error_reporting();
if ($errorLevel && $errno) {
if (isset($this->_errorHandlerMap[$errno])) {
$priority = $this->_errorHandlerMap[$errno];
} else {
$priority = Zend_Log::INFO;
}
$this->log($errstr, $priority, array('errno'=>$errno, 'file'=>$errfile, 'line'=>$errline, 'context'=>$errcontext));
}
if ($this->_origErrorHandler !== null) {
return call_user_func($this->_origErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext);
}
return false;
}
/**
* Set timestamp format for log entries.
*
* @param string $format
* @return Zend_Log
*/
public function setTimestampFormat($format)
{
$this->_timestampFormat = $format;
return $this;
}
/**
* Get timestamp format used for log entries.
*
* @return string
*/
public function getTimestampFormat()
{
return $this->_timestampFormat;
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Exception */
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Exception extends Zend_Exception
{}

View File

@ -1,38 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: FactoryInterface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @category Zend
* @package Zend_Log
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: FactoryInterface.php 23775 2011-03-01 17:25:24Z ralph $
*/
interface Zend_Log_FactoryInterface
{
/**
* Construct a Zend_Log driver
*
* @param array|Zend_Config $config
* @return Zend_Log_FactoryInterface
*/
static public function factory($config);
}

View File

@ -1,60 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Log_Filter_Interface */
require_once 'Zend/Log/Filter/Interface.php';
/** @see Zend_Log_FactoryInterface */
require_once 'Zend/Log/FactoryInterface.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
abstract class Zend_Log_Filter_Abstract
implements Zend_Log_Filter_Interface, Zend_Log_FactoryInterface
{
/**
* Validate and optionally convert the config to array
*
* @param array|Zend_Config $config Zend_Config or Array
* @return array
* @throws Zend_Log_Exception
*/
static protected function _parseConfig($config)
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Configuration must be an array or instance of Zend_Config');
}
return $config;
}
}

View File

@ -1,40 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
interface Zend_Log_Filter_Interface
{
/**
* Returns TRUE to accept the message, FALSE to block it.
*
* @param array $event event data
* @return boolean accepted?
*/
public function accept($event);
}

View File

@ -1,85 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Filter_Abstract */
require_once 'Zend/Log/Filter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Filter_Message extends Zend_Log_Filter_Abstract
{
/**
* @var string
*/
protected $_regexp;
/**
* Filter out any log messages not matching $regexp.
*
* @param string $regexp Regular expression to test the log message
* @return void
* @throws Zend_Log_Exception
*/
public function __construct($regexp)
{
if (@preg_match($regexp, '') === false) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception("Invalid regular expression '$regexp'");
}
$this->_regexp = $regexp;
}
/**
* Create a new instance of Zend_Log_Filter_Message
*
* @param array|Zend_Config $config
* @return Zend_Log_Filter_Message
*/
static public function factory($config)
{
$config = self::_parseConfig($config);
$config = array_merge(array(
'regexp' => null
), $config);
return new self(
$config['regexp']
);
}
/**
* Returns TRUE to accept the message, FALSE to block it.
*
* @param array $event event data
* @return boolean accepted?
*/
public function accept($event)
{
return preg_match($this->_regexp, $event['message']) > 0;
}
}

View File

@ -1,101 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Priority.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Filter_Abstract */
require_once 'Zend/Log/Filter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Priority.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Filter_Priority extends Zend_Log_Filter_Abstract
{
/**
* @var integer
*/
protected $_priority;
/**
* @var string
*/
protected $_operator;
/**
* Filter logging by $priority. By default, it will accept any log
* event whose priority value is less than or equal to $priority.
*
* @param integer $priority Priority
* @param string $operator Comparison operator
* @return void
* @throws Zend_Log_Exception
*/
public function __construct($priority, $operator = null)
{
if (! is_int($priority)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Priority must be an integer');
}
$this->_priority = $priority;
$this->_operator = $operator === null ? '<=' : $operator;
}
/**
* Create a new instance of Zend_Log_Filter_Priority
*
* @param array|Zend_Config $config
* @return Zend_Log_Filter_Priority
*/
static public function factory($config)
{
$config = self::_parseConfig($config);
$config = array_merge(array(
'priority' => null,
'operator' => null,
), $config);
// Add support for constants
if (!is_numeric($config['priority']) && isset($config['priority']) && defined($config['priority'])) {
$config['priority'] = constant($config['priority']);
}
return new self(
(int) $config['priority'],
$config['operator']
);
}
/**
* Returns TRUE to accept the message, FALSE to block it.
*
* @param array $event event data
* @return boolean accepted?
*/
public function accept($event)
{
return version_compare($event['priority'], $this->_priority, $this->_operator);
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Suppress.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Filter_Interface */
require_once 'Zend/Log/Filter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Filter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Suppress.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Filter_Suppress extends Zend_Log_Filter_Abstract
{
/**
* @var boolean
*/
protected $_accept = true;
/**
* This is a simple boolean filter.
*
* Call suppress(true) to suppress all log events.
* Call suppress(false) to accept all log events.
*
* @param boolean $suppress Should all log events be suppressed?
* @return void
*/
public function suppress($suppress)
{
$this->_accept = (! $suppress);
}
/**
* Returns TRUE to accept the message, FALSE to block it.
*
* @param array $event event data
* @return boolean accepted?
*/
public function accept($event)
{
return $this->_accept;
}
/**
* Create a new instance of Zend_Log_Filter_Suppress
*
* @param array|Zend_Config $config
* @return Zend_Log_Filter_Suppress
* @throws Zend_Log_Exception
*/
static public function factory($config)
{
return new self();
}
}

View File

@ -1,40 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Log_Formatter_Interface */
require_once 'Zend/Log/Formatter/Interface.php';
/** @see Zend_Log_FactoryInterface */
require_once 'Zend/Log/FactoryInterface.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
abstract class Zend_Log_Formatter_Abstract
implements Zend_Log_Formatter_Interface, Zend_Log_FactoryInterface
{
}

View File

@ -1,61 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Firebug.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Formatter_Abstract */
require_once 'Zend/Log/Formatter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Log_Formatter_Firebug extends Zend_Log_Formatter_Abstract
{
/**
* Factory for Zend_Log_Formatter_Firebug classe
*
* @param array|Zend_Config $options useless
* @return Zend_Log_Formatter_Firebug
*/
public static function factory($options)
{
return new self;
}
/**
* This method formats the event for the firebug writer.
*
* The default is to just send the message parameter, but through
* extension of this class and calling the
* {@see Zend_Log_Writer_Firebug::setFormatter()} method you can
* pass as much of the event data as you are interested in.
*
* @param array $event event data
* @return mixed event message
*/
public function format($event)
{
return $event['message'];
}
}

View File

@ -1,41 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
interface Zend_Log_Formatter_Interface
{
/**
* Formats data into a single line to be written by the writer.
*
* @param array $event event data
* @return string formatted line to write to the log
*/
public function format($event);
}

View File

@ -1,108 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Simple.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Formatter_Abstract */
require_once 'Zend/Log/Formatter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Simple.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Formatter_Simple extends Zend_Log_Formatter_Abstract
{
/**
* @var string
*/
protected $_format;
const DEFAULT_FORMAT = '%timestamp% %priorityName% (%priority%): %message%';
/**
* Class constructor
*
* @param null|string $format Format specifier for log messages
* @return void
* @throws Zend_Log_Exception
*/
public function __construct($format = null)
{
if ($format === null) {
$format = self::DEFAULT_FORMAT . PHP_EOL;
}
if (!is_string($format)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Format must be a string');
}
$this->_format = $format;
}
/**
* Factory for Zend_Log_Formatter_Simple classe
*
* @param array|Zend_Config $options
* @return Zend_Log_Formatter_Simple
*/
public static function factory($options)
{
$format = null;
if (null !== $options) {
if ($options instanceof Zend_Config) {
$options = $options->toArray();
}
if (array_key_exists('format', $options)) {
$format = $options['format'];
}
}
return new self($format);
}
/**
* Formats data into a single line to be written by the writer.
*
* @param array $event event data
* @return string formatted line to write to the log
*/
public function format($event)
{
$output = $this->_format;
foreach ($event as $name => $value) {
if ((is_object($value) && !method_exists($value,'__toString'))
|| is_array($value)
) {
$value = gettype($value);
}
$output = str_replace("%$name%", $value, $output);
}
return $output;
}
}

View File

@ -1,165 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Xml.php 24237 2011-07-13 18:22:20Z matthew $
*/
/** Zend_Log_Formatter_Abstract */
require_once 'Zend/Log/Formatter/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Formatter
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Xml.php 24237 2011-07-13 18:22:20Z matthew $
*/
class Zend_Log_Formatter_Xml extends Zend_Log_Formatter_Abstract
{
/**
* @var string Name of root element
*/
protected $_rootElement;
/**
* @var array Relates XML elements to log data field keys.
*/
protected $_elementMap;
/**
* @var string Encoding to use in XML
*/
protected $_encoding;
/**
* Class constructor
* (the default encoding is UTF-8)
*
* @param array|Zend_Config $options
* @return void
*/
public function __construct($options = array())
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
$args = func_get_args();
$options = array(
'rootElement' => array_shift($args)
);
if (count($args)) {
$options['elementMap'] = array_shift($args);
}
if (count($args)) {
$options['encoding'] = array_shift($args);
}
}
if (!array_key_exists('rootElement', $options)) {
$options['rootElement'] = 'logEntry';
}
if (!array_key_exists('encoding', $options)) {
$options['encoding'] = 'UTF-8';
}
$this->_rootElement = $options['rootElement'];
$this->setEncoding($options['encoding']);
if (array_key_exists('elementMap', $options)) {
$this->_elementMap = $options['elementMap'];
}
}
/**
* Factory for Zend_Log_Formatter_Xml classe
*
* @param array|Zend_Config $options
* @return Zend_Log_Formatter_Xml
*/
public static function factory($options)
{
return new self($options);
}
/**
* Get encoding
*
* @return string
*/
public function getEncoding()
{
return $this->_encoding;
}
/**
* Set encoding
*
* @param string $value
* @return Zend_Log_Formatter_Xml
*/
public function setEncoding($value)
{
$this->_encoding = (string) $value;
return $this;
}
/**
* Formats data into a single line to be written by the writer.
*
* @param array $event event data
* @return string formatted line to write to the log
*/
public function format($event)
{
if ($this->_elementMap === null) {
$dataToInsert = $event;
} else {
$dataToInsert = array();
foreach ($this->_elementMap as $elementName => $fieldKey) {
$dataToInsert[$elementName] = $event[$fieldKey];
}
}
$enc = $this->getEncoding();
$dom = new DOMDocument('1.0', $enc);
$elt = $dom->appendChild(new DOMElement($this->_rootElement));
foreach ($dataToInsert as $key => $value) {
if (empty($value)
|| is_scalar($value)
|| (is_object($value) && method_exists($value,'__toString'))
) {
if($key == "message") {
$value = htmlspecialchars($value, ENT_COMPAT, $enc);
}
$elt->appendChild(new DOMElement($key, (string)$value));
}
}
$xml = $dom->saveXML();
$xml = preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml);
return $xml . PHP_EOL;
}
}

View File

@ -1,138 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Filter_Priority */
require_once 'Zend/Log/Filter/Priority.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 23775 2011-03-01 17:25:24Z ralph $
*/
abstract class Zend_Log_Writer_Abstract implements Zend_Log_FactoryInterface
{
/**
* @var array of Zend_Log_Filter_Interface
*/
protected $_filters = array();
/**
* Formats the log message before writing.
*
* @var Zend_Log_Formatter_Interface
*/
protected $_formatter;
/**
* Add a filter specific to this writer.
*
* @param Zend_Log_Filter_Interface $filter
* @return Zend_Log_Writer_Abstract
*/
public function addFilter($filter)
{
if (is_int($filter)) {
$filter = new Zend_Log_Filter_Priority($filter);
}
if (!$filter instanceof Zend_Log_Filter_Interface) {
/** @see Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Invalid filter provided');
}
$this->_filters[] = $filter;
return $this;
}
/**
* Log a message to this writer.
*
* @param array $event log data event
* @return void
*/
public function write($event)
{
foreach ($this->_filters as $filter) {
if (! $filter->accept($event)) {
return;
}
}
// exception occurs on error
$this->_write($event);
}
/**
* Set a new formatter for this writer
*
* @param Zend_Log_Formatter_Interface $formatter
* @return Zend_Log_Writer_Abstract
*/
public function setFormatter(Zend_Log_Formatter_Interface $formatter)
{
$this->_formatter = $formatter;
return $this;
}
/**
* Perform shutdown activites such as closing open resources
*
* @return void
*/
public function shutdown()
{}
/**
* Write a message to the log.
*
* @param array $event log data event
* @return void
*/
abstract protected function _write($event);
/**
* Validate and optionally convert the config to array
*
* @param array|Zend_Config $config Zend_Config or Array
* @return array
* @throws Zend_Log_Exception
*/
static protected function _parseConfig($config)
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception(
'Configuration must be an array or instance of Zend_Config'
);
}
return $config;
}
}

View File

@ -1,145 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Db.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Db.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_Db extends Zend_Log_Writer_Abstract
{
/**
* Database adapter instance
*
* @var Zend_Db_Adapter
*/
private $_db;
/**
* Name of the log table in the database
*
* @var string
*/
private $_table;
/**
* Relates database columns names to log data field keys.
*
* @var null|array
*/
private $_columnMap;
/**
* Class constructor
*
* @param Zend_Db_Adapter $db Database adapter instance
* @param string $table Log table in database
* @param array $columnMap
* @return void
*/
public function __construct($db, $table, $columnMap = null)
{
$this->_db = $db;
$this->_table = $table;
$this->_columnMap = $columnMap;
}
/**
* Create a new instance of Zend_Log_Writer_Db
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Db
*/
static public function factory($config)
{
$config = self::_parseConfig($config);
$config = array_merge(array(
'db' => null,
'table' => null,
'columnMap' => null,
), $config);
if (isset($config['columnmap'])) {
$config['columnMap'] = $config['columnmap'];
}
return new self(
$config['db'],
$config['table'],
$config['columnMap']
);
}
/**
* Formatting is not possible on this writer
*
* @return void
* @throws Zend_Log_Exception
*/
public function setFormatter(Zend_Log_Formatter_Interface $formatter)
{
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception(get_class($this) . ' does not support formatting');
}
/**
* Remove reference to database adapter
*
* @return void
*/
public function shutdown()
{
$this->_db = null;
}
/**
* Write a message to the log.
*
* @param array $event event data
* @return void
* @throws Zend_Log_Exception
*/
protected function _write($event)
{
if ($this->_db === null) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Database adapter is null');
}
if ($this->_columnMap === null) {
$dataToInsert = $event;
} else {
$dataToInsert = array();
foreach ($this->_columnMap as $columnName => $fieldKey) {
$dataToInsert[$columnName] = $event[$fieldKey];
}
}
$this->_db->insert($this->_table, $dataToInsert);
}
}

View File

@ -1,204 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Firebug.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log */
require_once 'Zend/Log.php';
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/** Zend_Log_Formatter_Firebug */
require_once 'Zend/Log/Formatter/Firebug.php';
/** Zend_Wildfire_Plugin_FirePhp */
require_once 'Zend/Wildfire/Plugin/FirePhp.php';
/**
* Writes log messages to the Firebug Console via FirePHP.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Log_Writer_Firebug extends Zend_Log_Writer_Abstract
{
/**
* Maps logging priorities to logging display styles
*
* @var array
*/
protected $_priorityStyles = array(Zend_Log::EMERG => Zend_Wildfire_Plugin_FirePhp::ERROR,
Zend_Log::ALERT => Zend_Wildfire_Plugin_FirePhp::ERROR,
Zend_Log::CRIT => Zend_Wildfire_Plugin_FirePhp::ERROR,
Zend_Log::ERR => Zend_Wildfire_Plugin_FirePhp::ERROR,
Zend_Log::WARN => Zend_Wildfire_Plugin_FirePhp::WARN,
Zend_Log::NOTICE => Zend_Wildfire_Plugin_FirePhp::INFO,
Zend_Log::INFO => Zend_Wildfire_Plugin_FirePhp::INFO,
Zend_Log::DEBUG => Zend_Wildfire_Plugin_FirePhp::LOG);
/**
* The default logging style for un-mapped priorities
*
* @var string
*/
protected $_defaultPriorityStyle = Zend_Wildfire_Plugin_FirePhp::LOG;
/**
* Flag indicating whether the log writer is enabled
*
* @var boolean
*/
protected $_enabled = true;
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
if (php_sapi_name() == 'cli') {
$this->setEnabled(false);
}
$this->_formatter = new Zend_Log_Formatter_Firebug();
}
/**
* Create a new instance of Zend_Log_Writer_Firebug
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Firebug
*/
static public function factory($config)
{
return new self();
}
/**
* Enable or disable the log writer.
*
* @param boolean $enabled Set to TRUE to enable the log writer
* @return boolean The previous value.
*/
public function setEnabled($enabled)
{
$previous = $this->_enabled;
$this->_enabled = $enabled;
return $previous;
}
/**
* Determine if the log writer is enabled.
*
* @return boolean Returns TRUE if the log writer is enabled.
*/
public function getEnabled()
{
return $this->_enabled;
}
/**
* Set the default display style for user-defined priorities
*
* @param string $style The default log display style
* @return string Returns previous default log display style
*/
public function setDefaultPriorityStyle($style)
{
$previous = $this->_defaultPriorityStyle;
$this->_defaultPriorityStyle = $style;
return $previous;
}
/**
* Get the default display style for user-defined priorities
*
* @return string Returns the default log display style
*/
public function getDefaultPriorityStyle()
{
return $this->_defaultPriorityStyle;
}
/**
* Set a display style for a logging priority
*
* @param int $priority The logging priority
* @param string $style The logging display style
* @return string|boolean The previous logging display style if defined or TRUE otherwise
*/
public function setPriorityStyle($priority, $style)
{
$previous = true;
if (array_key_exists($priority,$this->_priorityStyles)) {
$previous = $this->_priorityStyles[$priority];
}
$this->_priorityStyles[$priority] = $style;
return $previous;
}
/**
* Get a display style for a logging priority
*
* @param int $priority The logging priority
* @return string|boolean The logging display style if defined or FALSE otherwise
*/
public function getPriorityStyle($priority)
{
if (array_key_exists($priority,$this->_priorityStyles)) {
return $this->_priorityStyles[$priority];
}
return false;
}
/**
* Log a message to the Firebug Console.
*
* @param array $event The event data
* @return void
*/
protected function _write($event)
{
if (!$this->getEnabled()) {
return;
}
if (array_key_exists($event['priority'],$this->_priorityStyles)) {
$type = $this->_priorityStyles[$event['priority']];
} else {
$type = $this->_defaultPriorityStyle;
}
$message = $this->_formatter->format($event);
$label = isset($event['firebugLabel'])?$event['firebugLabel']:null;
Zend_Wildfire_Plugin_FirePhp::getInstance()->send($message,
$label,
$type,
array('traceOffset'=>4,
'fixZendLogOffsetIfApplicable'=>true));
}
}

View File

@ -1,430 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mail.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/** Zend_Log_Exception */
require_once 'Zend/Log/Exception.php';
/** Zend_Log_Formatter_Simple*/
require_once 'Zend/Log/Formatter/Simple.php';
/**
* Class used for writing log messages to email via Zend_Mail.
*
* Allows for emailing log messages at and above a certain level via a
* Zend_Mail object. Note that this class only sends the email upon
* completion, so any log entries accumulated are sent in a single email.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mail.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_Mail extends Zend_Log_Writer_Abstract
{
/**
* Array of formatted events to include in message body.
*
* @var array
*/
protected $_eventsToMail = array();
/**
* Array of formatted lines for use in an HTML email body; these events
* are formatted with an optional formatter if the caller is using
* Zend_Layout.
*
* @var array
*/
protected $_layoutEventsToMail = array();
/**
* Zend_Mail instance to use
*
* @var Zend_Mail
*/
protected $_mail;
/**
* Zend_Layout instance to use; optional.
*
* @var Zend_Layout
*/
protected $_layout;
/**
* Optional formatter for use when rendering with Zend_Layout.
*
* @var Zend_Log_Formatter_Interface
*/
protected $_layoutFormatter;
/**
* Array keeping track of the number of entries per priority level.
*
* @var array
*/
protected $_numEntriesPerPriority = array();
/**
* Subject prepend text.
*
* Can only be used of the Zend_Mail object has not already had its
* subject line set. Using this will cause the subject to have the entry
* counts per-priority level appended to it.
*
* @var string|null
*/
protected $_subjectPrependText;
/**
* MethodMap for Zend_Mail's headers
*
* @var array
*/
protected static $_methodMapHeaders = array(
'from' => 'setFrom',
'to' => 'addTo',
'cc' => 'addCc',
'bcc' => 'addBcc',
);
/**
* Class constructor.
*
* Constructs the mail writer; requires a Zend_Mail instance, and takes an
* optional Zend_Layout instance. If Zend_Layout is being used,
* $this->_layout->events will be set for use in the layout template.
*
* @param Zend_Mail $mail Mail instance
* @param Zend_Layout $layout Layout instance; optional
* @return void
*/
public function __construct(Zend_Mail $mail, Zend_Layout $layout = null)
{
$this->_mail = $mail;
if (null !== $layout) {
$this->setLayout($layout);
}
$this->_formatter = new Zend_Log_Formatter_Simple();
}
/**
* Create a new instance of Zend_Log_Writer_Mail
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Mail
*/
static public function factory($config)
{
$config = self::_parseConfig($config);
$mail = self::_constructMailFromConfig($config);
$writer = new self($mail);
if (isset($config['layout']) || isset($config['layoutOptions'])) {
$writer->setLayout($config);
}
if (isset($config['layoutFormatter'])) {
$layoutFormatter = new $config['layoutFormatter'];
$writer->setLayoutFormatter($layoutFormatter);
}
if (isset($config['subjectPrependText'])) {
$writer->setSubjectPrependText($config['subjectPrependText']);
}
return $writer;
}
/**
* Set the layout
*
* @param Zend_Layout|array $layout
* @return Zend_Log_Writer_Mail
* @throws Zend_Log_Exception
*/
public function setLayout($layout)
{
if (is_array($layout)) {
$layout = $this->_constructLayoutFromConfig($layout);
}
if (!$layout instanceof Zend_Layout) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Mail must be an instance of Zend_Layout or an array');
}
$this->_layout = $layout;
return $this;
}
/**
* Construct a Zend_Mail instance based on a configuration array
*
* @param array $config
* @return Zend_Mail
* @throws Zend_Log_Exception
*/
protected static function _constructMailFromConfig(array $config)
{
$mailClass = 'Zend_Mail';
if (isset($config['mail'])) {
$mailClass = $config['mail'];
}
if (!array_key_exists('charset', $config)) {
$config['charset'] = null;
}
$mail = new $mailClass($config['charset']);
if (!$mail instanceof Zend_Mail) {
throw new Zend_Log_Exception($mail . 'must extend Zend_Mail');
}
if (isset($config['subject'])) {
$mail->setSubject($config['subject']);
}
$headerAddresses = array_intersect_key($config, self::$_methodMapHeaders);
if (count($headerAddresses)) {
foreach ($headerAddresses as $header => $address) {
$method = self::$_methodMapHeaders[$header];
if (is_array($address) && isset($address['name'])
&& !is_numeric($address['name'])
) {
$params = array(
$address['email'],
$address['name']
);
} else if (is_array($address) && isset($address['email'])) {
$params = array($address['email']);
} else {
$params = array($address);
}
call_user_func_array(array($mail, $method), $params);
}
}
return $mail;
}
/**
* Construct a Zend_Layout instance based on a configuration array
*
* @param array $config
* @return Zend_Layout
* @throws Zend_Log_Exception
*/
protected function _constructLayoutFromConfig(array $config)
{
$config = array_merge(array(
'layout' => 'Zend_Layout',
'layoutOptions' => null
), $config);
$layoutClass = $config['layout'];
$layout = new $layoutClass($config['layoutOptions']);
if (!$layout instanceof Zend_Layout) {
throw new Zend_Log_Exception($layout . 'must extend Zend_Layout');
}
return $layout;
}
/**
* Places event line into array of lines to be used as message body.
*
* Handles the formatting of both plaintext entries, as well as those
* rendered with Zend_Layout.
*
* @param array $event Event data
* @return void
*/
protected function _write($event)
{
// Track the number of entries per priority level.
if (!isset($this->_numEntriesPerPriority[$event['priorityName']])) {
$this->_numEntriesPerPriority[$event['priorityName']] = 1;
} else {
$this->_numEntriesPerPriority[$event['priorityName']]++;
}
$formattedEvent = $this->_formatter->format($event);
// All plaintext events are to use the standard formatter.
$this->_eventsToMail[] = $formattedEvent;
// If we have a Zend_Layout instance, use a specific formatter for the
// layout if one exists. Otherwise, just use the event with its
// default format.
if ($this->_layout) {
if ($this->_layoutFormatter) {
$this->_layoutEventsToMail[] =
$this->_layoutFormatter->format($event);
} else {
$this->_layoutEventsToMail[] = $formattedEvent;
}
}
}
/**
* Gets instance of Zend_Log_Formatter_Instance used for formatting a
* message using Zend_Layout, if applicable.
*
* @return Zend_Log_Formatter_Interface|null The formatter, or null.
*/
public function getLayoutFormatter()
{
return $this->_layoutFormatter;
}
/**
* Sets a specific formatter for use with Zend_Layout events.
*
* Allows use of a second formatter on lines that will be rendered with
* Zend_Layout. In the event that Zend_Layout is not being used, this
* formatter cannot be set, so an exception will be thrown.
*
* @param Zend_Log_Formatter_Interface $formatter
* @return Zend_Log_Writer_Mail
* @throws Zend_Log_Exception
*/
public function setLayoutFormatter(Zend_Log_Formatter_Interface $formatter)
{
if (!$this->_layout) {
throw new Zend_Log_Exception(
'cannot set formatter for layout; ' .
'a Zend_Layout instance is not in use');
}
$this->_layoutFormatter = $formatter;
return $this;
}
/**
* Allows caller to have the mail subject dynamically set to contain the
* entry counts per-priority level.
*
* Sets the text for use in the subject, with entry counts per-priority
* level appended to the end. Since a Zend_Mail subject can only be set
* once, this method cannot be used if the Zend_Mail object already has a
* subject set.
*
* @param string $subject Subject prepend text.
* @return Zend_Log_Writer_Mail
* @throws Zend_Log_Exception
*/
public function setSubjectPrependText($subject)
{
if ($this->_mail->getSubject()) {
throw new Zend_Log_Exception(
'subject already set on mail; ' .
'cannot set subject prepend text');
}
$this->_subjectPrependText = (string) $subject;
return $this;
}
/**
* Sends mail to recipient(s) if log entries are present. Note that both
* plaintext and HTML portions of email are handled here.
*
* @return void
*/
public function shutdown()
{
// If there are events to mail, use them as message body. Otherwise,
// there is no mail to be sent.
if (empty($this->_eventsToMail)) {
return;
}
if ($this->_subjectPrependText !== null) {
// Tack on the summary of entries per-priority to the subject
// line and set it on the Zend_Mail object.
$numEntries = $this->_getFormattedNumEntriesPerPriority();
$this->_mail->setSubject(
"{$this->_subjectPrependText} ({$numEntries})");
}
// Always provide events to mail as plaintext.
$this->_mail->setBodyText(implode('', $this->_eventsToMail));
// If a Zend_Layout instance is being used, set its "events"
// value to the lines formatted for use with the layout.
if ($this->_layout) {
// Set the required "messages" value for the layout. Here we
// are assuming that the layout is for use with HTML.
$this->_layout->events =
implode('', $this->_layoutEventsToMail);
// If an exception occurs during rendering, convert it to a notice
// so we can avoid an exception thrown without a stack frame.
try {
$this->_mail->setBodyHtml($this->_layout->render());
} catch (Exception $e) {
trigger_error(
"exception occurred when rendering layout; " .
"unable to set html body for message; " .
"message = {$e->getMessage()}; " .
"code = {$e->getCode()}; " .
"exception class = " . get_class($e),
E_USER_NOTICE);
}
}
// Finally, send the mail. If an exception occurs, convert it into a
// warning-level message so we can avoid an exception thrown without a
// stack frame.
try {
$this->_mail->send();
} catch (Exception $e) {
trigger_error(
"unable to send log entries via email; " .
"message = {$e->getMessage()}; " .
"code = {$e->getCode()}; " .
"exception class = " . get_class($e),
E_USER_WARNING);
}
}
/**
* Gets a string of number of entries per-priority level that occurred, or
* an emptry string if none occurred.
*
* @return string
*/
protected function _getFormattedNumEntriesPerPriority()
{
$strings = array();
foreach ($this->_numEntriesPerPriority as $priority => $numEntries) {
$strings[] = "{$priority}={$numEntries}";
}
return implode(', ', $strings);
}
}

View File

@ -1,81 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mock.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mock.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_Mock extends Zend_Log_Writer_Abstract
{
/**
* array of log events
*
* @var array
*/
public $events = array();
/**
* shutdown called?
*
* @var boolean
*/
public $shutdown = false;
/**
* Write a message to the log.
*
* @param array $event event data
* @return void
*/
public function _write($event)
{
$this->events[] = $event;
}
/**
* Record shutdown
*
* @return void
*/
public function shutdown()
{
$this->shutdown = true;
}
/**
* Create a new instance of Zend_Log_Writer_Mock
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Mock
*/
static public function factory($config)
{
return new self();
}
}

View File

@ -1,56 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Null.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Null.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_Null extends Zend_Log_Writer_Abstract
{
/**
* Write a message to the log.
*
* @param array $event event data
* @return void
*/
protected function _write($event)
{
}
/**
* Create a new instance of Zend_Log_Writer_Null
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Null
*/
static public function factory($config)
{
return new self();
}
}

View File

@ -1,138 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Stream.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/** Zend_Log_Formatter_Simple */
require_once 'Zend/Log/Formatter/Simple.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Stream.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_Stream extends Zend_Log_Writer_Abstract
{
/**
* Holds the PHP stream to log to.
*
* @var null|stream
*/
protected $_stream = null;
/**
* Class Constructor
*
* @param array|string|resource $streamOrUrl Stream or URL to open as a stream
* @param string|null $mode Mode, only applicable if a URL is given
* @return void
* @throws Zend_Log_Exception
*/
public function __construct($streamOrUrl, $mode = null)
{
// Setting the default
if (null === $mode) {
$mode = 'a';
}
if (is_resource($streamOrUrl)) {
if (get_resource_type($streamOrUrl) != 'stream') {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Resource is not a stream');
}
if ($mode != 'a') {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Mode cannot be changed on existing streams');
}
$this->_stream = $streamOrUrl;
} else {
if (is_array($streamOrUrl) && isset($streamOrUrl['stream'])) {
$streamOrUrl = $streamOrUrl['stream'];
}
if (! $this->_stream = @fopen($streamOrUrl, $mode, false)) {
require_once 'Zend/Log/Exception.php';
$msg = "\"$streamOrUrl\" cannot be opened with mode \"$mode\"";
throw new Zend_Log_Exception($msg);
}
}
$this->_formatter = new Zend_Log_Formatter_Simple();
}
/**
* Create a new instance of Zend_Log_Writer_Stream
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Stream
*/
static public function factory($config)
{
$config = self::_parseConfig($config);
$config = array_merge(array(
'stream' => null,
'mode' => null,
), $config);
$streamOrUrl = isset($config['url']) ? $config['url'] : $config['stream'];
return new self(
$streamOrUrl,
$config['mode']
);
}
/**
* Close the stream resource.
*
* @return void
*/
public function shutdown()
{
if (is_resource($this->_stream)) {
fclose($this->_stream);
}
}
/**
* Write a message to the log.
*
* @param array $event event data
* @return void
* @throws Zend_Log_Exception
*/
protected function _write($event)
{
$line = $this->_formatter->format($event);
if (false === @fwrite($this->_stream, $line)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception("Unable to write to stream");
}
}
}

View File

@ -1,267 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Syslog.php 23953 2011-05-03 05:47:39Z ralph $
*/
/** Zend_Log */
require_once 'Zend/Log.php';
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/**
* Writes log messages to syslog
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Log_Writer_Syslog extends Zend_Log_Writer_Abstract
{
/**
* Maps Zend_Log priorities to PHP's syslog priorities
*
* @var array
*/
protected $_priorities = array(
Zend_Log::EMERG => LOG_EMERG,
Zend_Log::ALERT => LOG_ALERT,
Zend_Log::CRIT => LOG_CRIT,
Zend_Log::ERR => LOG_ERR,
Zend_Log::WARN => LOG_WARNING,
Zend_Log::NOTICE => LOG_NOTICE,
Zend_Log::INFO => LOG_INFO,
Zend_Log::DEBUG => LOG_DEBUG,
);
/**
* The default log priority - for unmapped custom priorities
*
* @var string
*/
protected $_defaultPriority = LOG_NOTICE;
/**
* Last application name set by a syslog-writer instance
*
* @var string
*/
protected static $_lastApplication;
/**
* Last facility name set by a syslog-writer instance
*
* @var string
*/
protected static $_lastFacility;
/**
* Application name used by this syslog-writer instance
*
* @var string
*/
protected $_application = 'Zend_Log';
/**
* Facility used by this syslog-writer instance
*
* @var int
*/
protected $_facility = LOG_USER;
/**
* Types of program available to logging of message
*
* @var array
*/
protected $_validFacilities = array();
/**
* Class constructor
*
* @param array $params Array of options; may include "application" and "facility" keys
* @return void
*/
public function __construct(array $params = array())
{
if (isset($params['application'])) {
$this->_application = $params['application'];
}
$runInitializeSyslog = true;
if (isset($params['facility'])) {
$this->setFacility($params['facility']);
$runInitializeSyslog = false;
}
if ($runInitializeSyslog) {
$this->_initializeSyslog();
}
}
/**
* Create a new instance of Zend_Log_Writer_Syslog
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_Syslog
*/
static public function factory($config)
{
return new self(self::_parseConfig($config));
}
/**
* Initialize values facilities
*
* @return void
*/
protected function _initializeValidFacilities()
{
$constants = array(
'LOG_AUTH',
'LOG_AUTHPRIV',
'LOG_CRON',
'LOG_DAEMON',
'LOG_KERN',
'LOG_LOCAL0',
'LOG_LOCAL1',
'LOG_LOCAL2',
'LOG_LOCAL3',
'LOG_LOCAL4',
'LOG_LOCAL5',
'LOG_LOCAL6',
'LOG_LOCAL7',
'LOG_LPR',
'LOG_MAIL',
'LOG_NEWS',
'LOG_SYSLOG',
'LOG_USER',
'LOG_UUCP'
);
foreach ($constants as $constant) {
if (defined($constant)) {
$this->_validFacilities[] = constant($constant);
}
}
}
/**
* Initialize syslog / set application name and facility
*
* @return void
*/
protected function _initializeSyslog()
{
self::$_lastApplication = $this->_application;
self::$_lastFacility = $this->_facility;
openlog($this->_application, LOG_PID, $this->_facility);
}
/**
* Set syslog facility
*
* @param int $facility Syslog facility
* @return Zend_Log_Writer_Syslog
* @throws Zend_Log_Exception for invalid log facility
*/
public function setFacility($facility)
{
if ($this->_facility === $facility) {
return $this;
}
if (!count($this->_validFacilities)) {
$this->_initializeValidFacilities();
}
if (!in_array($facility, $this->_validFacilities)) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Invalid log facility provided; please see http://php.net/openlog for a list of valid facility values');
}
if ('WIN' == strtoupper(substr(PHP_OS, 0, 3))
&& ($facility !== LOG_USER)
) {
require_once 'Zend/Log/Exception.php';
throw new Zend_Log_Exception('Only LOG_USER is a valid log facility on Windows');
}
$this->_facility = $facility;
$this->_initializeSyslog();
return $this;
}
/**
* Set application name
*
* @param string $application Application name
* @return Zend_Log_Writer_Syslog
*/
public function setApplicationName($application)
{
if ($this->_application === $application) {
return $this;
}
$this->_application = $application;
$this->_initializeSyslog();
return $this;
}
/**
* Close syslog.
*
* @return void
*/
public function shutdown()
{
closelog();
}
/**
* Write a message to syslog.
*
* @param array $event event data
* @return void
*/
protected function _write($event)
{
if (array_key_exists($event['priority'], $this->_priorities)) {
$priority = $this->_priorities[$event['priority']];
} else {
$priority = $this->_defaultPriority;
}
if ($this->_application !== self::$_lastApplication
|| $this->_facility !== self::$_lastFacility)
{
$this->_initializeSyslog();
}
$message = $event['message'];
if ($this->_formatter instanceof Zend_Log_Formatter_Interface) {
$message = $this->_formatter->format($event);
}
syslog($priority, $message);
}
}

View File

@ -1,131 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ZendMonitor.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Log_Writer_Abstract */
require_once 'Zend/Log/Writer/Abstract.php';
/**
* @category Zend
* @package Zend_Log
* @subpackage Writer
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ZendMonitor.php 23775 2011-03-01 17:25:24Z ralph $
*/
class Zend_Log_Writer_ZendMonitor extends Zend_Log_Writer_Abstract
{
/**
* Is Zend Monitor enabled?
*
* @var boolean
*/
protected $_isEnabled = true;
/**
* Is this for a Zend Server intance?
*
* @var boolean
*/
protected $_isZendServer = false;
/**
* @return void
*/
public function __construct()
{
if (!function_exists('monitor_custom_event')) {
$this->_isEnabled = false;
}
if (function_exists('zend_monitor_custom_event')) {
$this->_isZendServer = true;
}
}
/**
* Create a new instance of Zend_Log_Writer_ZendMonitor
*
* @param array|Zend_Config $config
* @return Zend_Log_Writer_ZendMonitor
*/
static public function factory($config)
{
return new self();
}
/**
* Is logging to this writer enabled?
*
* If the Zend Monitor extension is not enabled, this log writer will
* fail silently. You can query this method to determine if the log
* writer is enabled.
*
* @return boolean
*/
public function isEnabled()
{
return $this->_isEnabled;
}
/**
* Log a message to this writer.
*
* @param array $event log data event
* @return void
*/
public function write($event)
{
if (!$this->isEnabled()) {
return;
}
parent::write($event);
}
/**
* Write a message to the log.
*
* @param array $event log data event
* @return void
*/
protected function _write($event)
{
$priority = $event['priority'];
$message = $event['message'];
unset($event['priority'], $event['message']);
if (!empty($event)) {
if ($this->_isZendServer) {
// On Zend Server; third argument should be the event
zend_monitor_custom_event($priority, $message, $event);
} else {
// On Zend Platform; third argument is severity -- either
// 0 or 1 -- and fourth is optional (event)
// Severity is either 0 (normal) or 1 (severe); classifying
// notice, info, and debug as "normal", and all others as
// "severe"
monitor_custom_event($priority, $message, ($priority > 4) ? 0 : 1, $event);
}
} else {
monitor_custom_event($priority, $message);
}
}
}