ZP-765 Logging system now uses instance instead of static files. Released...

ZP-765 Logging system now uses instance instead of static files. Released under the Affero GNU General Public License (AGPL) version 3.
parent e62f4478
/etc/kronos/z-push/config.php
\ No newline at end of file
...@@ -98,6 +98,8 @@ ...@@ -98,6 +98,8 @@
define('LOGERRORFILE', LOGFILEDIR . 'z-push-error.log'); define('LOGERRORFILE', LOGFILEDIR . 'z-push-error.log');
define('LOGLEVEL', LOGLEVEL_WBXML); define('LOGLEVEL', LOGLEVEL_WBXML);
define('LOGAUTHFAIL', false); define('LOGAUTHFAIL', false);
// Either filelog or syslog or a custom log class in core/log/logclass
define('LOGBACKEND', 'filelog');
// To save e.g. WBXML data only for selected users, add the usernames to the array // To save e.g. WBXML data only for selected users, add the usernames to the array
...@@ -107,14 +109,14 @@ ...@@ -107,14 +109,14 @@
define('LOGUSERLEVEL', LOGLEVEL_DEVICEID); define('LOGUSERLEVEL', LOGLEVEL_DEVICEID);
$specialLogUsers = array(); $specialLogUsers = array();
// If you want to disable log to file, and log to syslog instead
define('LOG_SYSLOG_ENABLED', false);
// false will log to local syslog, otherwise put the remote syslog IP here // false will log to local syslog, otherwise put the remote syslog IP here
define('LOG_SYSLOG_HOST', false); define('LOG_SYSLOG_HOST', false);
// Syslog port // Syslog port
define('LOG_SYSLOG_PORT', 514); define('LOG_SYSLOG_PORT', 514);
// Program showed in the syslog. Useful if you have more than one instance login to the same syslog // Program showed in the syslog. Useful if you have more than one instance login to the same syslog
define('LOG_SYSLOG_PROGRAM', '[z-push]'); define('LOG_SYSLOG_PROGRAM', 'z-push');
// Syslog facility
define('LOG_SYSLOG_FACILITY', LOG_LOCAL0);
// Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem' // Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem'
......
<?php
/*
* Copyright 2015 Leon van Kammen / Coder of Salvation. All rights reserved.
* Modifications 2015 - Francisco Miguel Biete
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Leon van Kammen / Coder of Salvation AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Leon van Kammen / Coder of Salvation OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Leon van Kammen / Coder of Salvation
*
* https://github.com/coderofsalvation/syslog-flexible
*/
class ZSyslog {
private static $hostname = false;
private static $port = 514;
private static $program = "[z-push]";
/**
* Initializes the logging
*
* @access public
* @return boolean
*/
public static function Initialize() {
if (defined('LOG_SYSLOG_HOST'))
self::$hostname = LOG_SYSLOG_HOST;
if (defined('LOG_SYSLOG_PORT'))
self::$port = LOG_SYSLOG_PORT;
if (defined('LOG_SYSLOG_PROGRAM'))
self::$program = LOG_SYSLOG_PROGRAM;
}
/**
* Send a message in the syslog facility.
*
* @params int $zlog_level Z-Push LogLevel
* @params string $message
*
* @access public
* @return boolean
*/
public static function send($zlog_level, $message) {
$level = self::zlogLevel2SyslogLevel($zlog_level);
if ($level === false) {
return false;
}
if (self::$hostname === false) {
return syslog($level, $message);
}
else {
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$facility = 1; // user level
$pri = ($facility*8) + $level; // multiplying the Facility number by 8 + adding the level
foreach (explode("\n", $message) as $line) {
if (strlen(trim($line)) > 0) {
$syslog_message = "<{$pri}>" . date('M d H:i:s ') . self::$program . ': ' . $line;
socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, self::$hostname, self::$port);
}
}
socket_close($sock);
}
return true;
}
/**
* Converts the ZLog level to SYSLOG level.
*
* @params int $loglevel Z-Push LogLevel
*
* @access private
* @return SYSLOG_LEVEL or false
*/
private static function zlogLevel2SyslogLevel($loglevel) {
switch($loglevel) {
case LOGLEVEL_OFF: return false; break;
case LOGLEVEL_FATAL: return LOG_ALERT; break;
case LOGLEVEL_ERROR: return LOG_ERR; break;
case LOGLEVEL_WARN: return LOG_WARNING; break;
case LOGLEVEL_INFO: return LOG_INFO; break;
case LOGLEVEL_DEBUG: return LOG_DEBUG; break;
case LOGLEVEL_WBXML: return LOG_DEBUG; break;
case LOGLEVEL_DEVICEID: return LOG_DEBUG; break;
case LOGLEVEL_WBXMLSTACK: return LOG_DEBUG; break;
}
}
}
...@@ -69,8 +69,10 @@ include_once('lib/core/asdevice.php'); ...@@ -69,8 +69,10 @@ include_once('lib/core/asdevice.php');
include_once('lib/core/statemanager.php'); include_once('lib/core/statemanager.php');
include_once('lib/core/devicemanager.php'); include_once('lib/core/devicemanager.php');
include_once('lib/core/zpush.php'); include_once('lib/core/zpush.php');
include_once('include/z_syslog.php');
include_once('lib/core/zlog.php'); include_once('lib/core/zlog.php');
include_once('lib/log/log.php');
include_once('lib/log/filelog.php');
include_once('lib/log/syslog.php');
include_once('lib/interface/ibackend.php'); include_once('lib/interface/ibackend.php');
include_once('lib/interface/ichanges.php'); include_once('lib/interface/ichanges.php');
include_once('lib/interface/iexportchanges.php'); include_once('lib/interface/iexportchanges.php');
......
...@@ -42,15 +42,19 @@ ...@@ -42,15 +42,19 @@
************************************************/ ************************************************/
class ZLog { class ZLog {
static private $devid = ''; static private $devid = ''; //done
static private $user = ''; static private $user = ''; // done
static private $authUser = false; static private $authUser = false;
static private $pidstr; static private $pidstr; //done
static private $wbxmlDebug = ''; static private $wbxmlDebug = '';
static private $lastLogs = array(); static private $lastLogs = array();
static private $userLog = false; static private $userLog = false;
static private $unAuthCache = array(); static private $unAuthCache = array();
static private $syslogEnabled = false; static private $syslogEnabled = false;
/**
* @var Log $logger
*/
static private $logger = null;
/** /**
* Initializes the logging * Initializes the logging
...@@ -59,12 +63,7 @@ class ZLog { ...@@ -59,12 +63,7 @@ class ZLog {
* @return boolean * @return boolean
*/ */
static public function Initialize() { static public function Initialize() {
global $specialLogUsers; $logger = self::getLogger();
if (defined('LOG_SYSLOG_ENABLED') && LOG_SYSLOG_ENABLED) {
self::$syslogEnabled = true;
ZSyslog::Initialize();
}
// define some constants for the logging // define some constants for the logging
if (!defined('LOGUSERLEVEL')) if (!defined('LOGUSERLEVEL'))
...@@ -73,27 +72,14 @@ class ZLog { ...@@ -73,27 +72,14 @@ class ZLog {
if (!defined('LOGLEVEL')) if (!defined('LOGLEVEL'))
define('LOGLEVEL', LOGLEVEL_OFF); define('LOGLEVEL', LOGLEVEL_OFF);
list($user,) = Utils::SplitDomainUser(strtolower(Request::GetGETUser())); if (!defined('WBXML_DEBUG')) {
self::$userLog = in_array($user, $specialLogUsers);
if (!defined('WBXML_DEBUG') && $user) {
// define the WBXML_DEBUG mode on user basis depending on the configurations // define the WBXML_DEBUG mode on user basis depending on the configurations
if (LOGLEVEL >= LOGLEVEL_WBXML || (LOGUSERLEVEL >= LOGLEVEL_WBXML && self::$userLog)) if (LOGLEVEL >= LOGLEVEL_WBXML || (LOGUSERLEVEL >= LOGLEVEL_WBXML && $logger->HasSpecialLogUsers()))
define('WBXML_DEBUG', true); define('WBXML_DEBUG', true);
else else
define('WBXML_DEBUG', false); define('WBXML_DEBUG', false);
} }
if ($user)
self::$user = '['. $user .'] ';
else
self::$user = '';
// log the device id if the global loglevel is set to log devid or the user is in and has the right log level
if (Request::GetDeviceID() != "" && (LOGLEVEL >= LOGLEVEL_DEVICEID || (LOGUSERLEVEL >= LOGLEVEL_DEVICEID && self::$userLog)))
self::$devid = '['. Request::GetDeviceID() .'] ';
else
self::$devid = '';
return true; return true;
} }
...@@ -114,35 +100,13 @@ class ZLog { ...@@ -114,35 +100,13 @@ class ZLog {
$message = substr($message, 0, 10240) . sprintf(" <log message with %d bytes truncated>", $messagesize); $message = substr($message, 0, 10240) . sprintf(" <log message with %d bytes truncated>", $messagesize);
self::$lastLogs[$loglevel] = $message; self::$lastLogs[$loglevel] = $message;
$data = self::buildLogString($loglevel) . $message . "\n";
if ($loglevel <= LOGLEVEL) { try{
self::writeToLog($loglevel, $data, LOGFILE); self::getLogger()->Log($loglevel, $message);
}
// should we write this into the user log?
if ($loglevel <= LOGUSERLEVEL && self::$userLog) {
// padd level for better reading
$data = str_replace(self::getLogLevelString($loglevel), self::getLogLevelString($loglevel,true), $data);
// is the user authenticated?
if (self::logToUserFile()) {
// something was logged before the user was authenticated, write this to the log
if (!empty(self::$unAuthCache)) {
self::writeToLog($loglevel, implode('', self::$unAuthCache), LOGFILEDIR . self::logToUserFile() . ".log");
self::$unAuthCache = array();
}
// only use plain old a-z characters for the generic log file
self::writeToLog($loglevel, $data, LOGFILEDIR . self::logToUserFile() . ".log");
}
// the user is not authenticated yet, we save the log into memory for now
else {
self::$unAuthCache[] = $data;
}
} }
catch(\Exception $e) {
if (($loglevel & LOGLEVEL_FATAL) || ($loglevel & LOGLEVEL_ERROR)) { //@TODO How should we handle logging error ?
self::writeToLog($loglevel, $data, LOGERRORFILE); // Ignore any error.
} }
if ($loglevel & LOGLEVEL_WBXMLSTACK) { if ($loglevel & LOGLEVEL_WBXMLSTACK) {
...@@ -193,101 +157,35 @@ class ZLog { ...@@ -193,101 +157,35 @@ class ZLog {
} }
} }
/**----------------------------------------------------------------------------------------------------------
* private log stuff
*/
/** /**
* Returns the filename logs for a WBXML debug log user should be saved to * Returns the logger object. If no logger has been initialized, FileLog will be initialized and returned.
* *
* @access private * @access private
* @return string * @return Log
* @throws Exception thrown if the logger class cannot be instantiated.
*/ */
static private function logToUserFile() { static private function getLogger() {
global $specialLogUsers; if (!self::$logger) {
global $specialLogUsers; // This variable comes from the configuration file (config.php)
if (self::$authUser === false) { $logger = LOGBACKEND;
if (RequestProcessor::isUserAuthenticated()) { if (!class_exists($logger)) {
$authuser = Request::GetAuthUser(); throw new \Exception('The class `'.$logger.'` does not exist.');
if ($authuser && in_array($authuser, $specialLogUsers))
self::$authUser = preg_replace('/[^a-z0-9]/', '_', strtolower($authuser));
} }
}
return self::$authUser;
}
/** $user = '['.Utils::SplitDomainUser(strtolower(Request::GetGETUser()))[0].']';
* Returns the string to be logged
*
* @access private
* @return string
*/
static private function buildLogString($loglevel) {
if (!isset(self::$pidstr))
self::$pidstr = '[' . str_pad(@getmypid(),5," ",STR_PAD_LEFT) . '] ';
if (!isset(self::$user))
self::$user = '';
if (!isset(self::$devid))
self::$devid = '';
if (self::$syslogEnabled)
return self::$pidstr . self::getLogLevelString($loglevel, (LOGLEVEL > LOGLEVEL_INFO)) . " " . self::$user . self::$devid;
else
return Utils::GetFormattedTime() . " " . self::$pidstr . self::getLogLevelString($loglevel, (LOGLEVEL > LOGLEVEL_INFO)) . " " . self::$user . self::$devid;
}
/** self::$logger = new $logger();
* Returns the string representation of the LOGLEVEL. self::$logger->SetUser($user);
* String can be padded self::$logger->SetSpecialLogUsers($specialLogUsers);
* self::$logger->SetDevid('['. Request::GetDeviceID() .']');
* @param int $loglevel one of the LOGLEVELs self::$logger->SetPidstr('[' . str_pad(@getmypid(),5," ",STR_PAD_LEFT) . ']');
* @param boolean $pad
*
* @access private
* @return string
*/
static private function getLogLevelString($loglevel, $pad = false) {
if ($pad) $s = " ";
else $s = "";
switch($loglevel) {
case LOGLEVEL_OFF: return ""; break;
case LOGLEVEL_FATAL: return "[FATAL]"; break;
case LOGLEVEL_ERROR: return "[ERROR]"; break;
case LOGLEVEL_WARN: return "[".$s."WARN]"; break;
case LOGLEVEL_INFO: return "[".$s."INFO]"; break;
case LOGLEVEL_DEBUG: return "[DEBUG]"; break;
case LOGLEVEL_WBXML: return "[WBXML]"; break;
case LOGLEVEL_DEVICEID: return "[DEVICEID]"; break;
case LOGLEVEL_WBXMLSTACK: return "[WBXMLSTACK]"; break;
} }
return self::$logger;
} }
/** /**----------------------------------------------------------------------------------------------------------
* Write the message to the log facility. * private log stuff
*
* @param int $loglevel
* @param string $data
* @param string $logfile
*
* @access private
* @return void
*/ */
static private function writeToLog($loglevel, $data, $logfile = null) {
if (self::$syslogEnabled) {
if (ZSyslog::send($loglevel, $data) === false) {
error_log("Unable to send to syslog");
error_log($data);
}
}
else {
if (@file_put_contents($logfile, $data, FILE_APPEND) === false) {
error_log(sprintf("Unable to write in %s", $logfile));
error_log($data);
}
}
}
} }
/**---------------------------------------------------------------------------------------------------------- /**----------------------------------------------------------------------------------------------------------
......
...@@ -220,24 +220,50 @@ class ZPush { ...@@ -220,24 +220,50 @@ class ZPush {
else else
define('REAL_BASE_PATH', BASE_PATH); define('REAL_BASE_PATH', BASE_PATH);
if (!defined('LOGFILEDIR')) if(!defined('LOGBACKEND')){
throw new FatalMisconfigurationException("The LOGFILEDIR is not configured. Check if the config.php file is in place."); define('LOGBACKEND', 'filelog');
}
if(LOGBACKEND == 'syslog') {
if(!defined('LOG_SYSLOG_FACILITY')) {
define('LOG_SYSLOG_FACILITY', LOG_LOCAL0);
}
if(!defined('LOG_SYSLOG_HOST')){
define('LOG_SYSLOG_HOST', false);
}
if(!defined('LOG_SYSLOG_PORT')){
define('LOG_SYSLOG_PORT', 514);
}
if(!defined('LOG_SYSLOG_PROGRAM')){
define('LOG_SYSLOG_PROGRAM', 'z-push');
}
if(!is_numeric(LOG_SYSLOG_PORT)){
throw new FatalMisconfigurationException("The LOG_SYSLOG_PORT must a be a number.");
}
if(LOG_SYSLOG_HOST && LOG_SYSLOG_PORT <= 0){
throw new FatalMisconfigurationException("LOG_SYSLOG_HOST is defined but the LOG_SYSLOG_PORT does not seem to be valid.");
}
}
elseif(LOGBACKEND == 'filelog'){
if (!defined('LOGFILEDIR'))
throw new FatalMisconfigurationException("The LOGFILEDIR is not configured. Check if the config.php file is in place.");
if (substr(LOGFILEDIR, -1,1) != "/") if (substr(LOGFILEDIR, -1,1) != "/")
throw new FatalMisconfigurationException("The LOGFILEDIR should terminate with a '/'"); throw new FatalMisconfigurationException("The LOGFILEDIR should terminate with a '/'");
if (!file_exists(LOGFILEDIR)) if (!file_exists(LOGFILEDIR))
throw new FatalMisconfigurationException("The configured LOGFILEDIR does not exist or can not be accessed."); throw new FatalMisconfigurationException("The configured LOGFILEDIR does not exist or can not be accessed.");
if ((!file_exists(LOGFILE) && !touch(LOGFILE)) || !is_writable(LOGFILE)) if ((!file_exists(LOGFILE) && !touch(LOGFILE)) || !is_writable(LOGFILE))
throw new FatalMisconfigurationException("The configured LOGFILE can not be modified."); throw new FatalMisconfigurationException("The configured LOGFILE can not be modified.");
if ((!file_exists(LOGERRORFILE) && !touch(LOGERRORFILE)) || !is_writable(LOGERRORFILE)) if ((!file_exists(LOGERRORFILE) && !touch(LOGERRORFILE)) || !is_writable(LOGERRORFILE))
throw new FatalMisconfigurationException("The configured LOGERRORFILE can not be modified."); throw new FatalMisconfigurationException("The configured LOGERRORFILE can not be modified.");
// check ownership on the (eventually) just created files // check ownership on the (eventually) just created files
Utils::FixFileOwner(LOGFILE); Utils::FixFileOwner(LOGFILE);
Utils::FixFileOwner(LOGERRORFILE); Utils::FixFileOwner(LOGERRORFILE);
}
// set time zone // set time zone
// code contributed by Robert Scheck (rsc) - more information: https://developer.berlios.de/mantis/view.php?id=479 // code contributed by Robert Scheck (rsc) - more information: https://developer.berlios.de/mantis/view.php?id=479
......
<?php
class FileLog extends Log{
/**
* @var string|bool
*/
private $log_to_user_file = false;
/**
* Get the log user file. If the parameter is false, it tries to generate it.
*
* @access private
* @return string|bool False if the log user file is not set and could not be generated otherwise string.
*/
private function getLogToUserFile() {
if ($this->log_to_user_file === false) {
$this->setLogToUserFile(preg_replace('/[^a-z0-9]/', '_', strtolower(Request::GetAuthUser())) . '.log');
}
return $this->log_to_user_file;
}
/**
* @param string $value
*/
private function setLogToUserFile($value) {
$this->log_to_user_file = $value;
}
public function __construct(){}
/**
* Returns the string to be logged
*
* @param int $loglevel
* @param string $message
*
* @access public
* @return string
*/
public function BuildLogString($loglevel, $message) {
$log = Utils::GetFormattedTime() . $this->GetPidstr() . $this->GetLogLevelString($loglevel, $loglevel >= LOGLEVEL_INFO) .' '. $this->GetUser();
if ($loglevel >= LOGLEVEL_DEVICEID) {
$log .= $this->GetDevid();
}
$log .= ' ' . $message;
return $log;
}
//
// Implementation of Log
//
protected function Write($loglevel, $message){
$data = $this->buildLogString($loglevel, $message) . "\n";
@file_put_contents(LOGFILE, $data, FILE_APPEND);
if (($loglevel & LOGLEVEL_FATAL) || ($loglevel & LOGLEVEL_ERROR)) {
@file_put_contents(LOGERRORFILE, $data, FILE_APPEND);
}
}
public function WriteForUser($loglevel, $message){
$data = $this->buildLogString($loglevel, $message) . "\n";
@file_put_contents(LOGFILEDIR . $this->getLogToUserFile(), $data, FILE_APPEND);
}
protected function afterLog($loglevel, $message){
if (($loglevel & LOGLEVEL_FATAL) || ($loglevel & LOGLEVEL_ERROR)) {
$data = $this->buildLogString($loglevel, $message) . "\n";
@file_put_contents(LOGERRORFILE, $data, FILE_APPEND);
}
}
}
<?php
abstract class Log{
/**
* @var string
*/
protected $user = '';
/**
* @var string
*/
protected $devid = '';
/**
* @var string
*/
protected $pidstr = '';
/**
* @var array
*/
protected $specialLogUsers = array();
/**
* @var array
*/
private $unauthMessageCache = array();
/**
* @access public
* @return string
*/
public function GetUser() {
return $this->user;
}
/**
* @param string$value
*
* @access public
*/
public function SetUser($value) {
$this->user = $value;
}
/**
* @access public
* @return string
*/
public function GetDevid() {
return $this->devid;
}
/**
* @param string $value
*
* @access public
*/
public function SetDevid($value) {
$this->devid = $value;
}
/**
* @access public
* @return string
*/
public function GetPidstr() {
return $this->pidstr;
}
/**
* @param string $value
*
* @access public
*/
public function SetPidstr($value) {
$this->pidstr = $value;
}
/**
* @access public
* @return bool True if we do have to log some specific user. False otherwise.
*/
public function HasSpecialLogUsers() {
return !empty($this->specialLogUsers);
}
/**
* @param string $user
*
* @acces public
* @return bool
*/
public function IsUserInSpecialLogUsers($user) {
if ($this->HasSpecialLogUsers()) {
return in_array($user, $this->GetSpecialLogUsers());
}
return false;
}
/**
* @access public
* @return array
*/
public function GetSpecialLogUsers() {
return $this->specialLogUsers;
}
/**
* @param array $value
*
* @access public
*/
public function SetSpecialLogUsers(array $value) {
$this->specialLogUsers = $value;
}
public function __construct() {}
/**
* @param int $loglevel
* @param string $message
*/
public function Log($loglevel, $message) {
if ($loglevel <= LOGLEVEL) {
$this->Write($loglevel, $message);
}
if ($loglevel <= LOGUSERLEVEL && $this->HasSpecialLogUsers()) {
if(RequestProcessor::isUserAuthenticated() && $this->IsUserInSpecialLogUsers(Request::GetAuthUser())) {
// something was logged before the user was authenticated, write this to the log
if (!empty($this->unauthMessageCache)) {
foreach ($this->unauthMessageCache as $authcache) {
$this->WriteForUser($authcache[0], $authcache[1]);
}
self::$unAuthCache = array();
}
$this->WriteForUser($loglevel, $message);
}
else {
$this->unauthMessageCache[] = [$loglevel, $message];
}
}
$this->afterLog($loglevel, $message);
}
/**
* This function is used as an event for log implementer.
*/
protected function afterLog($loglevel, $message) {}
/**
* Returns the string representation of the given $loglevel.
* String can be padded
*
* @param int $loglevel one of the LOGLEVELs
* @param boolean $pad
*
* @access protected
* @return string
*/
protected function GetLogLevelString($loglevel, $pad = false) {
if ($pad) $s = " ";
else $s = "";
switch($loglevel) {
case LOGLEVEL_OFF: return ""; break;
case LOGLEVEL_FATAL: return "[FATAL]"; break;
case LOGLEVEL_ERROR: return "[ERROR]"; break;
case LOGLEVEL_WARN: return "[".$s."WARN]"; break;
case LOGLEVEL_INFO: return "[".$s."INFO]"; break;
case LOGLEVEL_DEBUG: return "[DEBUG]"; break;
case LOGLEVEL_WBXML: return "[WBXML]"; break;
case LOGLEVEL_DEVICEID: return "[DEVICEID]"; break;
case LOGLEVEL_WBXMLSTACK: return "[WBXMLSTACK]"; break;
}
}
/**
* @param int $loglevel
* @param string $message
*
* @access public
* @return null
*/
abstract protected function Write($loglevel, $message);
/**
* @param int $loglevel
* @param string $message
*
* @access public
* @return null
*/
abstract public function WriteForUser($loglevel, $message);
}
\ No newline at end of file
<?php
class Syslog extends Log{
protected $program_name = '';
protected $host;
protected $port;
/**
* @access public
* @return string
*/
public function GetProgramName() {
return $this->program_name;
}
/**
* @param string $value
*
* @access public
*/
public function SetProgramName($value) {
$this->program_name = $value;
}
/**
* @access public
* @return string
*/
public function GetHost() {
return $this->host;
}
/**
* @param string $value
*
* @access public
*/
public function SetHost($value) {
$this->host = $value;
}
/**
* @access public
* @return int
*/
public function GetPort() {
return $this->port;
}
/**
* @param int $value
*
* @access public
*/
public function SetPort($value) {
if (is_numeric($value)) {
$this->port = (int)$value;
}
}
public function __construct($program_name = null, $host = null, $port = null) {
parent::__construct();
if(is_null($program_name)) $program_name = LOG_SYSLOG_PROGRAM;
if(is_null($host)) $host = LOG_SYSLOG_HOST;
if(is_null($port)) $port = LOG_SYSLOG_PORT;
$this->SetProgramName($program_name);
$this->SetHost($host);
$this->SetPort($port);
}
/**
* Return the full program name for syslog.
* The name can be z-push/core or z-push/{backend} where backend is the backend that initiated the log.
*
* @access protected
* @return string
*/
protected function GenerateProgramName() {
// @TODO Use another mechanism than debug_backtrace to determine to origin of the log
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// Shift the "syslog.php" entry.
array_shift($backtrace);
foreach($backtrace as $trace) {
if (!isset($trace['file'])) {
continue;
}
if (strpos($trace['file'], REAL_BASE_PATH . 'backend/') !== false) {
preg_match('/\/backend\/([a-zA-Z]*)/', $trace['file'], $match);
if (isset($match[1])) {
return $this->GetProgramName().'/'.$match[1];
}
}
elseif (basename($trace['file'], '.php') != 'zlog') {
return $this->GetProgramName().'/core';
}
}
return $this->GetProgramName().'/core';
}
/**
* Maps the z-push loglevel with those of syslog.
*
* @access protected
* @param int $loglevel
* @return int One of many LOG_* syslog level.
*/
protected function GetZpushLogLevelToSyslogLogLevel($loglevel) {
switch($loglevel) {
case LOGLEVEL_FATAL: return LOG_ALERT; break;
case LOGLEVEL_ERROR: return LOG_ERR; break;
case LOGLEVEL_WARN: return LOG_WARNING; break;
case LOGLEVEL_INFO: return LOG_INFO; break;
case LOGLEVEL_DEBUG: return LOG_DEBUG; break;
case LOGLEVEL_WBXML: return LOG_DEBUG; break;
case LOGLEVEL_DEVICEID: return LOG_DEBUG; break;
case LOGLEVEL_WBXMLSTACK: return LOG_DEBUG; break;
}
return null;
}
/**
* Build the log string for syslog.
*
* @param int $loglevel
* @param string $message
*
* @access public
* @return string
*/
public function BuildLogString($loglevel, $message) {
$log = $this->GetLogLevelString($loglevel); // Never pad syslog log because syslog log are usually read with a software.
$log .= $this->GetUser();
if($loglevel >= LOGLEVEL_DEVICEID) {
$log .= $this->GetDevid();
}
$log .= ' ' . $message;
return $log;
}
//
// Implementation of Log
//
protected function Write($loglevel, $message) {
if ($this->GetHost() && $this->GetPort()) {
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$facility = 1; // user level
$pri = ($facility*8) + $loglevel; // multiplying the Facility number by 8 + adding the level
$data = $this->buildLogString($loglevel, $message);
if (strlen(trim($data)) > 0) {
$syslog_message = "<{$pri}>" . date('M d H:i:s ') . '['.$this->GetProgramName() . ']: ' . $data;
socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $this->GetHost(), $this->GetPort());
}
socket_close($sock);
}
else {
openlog($this->GenerateProgramName(), LOG_PID, LOG_SYSLOG_FACILITY);
syslog(
$this->GetZpushLogLevelToSyslogLogLevel($loglevel),
$this->buildLogString($loglevel, $message)
);
}
}
public function WriteForUser($loglevel, $message) {
$this->Write(LOGLEVEL_DEBUG, $message); // Always pass the logleveldebug so it uses syslog level LOG_DEBUG
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment