Logging system based on Monolog.

This commit is contained in:
Julien Fontanet
2013-01-03 11:13:38 +01:00
parent 1b6ae84a8a
commit 91f38af97e
9 changed files with 440 additions and 7 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/src/log
/vendor/

View File

@@ -10,6 +10,7 @@
],
"require": {
"php": ">=5.3.0",
"monolog/monolog": "~1.2",
"vates/gallic": "~0.2.4",
"vates/xo-lib": "dev-master"
},

67
composer.lock generated
View File

@@ -1,6 +1,63 @@
{
"hash": "c5589c454e9fec62202a1574a57c9772",
"hash": "5ad48a363a48c325678f1c0fc47f628a",
"packages": [
{
"name": "monolog/monolog",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog",
"reference": "1.2.1"
},
"dist": {
"type": "zip",
"url": "https://github.com/Seldaek/monolog/zipball/1.2.1",
"reference": "1.2.1",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"mlehner/gelf-php": "1.0.*"
},
"suggest": {
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server"
},
"time": "2012-08-29 04:53:20",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Monolog": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be",
"role": "Developer"
}
],
"description": "Logging for PHP 5.3",
"homepage": "http://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging"
]
},
{
"name": "vates/gallic",
"version": "v0.2.4",
@@ -49,18 +106,18 @@
"source": {
"type": "git",
"url": "git://github.com/julien-f/xo-lib.git",
"reference": "e3ee16f1545ab9889c3e22f55625bb492fdf737e"
"reference": "2b7911c6c60f779410d6df6d99bcb0527c29a1eb"
},
"dist": {
"type": "zip",
"url": "https://github.com/julien-f/xo-lib/archive/e3ee16f1545ab9889c3e22f55625bb492fdf737e.zip",
"reference": "e3ee16f1545ab9889c3e22f55625bb492fdf737e",
"url": "https://github.com/julien-f/xo-lib/archive/2b7911c6c60f779410d6df6d99bcb0527c29a1eb.zip",
"reference": "2b7911c6c60f779410d6df6d99bcb0527c29a1eb",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2012-12-31 07:59:55",
"time": "2012-12-31 13:57:08",
"type": "library",
"installation-source": "source",
"autoload": {

View File

@@ -47,13 +47,27 @@ function _bootstrap()
$app_env = 'development';
}
// Class autoloading.
// Class autoloading is done by composer.
require($root_dir.'/../vendor/autoload.php');
// Reads configuration.
$conffile = $root_dir.'/config/'.$app_env.'.php';
$config = new Config(require($conffile));
// Injects some variables.
$config->set('root_dir', $root_dir);
$config->set('application_env', $app_env);
// Dependency injector.
$di = new DI;
$di->set('config', $config);
// Finally, creates the inventory.
// Logs all errors.
$error_logger = $di->get('error_logger');
set_error_handler(array($error_logger, 'log'));
register_shutdown_function(array($error_logger, 'handleShutdown'));
// Finally, creates the application.
$application = $di->get('application');
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* This file is a part of Xen Orchestra Web.
*
* Xen Orchestra Web is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Xen Orchestra Web is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Xen Orchestra Web. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Julien Fontanet <julien.fontanet@vates.fr>
* @license http://www.gnu.org/licenses/gpl-3.0-standalone.html GPLv3
*
* @package Xen Orchestra Web
*/
return array(
'log' => array(
//'email' => 'your.email@provider.tld',
'file' => '#{root_dir}/log',
),
);

26
src/config/production.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
/**
* This file is a part of Xen Orchestra Web.
*
* Xen Orchestra Web is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Xen Orchestra Web is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Xen Orchestra Web. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Julien Fontanet <julien.fontanet@vates.fr>
* @license http://www.gnu.org/licenses/gpl-3.0-standalone.html GPLv3
*
* @package Xen Orchestra Web
*/
return require(__DIR__.'/development.php') + array(
);

159
src/lib/Config.php Normal file
View File

@@ -0,0 +1,159 @@
<?php
/**
* This file is a part of Xen Orchestra Web.
*
* Xen Orchestra Web is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Xen Orchestra Web is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xen Orchestra Web. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Julien Fontanet <julien.fontanet@vates.fr>
* @license http://www.gnu.org/licenses/agpl-3.0-standalone.html GNU AGPLv3
*
* @package Xen Orchestra Web
*/
/**
*
*/
final class Config extends Base
{
/**
*
*/
function __construct(array $entries = null)
{
parent::__construct();
$this->_entries = isset($entries) ? $entries : array();
}
/**
* Returns an entry.
*
* @param string $path
* @param mixed $default Optional.
*
* @return array
*
* @throws Exception If there is no such entry and no default value as been
* specified.
*/
function get($path, $default = 'throws an exception')
{
$entry = $this->_entries;
$parts = explode('.', $path);
foreach ($parts as $part)
{
/*
* Nothing found.
*/
if (!isset($entry[$part])
&& !array_key_exists($part, $entry))
{
if (func_num_args() < 2)
{
throw new Exception('no such entry ('.$path.')');
}
$entry = $default;
break;
}
$entry = $entry[$part];
}
return $this->_resolve($entry);
}
/**
*
*
* @param string $path
* @param array|string $value
*/
function set($path, $value)
{
$entry = &$this->_entries;
$parts = explode('.', $path);
$i = 0;
$n = count($parts);
while (
($i < $n)
&& (
isset($entry[$part = $parts[$i]])
|| (
is_array($entry)
&& array_key_exists($part, $entry)
)
)
)
{
$entry = &$entry[$part];
++$i;
}
while ($i < $n)
{
if (!is_array($entry))
{
$entry = array();
}
$entry = &$entry[$parts[$i]];
++$i;
}
$entry = $value;
}
/**
* @var array
*/
private $_entries;
/**
*
*/
private function _replaceCallback(array $match)
{
return $this->get($match[1]);
}
/**
*
*/
private function _resolve($entry)
{
if (is_string($entry))
{
return preg_replace_callback(
'/#\{([-a-zA-Z0-9_.]+)\}/',
array($this, '_replaceCallback'),
$entry
);
}
if (is_array($entry))
{
foreach ($entry as &$item)
{
$item = $this->_resolve($item);
}
}
return $entry;
}
}

View File

@@ -71,6 +71,40 @@ final class DI extends Base
return new Application($this);
}
private function _init_errorLogger()
{
return new ErrorLogger($this->get('logger'));
}
private function _init_logger()
{
$logger = new \Monolog\Logger('main');
$config = $this->get('config');
if ($email = $config->get('log.email', false))
{
$logger->pushHandler(
new \Monolog\Handler\FingersCrossedHandler(
new \Monolog\Handler\NativeMailerHandler(
$email,
'[XO Server]',
'no-reply@vates.fr',
\Monolog\Logger::DEBUG
),
\Monolog\Logger::WARNING
)
);
}
if ($file = $config->get('log.file', false))
{
$logger->pushHandler(
new \Monolog\Handler\StreamHandler($file)
);
}
return $logger;
}
private function _init_template_manager()
{
return new Gallic_Template_Manager(

110
src/lib/ErrorLogger.php Normal file
View File

@@ -0,0 +1,110 @@
<?php
/**
* This file is a part of Xen Orchestra Web.
*
* Xen Orchestra Web is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Xen Orchestra Web is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xen Orchestra Web. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Julien Fontanet <julien.fontanet@vates.fr>
* @license http://www.gnu.org/licenses/agpl-3.0-standalone.html GNU AGPLv3
*
* @package Xen Orchestra Web
*/
use \Monolog\Logger;
/**
*
*/
final class ErrorLogger extends Base
{
/**
*
*/
function __construct(Logger $logger)
{
parent::__construct();
$this->_logger = $logger;
}
/**
* Handles fatal errors on shutdown.
*/
function handleShutdown()
{
$e = error_get_Last();
if ((($e['type'] === E_ERROR) || ($e['type'] === E_USER_ERROR))
&& ($e !== $this->_last))
{
$this->log($e['type'], $e['message'], $e['file'], $e['line']);
}
}
/**
*
*/
function log($no, $str, $file, $line)
{
static $map = array(
E_NOTICE => Logger::NOTICE,
E_USER_NOTICE => Logger::NOTICE,
E_WARNING => Logger::WARNING,
E_CORE_WARNING => Logger::WARNING,
E_USER_WARNING => Logger::WARNING,
E_ERROR => Logger::ERROR,
E_USER_ERROR => Logger::ERROR,
E_CORE_ERROR => Logger::ERROR,
E_RECOVERABLE_ERROR => Logger::ERROR,
E_STRICT => Logger::DEBUG,
);
// Used to prevents the last error from being logged twice.
$this->_last = array(
'type' => $no,
'message' => $str,
'file' => $file,
'line' => $line
);
$priority = isset($map[$no])
? $map[$no]
: Logger::WARNING
;
// Appends the location if necessary.
if (!preg_match('/(?:at|in) [^ ]+:[0-9]+$/', $str))
{
$str .= " in $file:$line";
}
$this->_logger->addRecord($priority, $str, array(
'no' => $no,
'file' => $file,
'line' => $line,
));
return false;
}
/**
*
*/
private $_last;
/**
* @var Logger
*/
private $_logger;
}