Skip to content
Snippets Groups Projects
Commit 6b8b5b25 authored by Jaime Perez's avatar Jaime Perez
Browse files

Reformat the logging classes. Extract the LoggingHandler to its own file. Add...

Reformat the logging classes. Extract the LoggingHandler to its own file. Add proper documentation. Fix typos.
parent 0e2f2ec4
No related branches found
No related tags found
No related merge requests found
<?php <?php
/** /**
* A class for logging * The main logger class for SimpleSAMLphp.
* *
* @author Lasse Birnbaum Jensen, SDU. * @author Lasse Birnbaum Jensen, SDU.
* @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no> * @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
...@@ -9,40 +9,32 @@ ...@@ -9,40 +9,32 @@
* @version $ID$ * @version $ID$
*/ */
interface SimpleSAML_Logger_LoggingHandler { class SimpleSAML_Logger
function log_internal($level,$string); {
private static $loggingHandler = NULL;
private static $logLevel = NULL;
private static $captureLog = FALSE;
private static $capturedLog = array();
function setLogFormat($format); /**
} * Array with messages logged before the logging handler was initialized.
*
* @var array
*/
private static $earlyLog = array();
class SimpleSAML_Logger {
private static $loggingHandler = null; /**
private static $logLevel = null; * This constant defines the string we set the track ID to while we are fetching the track ID from the session
* class. This is used to prevent infinite recursion.
private static $captureLog = FALSE; */
private static $capturedLog = array(); private static $TRACKID_FETCHING = '_NOTRACKIDYET_';
/** /**
* Array with log messages from before we * This variable holds the track ID we have retrieved from the session class. It can also be NULL, in which case
* initialized the logging handler. * we haven't fetched the track ID yet, or TRACKID_FETCHING, which means that we are fetching the track ID now.
* */
* @var array private static $trackid = NULL;
*/
private static $earlyLog = array();
/**
* This constant defines the string we set the trackid to while we are fetching the
* trackid from the session class. This is used to prevent infinite recursion.
*/
private static $TRACKID_FETCHING = '_NOTRACKIDYET_';
/**
* This variable holds the trackid we have retrieved from the session class.
* It can also hold NULL, in which case we haven't fetched the trackid yet, or
* TRACKID_FETCHING, which means that we are fetching the trackid now.
*/
private static $trackid = null;
/** /**
* This variable holds the format used to log any message. Its use varies depending on the log handler used (for * This variable holds the format used to log any message. Its use varies depending on the log handler used (for
...@@ -73,156 +65,208 @@ class SimpleSAML_Logger { ...@@ -73,156 +65,208 @@ class SimpleSAML_Logger {
*/ */
private static $format = '%date{%b %d %H:%M:%S} %process %level %stat[%trackid] %msg'; private static $format = '%date{%b %d %H:%M:%S} %process %level %stat[%trackid] %msg';
/* const EMERG = 0;
* LOG_ERR No statistics, only errors const ALERT = 1;
* LOG_WARNING No statistics, only warnings/errors const CRIT = 2;
* LOG_NOTICE Statistics and errors const ERR = 3;
* LOG_INFO Verbose logs const WARNING = 4;
* LOG_DEBUG Full debug logs - not reccomended for production const NOTICE = 5;
const INFO = 6;
*/ const DEBUG = 7;
const EMERG = 0;
const ALERT = 1;
const CRIT = 2; /**
const ERR = 3; * Log an emergency message.
const WARNING = 4; *
const NOTICE = 5; * @var string $string The message to log.
const INFO = 6; */
const DEBUG = 7; public static function emergency($string)
{
static function emergency($string) { self::log(self::EMERG, $string);
self::log_internal(self::EMERG,$string); }
}
static function critical($string) { /**
self::log_internal(self::CRIT,$string); * Log a critical message.
} *
* @var string $string The message to log.
static function alert($string) { */
self::log_internal(self::ALERT,$string); public static function critical($string)
} {
self::log(self::CRIT, $string);
static function error($string) { }
self::log_internal(self::ERR,$string);
}
/**
static function warning($string) { * Log an alert.
self::log_internal(self::WARNING,$string); *
} * @var string $string The message to log.
*/
/** public static function alert($string)
* We reserve the notice level for statistics, so do not use {
* this level for other kind of log messages. self::log(self::ALERT, $string);
*/ }
static function notice($string) {
self::log_internal(self::NOTICE,$string);
} /**
* Log an error.
/** *
* Info messages is abit less verbose than debug messages. This is useful * @var string $string The message to log.
* for tracing a session. */
*/ public static function error($string)
static function info($string) { {
self::log_internal(self::INFO,$string); self::log(self::ERR, $string);
} }
/**
* Debug messages is very verbose, and will contain more inforation than /**
* what is neccessary for a production system. * Log a warning.
*/ *
static function debug($string) { * @var string $string The message to log.
self::log_internal(self::DEBUG,$string); */
} public static function warning($string)
{
/** self::log(self::WARNING, $string);
* Statisitics }
*/
static function stats($string) { /**
self::log_internal(self::NOTICE,$string,true); * We reserve the notice level for statistics, so do not use this level for other kind of log messages.
} *
* @var string $string The message to log.
*/
public static function notice($string)
public static function createLoggingHandler() { {
self::log(self::NOTICE, $string);
/* Set to FALSE to indicate that it is being initialized. */ }
self::$loggingHandler = FALSE;
/* Get the configuration. */ /**
$config = SimpleSAML_Configuration::getInstance(); * Info messages are a bit less verbose than debug messages. This is useful to trace a session.
assert($config instanceof SimpleSAML_Configuration); *
* @var string $string The message to log.
/* Get the metadata handler option from the configuration. */ */
$handler = $config->getString('logging.handler', 'syslog'); public static function info($string)
{
/* self::log(self::INFO, $string);
* setting minimum log_level }
*/
self::$logLevel = $config->getInteger('logging.level',self::INFO);
/**
$handler = strtolower($handler); * Debug messages are very verbose, and will contain more information than what is necessary for a production
* system.
if($handler === 'syslog') { *
$sh = new SimpleSAML_Logger_LoggingHandlerSyslog(); * @var string $string The message to log.
*/
} elseif ($handler === 'file') { public static function debug($string)
$sh = new SimpleSAML_Logger_LoggingHandlerFile(); {
} elseif ($handler === 'errorlog') { self::log(self::DEBUG, $string);
$sh = new SimpleSAML_Logger_LoggingHandlerErrorLog(); }
} else {
throw new Exception('Invalid value for the [logging.handler] configuration option. Unknown handler: ' . $handler);
} /**
* Statistics.
*
* @var string $string The message to log.
*/
public static function stats($string)
{
self::log(self::NOTICE, $string, TRUE);
}
/**
* Set the logger to capture logs.
*
* @var boolean $val Whether to capture logs or not. Defaults to TRUE.
*/
public static function setCaptureLog($val = TRUE)
{
self::$captureLog = $val;
}
/**
* Get the captured log.
*/
public static function getCapturedLog()
{
return self::$capturedLog;
}
private static function createLoggingHandler()
{
// set to FALSE to indicate that it is being initialized
self::$loggingHandler = FALSE;
// get the configuration
$config = SimpleSAML_Configuration::getInstance();
assert($config instanceof SimpleSAML_Configuration);
// get the metadata handler option from the configuration
$handler = $config->getString('logging.handler', 'syslog');
// setting minimum log_level
self::$logLevel = $config->getInteger('logging.level', self::INFO);
$handler = strtolower($handler);
if ($handler === 'syslog') {
$sh = new SimpleSAML_Logger_LoggingHandlerSyslog();
} elseif ($handler === 'file') {
$sh = new SimpleSAML_Logger_LoggingHandlerFile();
} elseif ($handler === 'errorlog') {
$sh = new SimpleSAML_Logger_LoggingHandlerErrorLog();
} else {
throw new Exception(
'Invalid value for the [logging.handler] configuration option. Unknown handler: ' . $handler
);
}
self::$format = $config->getString('logging.format', self::$format); self::$format = $config->getString('logging.format', self::$format);
$sh->setLogFormat(self::$format); $sh->setLogFormat(self::$format);
/* Set the session handler. */ // set the session handler
self::$loggingHandler = $sh; self::$loggingHandler = $sh;
} }
public static function setCaptureLog($val = TRUE) {
self::$captureLog = $val; private static function log($level, $string, $statsLog = FALSE)
} {
if (self::$loggingHandler === NULL) {
public static function getCapturedLog() { /* Initialize logging. */
return self::$capturedLog; self::createLoggingHandler();
}
if (!empty(self::$earlyLog)) {
static function log_internal($level,$string,$statsLog = false) { error_log('----------------------------------------------------------------------');
if (self::$loggingHandler === NULL) { // output messages which were logged before we properly initialized logging
/* Initialize logging. */ foreach (self::$earlyLog as $msg) {
self::createLoggingHandler(); self::log($msg['level'], $msg['string'], $msg['statsLog']);
}
if (!empty(self::$earlyLog)) { }
error_log('----------------------------------------------------------------------'); } elseif (self::$loggingHandler === FALSE) {
/* Output messages which were logged before we initialized to the proper log. */ // some error occurred while initializing logging
foreach (self::$earlyLog as $msg) { if (empty(self::$earlyLog)) {
self::log_internal($msg['level'], $msg['string'], $msg['statsLog']); // this is the first message
} error_log('--- Log message(s) while initializing logging ------------------------');
} }
error_log($string);
} elseif (self::$loggingHandler === FALSE) {
/* Some error occurred while initializing logging. */ self::$earlyLog[] = array('level' => $level, 'string' => $string, 'statsLog' => $statsLog);
if (empty(self::$earlyLog)) { return;
/* This is the first message. */ }
error_log('--- Log message(s) while initializing logging ------------------------');
} if (self::$captureLog) {
error_log($string); $ts = microtime(TRUE);
$msecs = (int) (($ts - (int) $ts) * 1000);
self::$earlyLog[] = array('level' => $level, 'string' => $string, 'statsLog' => $statsLog); $ts = GMdate('H:i:s', $ts).sprintf('.%03d', $msecs).'Z';
return; self::$capturedLog[] = $ts.' '.$string;
} }
if (self::$logLevel >= $level || $statsLog) {
if (self::$captureLog) { if (is_array($string)) {
$ts = microtime(TRUE); $string = implode(",", $string);
$msecs = (int)(($ts - (int)$ts) * 1000); }
$ts = GMdate('H:i:s', $ts) . sprintf('.%03d', $msecs) . 'Z';
self::$capturedLog[] = $ts . ' ' . $string;
}
if (self::$logLevel >= $level || $statsLog) {
if (is_array($string)) $string = implode(",",$string);
$formats = array('%trackid', '%msg', '%srcip', '%stat'); $formats = array('%trackid', '%msg', '%srcip', '%stat');
$replacements = array(self::getTrackId(), $string, $_SERVER['REMOTE_ADDR']); $replacements = array(self::getTrackId(), $string, $_SERVER['REMOTE_ADDR']);
...@@ -234,39 +278,38 @@ class SimpleSAML_Logger { ...@@ -234,39 +278,38 @@ class SimpleSAML_Logger {
array_push($replacements, $stat); array_push($replacements, $stat);
$string = str_replace($formats, $replacements, self::$format); $string = str_replace($formats, $replacements, self::$format);
self::$loggingHandler->log_internal($level, $string); self::$loggingHandler->log($level, $string);
} }
} }
/** /**
* Retrieve the trackid we should use for logging. * Retrieve the track ID we should use for logging. It is used to avoid infinite recursion between the logger class
* * and the session class.
* It is used to avoid infinite recursion between the logger class and the session class. *
* * @return string The track ID we should use for logging, or 'NA' if we detect recursion.
* @return The trackid we should use for logging, or 'NA' if we detect recursion. */
*/ private static function getTrackId()
private static function getTrackId() { {
if (self::$trackid === self::$TRACKID_FETCHING) {
if(self::$trackid === self::$TRACKID_FETCHING) { // recursion detected!
/* Recursion detected. */ return 'NA';
return 'NA'; }
}
if (self::$trackid === NULL) {
if(self::$trackid === NULL) { // no track ID yet, fetch it from the session class
/* No trackid yet, fetch it from the session class. */
// mark it as currently being fetched
/* Mark it as currently being fetched. */ self::$trackid = self::$TRACKID_FETCHING;
self::$trackid = self::$TRACKID_FETCHING;
// get the current session. This could cause recursion back to the logger class
/* Get the current session. This could cause recursion back to the logger class. */ $session = SimpleSAML_Session::getInstance();
$session = SimpleSAML_Session::getInstance();
// update the track ID
/* Update the trackid. */ self::$trackid = $session->getTrackID();
self::$trackid = $session->getTrackID(); }
}
assert('is_string(self::$trackid)');
assert('is_string(self::$trackid)'); return self::$trackid;
return self::$trackid; }
}
} }
<?php
/**
* The interface that must be implemented by any log handler.
*
* @author Jaime Perez Crespo, UNINETT AS.
* @package simpleSAMLphp
* @version $ID$
*/
interface SimpleSAML_Logger_LoggingHandler
{
/**
* Log a message to its destination.
*
* @param int $level The log level.
* @param string $string The formatted message to log.
*/
public function log($level, $string);
/**
* Set the format desired for the logs.
*
* @param string $format The format used for logs.
*/
public function setLogFormat($format);
}
...@@ -9,38 +9,53 @@ ...@@ -9,38 +9,53 @@
* @package simpleSAMLphp * @package simpleSAMLphp
* @version $ID$ * @version $ID$
*/ */
class SimpleSAML_Logger_LoggingHandlerErrorLog implements SimpleSAML_Logger_LoggingHandler { class SimpleSAML_Logger_LoggingHandlerErrorLog implements SimpleSAML_Logger_LoggingHandler
{
/**
* This array contains the mappings from syslog loglevel to names. /**
*/ * This array contains the mappings from syslog loglevel to names.
private static $levelNames = array( */
SimpleSAML_Logger::EMERG => 'EMERG', private static $levelNames = array(
SimpleSAML_Logger::ALERT => 'ALERT', SimpleSAML_Logger::EMERG => 'EMERG',
SimpleSAML_Logger::CRIT => 'CRIT', SimpleSAML_Logger::ALERT => 'ALERT',
SimpleSAML_Logger::ERR => 'ERR', SimpleSAML_Logger::CRIT => 'CRIT',
SimpleSAML_Logger::WARNING => 'WARNING', SimpleSAML_Logger::ERR => 'ERR',
SimpleSAML_Logger::NOTICE => 'NOTICE', SimpleSAML_Logger::WARNING => 'WARNING',
SimpleSAML_Logger::INFO => 'INFO', SimpleSAML_Logger::NOTICE => 'NOTICE',
SimpleSAML_Logger::DEBUG => 'DEBUG', SimpleSAML_Logger::INFO => 'INFO',
); SimpleSAML_Logger::DEBUG => 'DEBUG',
);
private $format;
function setLogFormat($format) {
/**
* Set the format desired for the logs.
*
* @param string $format The format used for logs.
*/
public function setLogFormat($format)
{
$this->format = $format; $this->format = $format;
} }
function log_internal($level, $string) { /**
$config = SimpleSAML_Configuration::getInstance(); * Log a message to syslog.
assert($config instanceof SimpleSAML_Configuration); *
$processname = $config->getString('logging.processname','simpleSAMLphp'); * @param int $level The log level.
* @param string $string The formatted message to log.
if(array_key_exists($level, self::$levelNames)) { */
$levelName = self::$levelNames[$level]; public function log($level, $string)
} else { {
$levelName = sprintf('UNKNOWN%d', $level); $config = SimpleSAML_Configuration::getInstance();
} assert($config instanceof SimpleSAML_Configuration);
$processname = $config->getString('logging.processname', 'simpleSAMLphp');
if (array_key_exists($level, self::$levelNames)) {
$levelName = self::$levelNames[$level];
} else {
$levelName = sprintf('UNKNOWN%d', $level);
}
$formats = array('%process', '%level'); $formats = array('%process', '%level');
$replacements = array($processname, $levelName); $replacements = array($processname, $levelName);
...@@ -48,8 +63,6 @@ class SimpleSAML_Logger_LoggingHandlerErrorLog implements SimpleSAML_Logger_Logg ...@@ -48,8 +63,6 @@ class SimpleSAML_Logger_LoggingHandlerErrorLog implements SimpleSAML_Logger_Logg
$string = preg_replace('/%\w+(\{[^\}]+\})?/', '', $string); $string = preg_replace('/%\w+(\{[^\}]+\})?/', '', $string);
$string = trim($string); $string = trim($string);
error_log($string); error_log($string);
} }
} }
?>
\ No newline at end of file
...@@ -9,60 +9,82 @@ ...@@ -9,60 +9,82 @@
* @version $ID$ * @version $ID$
*/ */
class SimpleSAML_Logger_LoggingHandlerFile implements SimpleSAML_Logger_LoggingHandler { class SimpleSAML_Logger_LoggingHandlerFile implements SimpleSAML_Logger_LoggingHandler
{
/** /**
* This array contains the mappings from syslog loglevel to names. Copied * This array contains the mappings from syslog loglevel to names. Copied
* more or less directly from SimpleSAML_Logger_LoggingHandlerErrorLog. * more or less directly from SimpleSAML_Logger_LoggingHandlerErrorLog.
*/ */
private static $levelNames = array( private static $levelNames = array(
SimpleSAML_Logger::EMERG => 'EMERGENCY', SimpleSAML_Logger::EMERG => 'EMERGENCY',
SimpleSAML_Logger::ALERT => 'ALERT', SimpleSAML_Logger::ALERT => 'ALERT',
SimpleSAML_Logger::CRIT => 'CRITICAL', SimpleSAML_Logger::CRIT => 'CRITICAL',
SimpleSAML_Logger::ERR => 'ERROR', SimpleSAML_Logger::ERR => 'ERROR',
SimpleSAML_Logger::WARNING => 'WARNING', SimpleSAML_Logger::WARNING => 'WARNING',
SimpleSAML_Logger::NOTICE => 'NOTICE', SimpleSAML_Logger::NOTICE => 'NOTICE',
SimpleSAML_Logger::INFO => 'INFO', SimpleSAML_Logger::INFO => 'INFO',
SimpleSAML_Logger::DEBUG => 'DEBUG', SimpleSAML_Logger::DEBUG => 'DEBUG',
); );
private $logFile = NULL;
private $logFile = null; private $processname = NULL;
private $processname = null;
private $format; private $format;
function __construct() {
/**
* Build a new logging handler based on files.
*/
public function __construct()
{
$config = SimpleSAML_Configuration::getInstance(); $config = SimpleSAML_Configuration::getInstance();
assert($config instanceof SimpleSAML_Configuration); assert($config instanceof SimpleSAML_Configuration);
/* Get the metadata handler option from the configuration. */ // get the metadata handler option from the configuration
$this->logFile = $config->getPathValue('loggingdir', 'log/').$config->getString('logging.logfile', 'simplesamlphp.log'); $this->logFile = $config->getPathValue('loggingdir', 'log/') .
$this->processname = $config->getString('logging.processname','simpleSAMLphp'); $config->getString('logging.logfile', 'simplesamlphp.log');
$this->processname = $config->getString('logging.processname', 'simpleSAMLphp');
if (@file_exists($this->logFile)) { if (@file_exists($this->logFile)) {
if (!@is_writeable($this->logFile)) throw new Exception("Could not write to logfile: ".$this->logFile); if (!@is_writeable($this->logFile)) {
} throw new Exception("Could not write to logfile: " . $this->logFile);
else }
{ } else {
if (!@touch($this->logFile)) throw new Exception("Could not create logfile: ".$this->logFile." Loggingdir is not writeable for the webserver user."); if (!@touch($this->logFile)) {
throw new Exception(
"Could not create logfile: " . $this->logFile .
" Loggingdir is not writeable for the webserver user."
);
}
} }
SimpleSAML_Utilities::initTimezone(); SimpleSAML_Utilities::initTimezone();
} }
function setLogFormat($format) { /**
* Set the format desired for the logs.
*
* @param string $format The format used for logs.
*/
public function setLogFormat($format)
{
$this->format = $format; $this->format = $format;
} }
function log_internal($level, $string) { /**
if ($this->logFile != null) { * Log a message to the log file.
*
// Set human-readable log level. Copied from SimpleSAML_Logger_LoggingHandlerErrorLog. * @param int $level The log level.
if(array_key_exists($level, self::$levelNames)) * @param string $string The formatted message to log.
$levelName = self::$levelNames[$level]; */
else public function log($level, $string)
$levelName = sprintf('UNKNOWN%d', $level); {
if ($this->logFile != NULL) {
// set human-readable log level. Copied from SimpleSAML_Logger_LoggingHandlerErrorLog.
$levelName = sprintf('UNKNOWN%d', $level);
if (array_key_exists($level, self::$levelNames)) {
$levelName = self::$levelNames[$level];
}
$formats = array('%process', '%level'); $formats = array('%process', '%level');
$replacements = array($this->processname, $levelName); $replacements = array($this->processname, $levelName);
...@@ -79,9 +101,7 @@ class SimpleSAML_Logger_LoggingHandlerFile implements SimpleSAML_Logger_LoggingH ...@@ -79,9 +101,7 @@ class SimpleSAML_Logger_LoggingHandlerFile implements SimpleSAML_Logger_LoggingH
} }
$string = str_replace($formats, $replacements, $string); $string = str_replace($formats, $replacements, $string);
file_put_contents($this->logFile, $string . PHP_EOL, FILE_APPEND); file_put_contents($this->logFile, $string.PHP_EOL, FILE_APPEND);
} }
} }
} }
?>
\ No newline at end of file
...@@ -9,44 +9,60 @@ ...@@ -9,44 +9,60 @@
* @version $ID$ * @version $ID$
*/ */
class SimpleSAML_Logger_LoggingHandlerSyslog implements SimpleSAML_Logger_LoggingHandler { class SimpleSAML_Logger_LoggingHandlerSyslog implements SimpleSAML_Logger_LoggingHandler
{
private $isWindows = FALSE;
private $format;
private $isWindows = false;
function __construct() { /**
* Build a new logging handler based on syslog.
*/
public function __construct()
{
$config = SimpleSAML_Configuration::getInstance(); $config = SimpleSAML_Configuration::getInstance();
assert($config instanceof SimpleSAML_Configuration); assert($config instanceof SimpleSAML_Configuration);
$facility = $config->getInteger('logging.facility', defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER); $facility = $config->getInteger('logging.facility', defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER);
$processname = $config->getString('logging.processname','simpleSAMLphp'); $processname = $config->getString('logging.processname', 'simpleSAMLphp');
/*
* OS Check // Setting facility to LOG_USER (only valid in Windows), enable log level rewrite on windows systems.
* Setting facility to LOG_USER (only valid in Windows), enable log level rewrite on windows systems.
*/
if (SimpleSAML_Utilities::isWindowsOS()) { if (SimpleSAML_Utilities::isWindowsOS()) {
$this->isWindows = true; $this->isWindows = TRUE;
$facility = LOG_USER; $facility = LOG_USER;
} }
openlog($processname, LOG_PID, $facility); openlog($processname, LOG_PID, $facility);
} }
function setLogFormat($format) { /**
* Set the format desired for the logs.
*
* @param string $format The format used for logs.
*/
public function setLogFormat($format)
{
$this->format = $format; $this->format = $format;
} }
function log_internal($level,$string) { /**
/* * Log a message to syslog.
* Changing log level to supported levels if OS is Windows *
*/ * @param int $level The log level.
if ($this->isWindows) { * @param string $string The formatted message to log.
if ($level <= 4) */
$level = LOG_ERR; public function log($level, $string)
else {
$level = LOG_INFO; // changing log level to supported levels if OS is Windows
} if ($this->isWindows) {
if ($level <= 4) {
$level = LOG_ERR;
} else {
$level = LOG_INFO;
}
}
$formats = array('%process', '%level'); $formats = array('%process', '%level');
$replacements = array('', $level); $replacements = array('', $level);
...@@ -57,4 +73,3 @@ class SimpleSAML_Logger_LoggingHandlerSyslog implements SimpleSAML_Logger_Loggin ...@@ -57,4 +73,3 @@ class SimpleSAML_Logger_LoggingHandlerSyslog implements SimpleSAML_Logger_Loggin
syslog($level, $string); syslog($level, $string);
} }
} }
?>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment