#74 Added the configuration of logging (errors, web service usage, etc.), and improved a little the error logging (both in a file and into the database + new format for additional information such as the callstack)

SVN:trunk[403]
This commit is contained in:
Romain Quetiez
2010-05-13 20:40:52 +00:00
parent 4e09d304f8
commit d527b56340
14 changed files with 492 additions and 57 deletions

View File

@@ -291,53 +291,55 @@ class ActionEmail extends ActionNotification
$this->m_aMailErrors[] = $e->getMessage();
}
$oLog = new EventNotificationEmail();
if (empty($this->m_aMailErrors))
if (MetaModel::IsLogEnabledNotification())
{
if ($this->IsBeingTested())
$oLog = new EventNotificationEmail();
if (empty($this->m_aMailErrors))
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification sent');
}
}
else
{
$oLog->Set('message', 'Notification sent');
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
}
else
{
$oLog->Set('message', 'Notification was not sent: '.$sError);
}
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
}
else
{
$oLog->Set('message', 'Notification was not sent: '.$sError);
}
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->id']);
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->id']);
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
$oLog->DBInsertNoReload();
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
$oLog->DBInsertNoReload();
}
}
}
?>

View File

@@ -1441,10 +1441,20 @@ class AttributeBlob extends AttributeDefinition
// (temporary tables created on disk)
// We will have to remove the blobs from the list of attributes when doing the select
// then the use of Get() should finalize the load
$aValues = array();
$aValues[$this->GetCode().'_data'] = $value->GetData();
$aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
$aValues[$this->GetCode().'_filename'] = $value->GetFileName();
if ($value instanceOf ormDocument)
{
$aValues = array();
$aValues[$this->GetCode().'_data'] = $value->GetData();
$aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
$aValues[$this->GetCode().'_filename'] = $value->GetFileName();
}
else
{
$aValues = array();
$aValues[$this->GetCode().'_data'] = '';
$aValues[$this->GetCode().'_mimetype'] = '';
$aValues[$this->GetCode().'_filename'] = '';
}
return $aValues;
}
@@ -1490,5 +1500,121 @@ class AttributeBlob extends AttributeDefinition
}
}
// Indexed array having two dimensions
class AttributeTable extends AttributeText
{
public function GetType() {return "Table";}
public function GetTypeDesc() {return "Array with 2 dimensions";}
public function GetEditClass() {return "Text";}
protected function GetSQLCol() {return "TEXT";}
// Facilitate things: allow the user to Set the value from a string
public function MakeRealValue($proposedValue)
{
if (!is_array($proposedValue))
{
return array(0 => array(0 => $proposedValue));
}
return $proposedValue;
}
public function FromSQLToValue($aCols, $sPrefix = '')
{
try
{
$value = @unserialize($aCols[$sPrefix.'']);
if ($value === false)
{
$value = $this->MakeRealValue($aCols[$sPrefix.'']);
}
}
catch(Exception $e)
{
$value = $this->MakeRealValue($aCols[$sPrefix.'']);
}
return $value;
}
public function GetSQLValues($value)
{
$aValues = array();
$aValues[$this->Get("sql")] = serialize($value);
return $aValues;
}
public function GetAsHTML($value)
{
if (!is_array($value))
{
throw new CoreException('Expecting an array', array('found' => get_class($value)));
}
if (count($value) == 0)
{
return "";
}
$sRes = "<TABLE class=\"listResults\">";
$sRes .= "<TBODY>";
foreach($value as $iRow => $aRawData)
{
$sRes .= "<TR>";
foreach ($aRawData as $iCol => $cell)
{
$sCell = str_replace("\n", "<br>\n", Str::pure2html((string)$cell));
$sRes .= "<TD>$sCell</TD>";
}
$sRes .= "</TR>";
}
$sRes .= "</TBODY>";
$sRes .= "</TABLE>";
return $sRes;
}
}
// The PHP value is a hash array, it is stored as a TEXT column
class AttributePropertySet extends AttributeTable
{
public function GetType() {return "PropertySet";}
public function GetTypeDesc() {return "List of properties (name and value)";}
public function GetEditClass() {return "Text";}
protected function GetSQLCol() {return "TEXT";}
// Facilitate things: allow the user to Set the value from a string
public function MakeRealValue($proposedValue)
{
if (!is_array($proposedValue))
{
return array('?' => (string)$proposedValue);
}
return $proposedValue;
}
public function GetAsHTML($value)
{
if (!is_array($value))
{
throw new CoreException('Expecting an array', array('found' => get_class($value)));
}
if (count($value) == 0)
{
return "";
}
$sRes = "<TABLE class=\"listResults\">";
$sRes .= "<TBODY>";
foreach($value as $sProperty => $sValue)
{
$sRes .= "<TR>";
$sCell = str_replace("\n", "<br>\n", Str::pure2html((string)$sValue));
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
$sRes .= "</TR>";
}
$sRes .= "</TBODY>";
$sRes .= "</TABLE>";
return $sRes;
}
}
?>

