diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 5e86fa5f8..6551508d5 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -113,70 +113,86 @@ class Config * @since 2.7.0 export_pdf_font param */ protected $m_aSettings = [ - 'log_level_min' => [ - 'type' => 'array', - 'description' => 'Optional min log level, per channel.', - 'default' => '', - 'value' => '', - 'source_of_value' => '', + 'log_level_min' => [ + 'type' => 'array', + 'description' => 'Optional min log level, per channel.', + 'default' => '', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'log_level_min.write_in_db' => [ - 'type' => 'array', - 'description' => 'Optional min log level IN DB, per channel.', - 'default' => '', - 'value' => '', - 'source_of_value' => '', + 'log_level_min.write_in_db' => [ + 'type' => 'array', + 'description' => 'Optional min log level IN DB, per channel.', + 'default' => '', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'event_service.debug.filter_events' => [ - 'type' => 'array', - 'description' => 'List of events name to filter Event Service debug messages', - 'default' => [], - 'value' => '', - 'source_of_value' => '', + 'log_purge.enabled' => [ + 'type' => 'bool', + 'description' => 'Optional purge activation.', + 'default' => false, + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], + 'log_purge.max_keep_days' => [ + 'type' => 'integer', + 'description' => 'Optional purge number of days to keep logs.', + 'default' => 365, + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], + 'event_service.debug.filter_events' => [ + 'type' => 'array', + 'description' => 'List of events name to filter Event Service debug messages', + 'default' => [], + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], 'event_service.debug.filter_sources' => [ - 'type' => 'array', - 'description' => 'List of event sources to filter Event Service debug messages', - 'default' => '', - 'value' => '', - 'source_of_value' => '', + 'type' => 'array', + 'description' => 'List of event sources to filter Event Service debug messages', + 'default' => '', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'app_env_label' => [ - 'type' => 'string', - 'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")', - 'default' => '', - 'value' => '', - 'source_of_value' => '', + 'app_env_label' => [ + 'type' => 'string', + 'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")', + 'default' => '', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'app_root_url' => [ - 'type' => 'string', - 'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)', - 'default' => '', - 'value' => '', - 'source_of_value' => '', + 'app_root_url' => [ + 'type' => 'string', + 'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)', + 'default' => '', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => true, ], - 'app_icon_url' => [ - 'type' => 'string', - 'description' => 'Hyperlink to redirect the user when clicking on the application icon (in the main window, or login/logoff pages)', - 'default' => 'http://www.combodo.com/itop', - 'value' => '', - 'source_of_value' => '', + 'app_icon_url' => [ + 'type' => 'string', + 'description' => 'Hyperlink to redirect the user when clicking on the application icon (in the main window, or login/logoff pages)', + 'default' => 'http://www.combodo.com/itop', + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => false, ], - 'db_host' => [ - 'type' => 'string', - 'default' => null, - 'value' => '', - 'source_of_value' => '', + 'db_host' => [ + 'type' => 'string', + 'default' => null, + 'value' => '', + 'source_of_value' => '', 'show_in_conf_sample' => true, ], - 'db_user' => [ + 'db_user' => [ 'type' => 'string', 'default' => null, 'value' => '', diff --git a/core/log.class.inc.php b/core/log.class.inc.php index eb83beedd..092faded2 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -612,12 +612,12 @@ abstract class LogAPI { public const CHANNEL_DEFAULT = ''; - public const LEVEL_ERROR = 'Error'; + public const LEVEL_ERROR = 'Error'; public const LEVEL_WARNING = 'Warning'; - public const LEVEL_INFO = 'Info'; - public const LEVEL_OK = 'Ok'; - public const LEVEL_DEBUG = 'Debug'; - public const LEVEL_TRACE = 'Trace'; + public const LEVEL_INFO = 'Info'; + public const LEVEL_OK = 'Ok'; + public const LEVEL_DEBUG = 'Debug'; + public const LEVEL_TRACE = 'Trace'; /** * @see GetMinLogLevel @@ -645,7 +645,22 @@ abstract class LogAPI ); public const ENUM_CONFIG_PARAM_FILE = 'log_level_min'; - public const ENUM_CONFIG_PARAM_DB = 'log_level_min.write_in_db'; + public const ENUM_CONFIG_PARAM_DB = 'log_level_min.write_in_db'; + + + /** + * Parameter to enable log purge. + * + * @since 3.1.0 + */ + public const ENUM_CONFIG_PARAM_PURGE_ENABLED = 'log_purge.enabled'; + + /** + * Parameter to define day we want to keep old log files. + * + * @since 3.1.0 + */ + public const ENUM_CONFIG_PARAM_PURGE_MAX_KEEP_DAYS = 'log_purge.max_keep_days'; /** * @var \Config attribute allowing to mock config in the tests @@ -1336,8 +1351,7 @@ class LogFileRotationProcess implements iScheduledProcess { $sLogFileNameBuilder = $this->GetLogFileNameBuilderClassName(); - foreach (self::LOGFILES_TO_ROTATE as $sLogFileName) - { + foreach (self::LOGFILES_TO_ROTATE as $sLogFileName) { $sLogFileFullPath = APPROOT .DIRECTORY_SEPARATOR.'log' .DIRECTORY_SEPARATOR.$sLogFileName; @@ -1347,6 +1361,77 @@ class LogFileRotationProcess implements iScheduledProcess $oLogFileNameBuilder->ResetLastModifiedDateForFile(); $oLogFileNameBuilder->CheckAndRotateLogFile(); } + + // Purge logs if purge enabled + if (MetaModel::GetConfig()->Get(LogAPI::ENUM_CONFIG_PARAM_PURGE_ENABLED)) { + $this->PurgeLogs(); + } + } + + /** + * PurgeLogs. + * + * Purge test last modification time of file in log folder and delete + * files that haven't modifications since {@see \LogAPI::ENUM_CONFIG_PARAM_PURGE_MAX_KEEP_DAYS} + * + * @return array process feedback + * @since 3.1.0 + */ + public function PurgeLogs(): array + { + // result + $aFilesResult = array(); + + // Max keep days + $iMaxDays = MetaModel::GetConfig()->Get(LogAPI::ENUM_CONFIG_PARAM_PURGE_MAX_KEEP_DAYS); + + // Files iterator (*.*) + $oIterator = new \GlobIterator(APPROOT.'log'.DIRECTORY_SEPARATOR.'/*.*'); + $aLogFiles = iterator_to_array($oIterator); + + // Reference date + $oDateNow = new DateTime('now'); + + // Iterate throw files... + foreach ($aLogFiles as $oLogFile) { + + // File real path + $sFileRealPath = $oLogFile->getRealPath(); + + // Compute number of days since last modification + $oDateFileLastModification = new DateTime(); + $oDateFileLastModification->setTimestamp($oLogFile->getMTime()); + $iDays = intval($oDateFileLastModification->diff($oDateNow)->format('%a')); + + // File process status + $aFileResult = [ + 'file_name' => $sFileRealPath, + 'days_since_last_modification' => $iDays, + 'deleted' => false, + 'error' => null, + ]; + + // Delete file older than max last modified in days + if ($iDays > $iMaxDays) { + + // unlink file + if (!is_writable($sFileRealPath)) { + $aFileResult['error'] = Dict::S('itop-log-mgmt:UI:Error:file_read_only'); + } // unlink OK + else if (unlink($sFileRealPath)) { + $aFileResult['deleted'] = true; + } // unlink KO + else { + $aFileResult['error'] = Dict::S('itop-log-mgmt:UI:Error:unknown_error'); + } + + } + + // append result + $aFilesResult[] = $aFileResult; + } + + return $aFilesResult; } /** @@ -1354,12 +1439,10 @@ class LogFileRotationProcess implements iScheduledProcess */ public function GetNextOccurrence() { - try - { + try { $sLogFileNameBuilder = $this->GetLogFileNameBuilderClassName(); } - catch (ProcessException $e) - { + catch (ProcessException $e) { return new DateTime('3000-01-01'); }