View File

@@ -16,6 +16,7 @@
require_once('coreexception.class.inc.php');
require_once('config.class.inc.php');
require_once('log.class.inc.php');
require_once('dict.class.inc.php');

View File

@@ -16,6 +16,11 @@ class ConfigException extends CoreException
{
}
define ('DEFAULT_LOG_GLOBAL', true);
define ('DEFAULT_LOG_NOTIFICATION', true);
define ('DEFAULT_LOG_ISSUE', true);
define ('DEFAULT_LOG_WEB_SERVICE', true);
define ('DEFAULT_MIN_DISPLAY_LIMIT', 10);
define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
@@ -38,6 +43,14 @@ class Config
protected $m_sDBName;
protected $m_sDBSubname;
/**
* @var integer Event log options (see LOG_... definition)
*/
protected $m_bLogGlobal;
protected $m_bLogNotification;
protected $m_bLogIssue;
protected $m_bLogWebService;
/**
* @var integer Number of elements to be displayed when there are more than m_iMaxDisplayLimit elements
*/
@@ -79,6 +92,10 @@ class Config
$this->m_sDBPwd = '';
$this->m_sDBName = '';
$this->m_sDBSubname = '';
$this->m_bLogGlobal = DEFAULT_LOG_GLOBAL;
$this->m_bLogNotification = DEFAULT_LOG_NOTIFICATION;
$this->m_bLogIssue = DEFAULT_LOG_ISSUE;
$this->m_bLogWebService = DEFAULT_LOG_WEB_SERVICE;
$this->m_iMinDisplayLimit = DEFAULT_MIN_DISPLAY_LIMIT;
$this->m_iMaxDisplayLimit = DEFAULT_MAX_DISPLAY_LIMIT;
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
@@ -167,6 +184,10 @@ class Config
$this->m_sDBName = trim($MySettings['db_name']);
$this->m_sDBSubname = trim($MySettings['db_subname']);
$this->m_bLogGlobal = isset($MySettings['log_global']) ? trim($MySettings['log_global']) : DEFAULT_LOG_GLOBAL;
$this->m_bLogNotification = isset($MySettings['log_notification']) ? trim($MySettings['log_notification']) : DEFAULT_LOG_NOTIFICATION;
$this->m_bLogIssue = isset($MySettings['log_issue']) ? trim($MySettings['log_issue']) : DEFAULT_LOG_ISSUE;
$this->m_bLogWebService = isset($MySettings['log_web_service']) ? trim($MySettings['log_web_service']) : DEFAULT_LOG_WEB_SERVICE;
$this->m_iMinDisplayLimit = isset($MySettings['min_display_limit']) ? trim($MySettings['min_display_limit']) : DEFAULT_MIN_DISPLAY_LIMIT;
$this->m_iMaxDisplayLimit = isset($MySettings['max_display_limit']) ? trim($MySettings['max_display_limit']) : DEFAULT_MAX_DISPLAY_LIMIT;
$this->m_iStandardReloadInterval = isset($MySettings['standard_reload_interval']) ? trim($MySettings['standard_reload_interval']) : DEFAULT_STANDARD_RELOAD_INTERVAL;
@@ -241,6 +262,26 @@ class Config
return $this->m_sDBPwd;
}
public function GetLogGlobal()
{
return $this->m_bLogGlobal;
}
public function GetLogNotification()
{
return $this->m_bLogNotification;
}
public function GetLogIssue()
{
return $this->m_bLogIssue;
}
public function GetLogWebService()
{
return $this->m_bLogWebService;
}
public function GetMinDisplayLimit()
{
return $this->m_iMinDisplayLimit;
@@ -296,6 +337,26 @@ class Config
$this->m_sDBPwd = $sPwd;
}
public function SetLogGlobal($iLogGlobal)
{
$this->m_iLogGlobal = $iLogGlobal;
}
public function SetLogNotification($iLogNotification)
{
$this->m_iLogNotification = $iLogNotification;
}
public function SetLogIssue($iLogIssue)
{
$this->m_iLogIssue = $iLogIssue;
}
public function SetLogWebService($iLogWebService)
{
$this->m_iLogWebService = $iLogWebService;
}
public function SetMinDisplayLimit($iMinDisplayLimit)
{
$this->m_iMinDisplayLimit = $iMinDisplayLimit;
@@ -363,6 +424,10 @@ class Config
fwrite($hFile, "\t'db_name' => '{$this->m_sDBName}',\n");
fwrite($hFile, "\t'db_subname' => '{$this->m_sDBSubname}',\n");
fwrite($hFile, "\n");
fwrite($hFile, "\t'log_global' => {$this->m_bLogGlobal},\n");
fwrite($hFile, "\t'log_notification' => {$this->m_bLogNotification},\n");
fwrite($hFile, "\t'log_issue' => {$this->m_bLogIssue},\n");
fwrite($hFile, "\t'log_web_service' => {$this->m_bLogWebService},\n");
fwrite($hFile, "\t'min_display_limit' => {$this->m_iMinDisplayLimit},\n");
fwrite($hFile, "\t'max_display_limit' => {$this->m_iMaxDisplayLimit},\n");
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");

View File

@@ -64,6 +64,19 @@ class CoreException extends Exception
{
$this->m_aContextData[$sKey] = $value;
}
public function getIssue()
{
return $this->m_sIssue;
}
public function getImpact()
{
return $this->m_sImpact;
}
public function getContextData()
{
return $this->m_aContextData;
}
}
class CoreWarning extends CoreException

View File

@@ -145,10 +145,10 @@ class EventIssue extends Event
MetaModel::Init_AddAttribute(new AttributeString("issue", array("allowed_values"=>null, "sql"=>"issue", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("impact", array("allowed_values"=>null, "sql"=>"impact", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("page", array("allowed_values"=>null, "sql"=>"page", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBlob("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTable("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_InheritFilters();
MetaModel::Init_AddFilterFromAttribute("issue");
@@ -161,6 +161,43 @@ class EventIssue extends Event
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
public function OnInsert()
{
// Init page information: name, arguments
//
$this->Set('page', @$GLOBALS['_SERVER']['SCRIPT_NAME']);
if (array_key_exists('_GET', $GLOBALS) && is_array($GLOBALS['_GET']))
{
$this->Set('arguments_get', $GLOBALS['_GET']);
}
else
{
$this->Set('arguments_get', array());
}
if (array_key_exists('_POST', $GLOBALS) && is_array($GLOBALS['_POST']))
{
$aPost = array();
foreach($GLOBALS['_POST'] as $sKey => $sValue)
{
if (strlen($sValue) < 256)
{
$aPost[$sKey] = $sValue;
}
else
{
$aPost[$sKey] = "!long string: ".strlen($sValue). " chars";
}
}
$this->Set('arguments_post', $aPost);
}
else
{
$this->Set('arguments_post', array());
}
}
}

109
core/log.class.inc.php Normal file
View File

@@ -0,0 +1,109 @@
<?php
/**
* Log
* logging to files
*
* @package iTopORM
* @author Romain Quetiez <romainquetiez@yahoo.fr>
* @author Denis Flaven <denisflave@free.fr>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.itop.com
* @since 1.0
* @version 1.1.1.1 $
*/
class FileLog
{
protected $m_sFile = ''; // log is disabled if this is empty
public function __construct($sFileName = '')
{
$this->m_sFile = $sFileName;
}
public function Error($sText)
{
self::Write("Error | ".$sText);
}
public function Warning($sText)
{
self::Write("Warning | ".$sText);
}
public function Info($sText)
{
self::Write("Info | ".$sText);
}
public function Ok($sText)
{
self::Write("Ok | ".$sText);
}
protected function Write($sText)
{
if (strlen($this->m_sFile) == 0) return;
$hLogFile = @fopen($this->m_sFile, 'a');
if ($hLogFile !== false)
{
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fclose($hLogFile);
}
}
}
class SetupLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
class IssueLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
?>

View File

@@ -167,6 +167,22 @@ abstract class MetaModel
private static $m_bTraceQueries = true;
private static $m_aQueriesLog = array();
private static $m_bLogIssue = false;
private static $m_bLogNotification = false;
private static $m_bLogWebService = false;
public static function IsLogEnabledIssue()
{
return self::$m_bLogIssue;
}
public static function IsLogEnabledNotification()
{
return self::$m_bLogNotification;
}
public static function IsLogEnabledWebService()
{
return self::$m_bLogWebService;
}
private static $m_sDBName = "";
private static $m_sTablePrefix = ""; // table prefix for the current application instance (allow several applications on the same DB)
@@ -2839,6 +2855,24 @@ abstract class MetaModel
{
$oConfig = new Config($sConfigFile);
// Set log ASAP
if ($oConfig->GetLogGlobal())
{
if ($oConfig->GetLogIssue())
{
self::$m_bLogIssue = true;
IssueLog::Enable('../error.log');
}
self::$m_bLogNotification = $oConfig->GetLogNotification();
self::$m_bLogWebService = $oConfig->GetLogWebService();
}
else
{
self::$m_bLogIssue = false;
self::$m_bLogNotification = false;
self::$m_bLogWebService = false;
}
foreach ($oConfig->GetAppModules() as $sModule => $sToInclude)
{
self::Plugin($sConfigFile, 'application', $sToInclude);

View File

@@ -10,6 +10,8 @@ require_once('expression.class.inc.php');
require_once('cmdbsource.class.inc.php');
require_once('sqlquery.class.inc.php');
require_once('log.class.inc.php');
require_once('dbobject.class.php');
require_once('dbobjectsearch.class.php');
require_once('dbobjectset.class.php');