diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ffd0a70..14c9871e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ Features: * #82: Added Danish translation. * #103: Added Russian translation. * #109: Custom time-out per server. +* #119: Log and archive retention period. * #110: Support for SMSGlobal SMS gateway . * #82: Support for Danish SMS provider Smsit diff --git a/src/lang/bg_BG.lang.php b/src/lang/bg_BG.lang.php index 257728cc..679fc405 100644 --- a/src/lang/bg_BG.lang.php +++ b/src/lang/bg_BG.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // За нов ред в имейл съобщението, моля използвайте тага
'notifications' => array( diff --git a/src/lang/da_DK.lang.php b/src/lang/da_DK.lang.php index 43d3e881..5dd633b7 100644 --- a/src/lang/da_DK.lang.php +++ b/src/lang/da_DK.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/de_DE.lang.php b/src/lang/de_DE.lang.php index b36e4dac..38bc37c9 100644 --- a/src/lang/de_DE.lang.php +++ b/src/lang/de_DE.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/en_US.lang.php b/src/lang/en_US.lang.php index ce789338..9c47eca6 100644 --- a/src/lang/en_US.lang.php +++ b/src/lang/en_US.lang.php @@ -173,7 +173,7 @@ $sm_lang = array( 'config' => array( 'general' => 'General', 'language' => 'Language', - 'show_update' => 'Updates', + 'show_update' => 'Check for updates?', 'email_status' => 'Allow sending email', 'email_from_email' => 'Email from address', 'email_from_name' => 'Email from name', @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/es_ES.lang.php b/src/lang/es_ES.lang.php index 5c32096a..095f3e4b 100644 --- a/src/lang/es_ES.lang.php +++ b/src/lang/es_ES.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/fr_FR.lang.php b/src/lang/fr_FR.lang.php index 00a5fa2b..cab685a7 100644 --- a/src/lang/fr_FR.lang.php +++ b/src/lang/fr_FR.lang.php @@ -251,6 +251,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/it_IT.lang.php b/src/lang/it_IT.lang.php index c4859486..86da1063 100644 --- a/src/lang/it_IT.lang.php +++ b/src/lang/it_IT.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/ko_KR.lang.php b/src/lang/ko_KR.lang.php index 68a71897..cda96b74 100644 --- a/src/lang/ko_KR.lang.php +++ b/src/lang/ko_KR.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/nl_NL.lang.php b/src/lang/nl_NL.lang.php index fede517b..8a273710 100644 --- a/src/lang/nl_NL.lang.php +++ b/src/lang/nl_NL.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'De volgende fout is opgetreden bij het versturen van de Pushover notificatie: %s', 'pushover_error_noapp' => 'Kan test notificatie niet verzenden: er is geen Pushover App API token gevonden in de algemene configuratie.', 'pushover_error_nokey' => 'Kan test notificatie niet verzenden: er is geen Pushover key gevonden in je profiel.', + 'log_retention_period' => 'Log retentie periode', + 'log_retention_period_description' => 'Aantal dagen dat logs van notificaties en archieven van server uptime worden bewaard. Vul 0 in om log opruiming uit te zetten.', + 'log_retention_days' => 'dagen', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/pt_BR.lang.php b/src/lang/pt_BR.lang.php index 5436cd22..91450b4e 100644 --- a/src/lang/pt_BR.lang.php +++ b/src/lang/pt_BR.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/ru_RU.lang.php b/src/lang/ru_RU.lang.php index 87712f94..6811305d 100644 --- a/src/lang/ru_RU.lang.php +++ b/src/lang/ru_RU.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'Произошла ошибка во время отправки Pushover уведомления: %s', 'pushover_error_noapp' => 'Не удалось отправить пробное уведомление: Pushover "App API token" не был найден в основных настройках.', 'pushover_error_nokey' => 'Не удалось отправить пробное уведомление: Pushover ключ не был найден в вашем профиле.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/lang/zh_CN.lang.php b/src/lang/zh_CN.lang.php index 6e83ca04..81703b3a 100644 --- a/src/lang/zh_CN.lang.php +++ b/src/lang/zh_CN.lang.php @@ -250,6 +250,9 @@ $sm_lang = array( 'pushover_error' => 'An error has occurred while sending the Pushover notification: %s', 'pushover_error_noapp' => 'Unable to send test notification: no Pushover App API token found in the global configuration.', 'pushover_error_nokey' => 'Unable to send test notification: no Pushover key found in your profile.', + 'log_retention_period' => 'Log retention period', + 'log_retention_period_description' => 'Number of days to keep logs of notifications and archives of server uptime. Enter 0 to disable log cleanup.', + 'log_retention_days' => 'days', ), // for newlines in the email messages use
'notifications' => array( diff --git a/src/psm/Module/Config/Controller/ConfigController.class.php b/src/psm/Module/Config/Controller/ConfigController.class.php index 125fee0b..5c7a2be1 100644 --- a/src/psm/Module/Config/Controller/ConfigController.class.php +++ b/src/psm/Module/Config/Controller/ConfigController.class.php @@ -112,6 +112,7 @@ class ConfigController extends AbstractController { $tpl_data['sms_selected_' . $config['sms_gateway']] = 'selected="selected"'; $tpl_data['alert_type_selected_' . $config['alert_type']] = 'selected="selected"'; $tpl_data['auto_refresh_servers'] = (isset($config['auto_refresh_servers'])) ? $config['auto_refresh_servers'] : '0'; + $tpl_data['log_retention_period'] = (isset($config['log_retention_period'])) ? $config['log_retention_period'] : '365'; foreach($this->checkboxes as $input_key) { $tpl_data[$input_key . '_checked'] = @@ -148,7 +149,8 @@ class ConfigController extends AbstractController { 'language' => $_POST['language'], 'sms_gateway' => $_POST['sms_gateway'], 'alert_type' => $_POST['alert_type'], - 'auto_refresh_servers' => (isset($_POST['auto_refresh_servers'])) ? intval($_POST['auto_refresh_servers']) : '0', + 'auto_refresh_servers' => intval(psm_POST('auto_refresh_servers', 0)), + 'log_retention_period' => intval(psm_POST('log_retention_period', 365)), ); foreach($this->checkboxes as $input_key) { $clean[$input_key] = (isset($_POST[$input_key])) ? '1': '0'; @@ -330,6 +332,9 @@ class ConfigController extends AbstractController { 'label_seconds' => psm_get_lang('config', 'seconds'), 'label_save' => psm_get_lang('system', 'save'), 'label_test' => psm_get_lang('config', 'test'), + 'label_log_retention_period' => psm_get_lang('config', 'log_retention_period'), + 'label_log_retention_period_description' => psm_get_lang('config', 'log_retention_period_description'), + 'label_log_retention_days' => psm_get_lang('config', 'log_retention_days'), ); } } diff --git a/src/psm/Util/Install/Installer.class.php b/src/psm/Util/Install/Installer.class.php index b3729195..4804c87a 100644 --- a/src/psm/Util/Install/Installer.class.php +++ b/src/psm/Util/Install/Installer.class.php @@ -150,6 +150,7 @@ class Installer { ('log_email', '1'), ('log_sms', '1'), ('log_pushover', '1'), + ('log_retention_period', '365'), ('version', '" . PSM_VERSION . "'), ('version_update_check', '" . PSM_VERSION . "'), ('auto_refresh_servers', '0'), @@ -398,6 +399,8 @@ class Installer { protected function upgrade310() { $queries = array(); + psm_update_conf('log_retention_period', '365'); + psm_update_conf('pushover_status', 1); psm_update_conf('log_pushover', 1); psm_update_conf('pushover_api_token', ''); diff --git a/src/psm/Util/Server/ArchiveManager.class.php b/src/psm/Util/Server/ArchiveManager.class.php new file mode 100644 index 00000000..42da59cd --- /dev/null +++ b/src/psm/Util/Server/ArchiveManager.class.php @@ -0,0 +1,119 @@ +. + * + * @package phpservermon + * @author Pepijn Over + * @copyright Copyright (c) 2008-2014 Pepijn Over + * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 + * @version Release: @package_version@ + * @link http://www.phpservermonitor.org/ + * @since phpservermon 3.1 + **/ + +namespace psm\Util\Server; + +/** + * Makes sure all data of servers is being archived properly or removed if necessary. + */ +class ArchiveManager { + + /** + * Available archiver utils. + * @var array $archivers + */ + protected $archivers = array(); + + /** + * Database service + * @var \psm\Service\Database $db + */ + protected $db; + + /** + * Retention period + * @var \DateInterval $retention_period + * @see setRetentionPeriod() + */ + protected $retention_period; + + public function __construct(\psm\Service\Database $db) { + $this->db = $db; + + $this->setRetentionPeriod(psm_get_conf('log_retention_period', 365)); + + $this->archivers[] = new Archiver\UptimeArchiver($db); + $this->archivers[] = new Archiver\LogsArchiver($db); + } + + /** + * Archive one or more servers. + * @param int $server_id + * @return boolean + */ + public function archive($server_id = null) { + $result = true; + foreach($this->archivers as $archiver) { + if(!$archiver->archive($server_id)) { + $result = false; + } + } + return $result; + } + + /** + * Cleanup old records for one or more servers + * @param int $server_id + * @return boolean + */ + public function cleanup($server_id = null) { + $result = true; + if(!$this->retention_period) { + // cleanup is disabled + return $result; + } + $retdate = new \DateTime(); + $retdate->sub($this->retention_period); + + foreach($this->archivers as $archiver) { + if(!$archiver->cleanup($retdate, $server_id)) { + $result = false; + } + } + return $result; + } + + /** + * Set retention period for this archive run. + * + * Set period to 0 to disable cleanup altogether. + * @param \DateInterval|int $period \DateInterval object or number of days (int) + * @return \psm\Util\Server\ArchiveManager + */ + public function setRetentionPeriod($period) { + if(is_object($period) && $period instanceof \DateInterval) { + $this->retention_period = $period; + } elseif(intval($period) == 0) { + // cleanup disabled + $this->retention_period = false; + } else { + $this->retention_period = new \DateInterval('P' . intval($period) . 'D'); + } + return $this; + } +} \ No newline at end of file diff --git a/src/psm/Util/Server/Archiver/ArchiverInterface.class.php b/src/psm/Util/Server/Archiver/ArchiverInterface.class.php new file mode 100644 index 00000000..084b3f6d --- /dev/null +++ b/src/psm/Util/Server/Archiver/ArchiverInterface.class.php @@ -0,0 +1,47 @@ +. + * + * @package phpservermon + * @author Pepijn Over + * @copyright Copyright (c) 2008-2014 Pepijn Over + * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 + * @version Release: @package_version@ + * @link http://www.phpservermonitor.org/ + * @since phpservermon 3.1 + **/ + +namespace psm\Util\Server\Archiver; + +interface ArchiverInterface { + + /** + * Archive for one or all servers. + * @param int $server_id + * @return boolean + */ + public function archive($server_id = null); + + /** + * Cleanup data older than the retention period given. + * @param \DateTime $retention_date + * @param int $server_id + * @return boolean + */ + public function cleanup(\DateTime $retention_date, $server_id = null); +} \ No newline at end of file diff --git a/src/psm/Util/Server/Archiver/LogsArchiver.class.php b/src/psm/Util/Server/Archiver/LogsArchiver.class.php new file mode 100644 index 00000000..c64073aa --- /dev/null +++ b/src/psm/Util/Server/Archiver/LogsArchiver.class.php @@ -0,0 +1,70 @@ +. + * + * @package phpservermon + * @author Pepijn Over + * @copyright Copyright (c) 2008-2014 Pepijn Over + * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 + * @version Release: @package_version@ + * @link http://www.phpservermonitor.org/ + * @since phpservermon 3.1 + **/ + +/** + * Cleanup log table + */ +namespace psm\Util\Server\Archiver; +use psm\Service\Database; + +class LogsArchiver implements ArchiverInterface { + + /** + * Database service + * @var \psm\Service\Database $db + */ + protected $db; + + function __construct(Database $db) { + $this->db = $db; + } + + /** + * Currently there is not really a log archive. + * + * It stays in the log table until cleaned up. + * @param int $server_id + */ + public function archive($server_id = null) { + return true; + } + + public function cleanup(\DateTime $retention_date, $server_id = null) { + $sql_where_server = ($server_id !== null) + // this is obviously not the cleanest way to implement this when using paramter binding.. sorry. + ? ' `server_id` = ' . intval($server_id) . ' AND ' + : ''; + + $this->db->execute( + "DELETE FROM `".PSM_DB_PREFIX."log` WHERE {$sql_where_server} `datetime` < :latest_date", + array('latest_date' => $retention_date->format('Y-m-d 00:00:00')), + false + ); + return true; + } +} \ No newline at end of file diff --git a/src/psm/Service/Archiver.class.php b/src/psm/Util/Server/Archiver/UptimeArchiver.class.php similarity index 80% rename from src/psm/Service/Archiver.class.php rename to src/psm/Util/Server/Archiver/UptimeArchiver.class.php index cd283581..e40e50ef 100644 --- a/src/psm/Service/Archiver.class.php +++ b/src/psm/Util/Server/Archiver/UptimeArchiver.class.php @@ -19,6 +19,7 @@ * * @package phpservermon * @author Pepijn Over + * Jérôme Cabanis * @copyright Copyright (c) 2008-2014 Pepijn Over * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 * @version Release: @package_version@ @@ -36,10 +37,10 @@ * * @see \psm\Util\Updater\Autorun */ -namespace psm\Service; +namespace psm\Util\Server\Archiver; use psm\Service\Database; -class Archiver { +class UptimeArchiver implements ArchiverInterface { /** * Database service @@ -56,29 +57,23 @@ class Archiver { * * Archiving means calculating averages per day, and storing 1 single * history row for each day for each server. + * + * @param int $server_id */ - public function archiveStatus() { + public function archive($server_id = null) { $latest_date = new \DateTime('-1 week 0:0:0'); - $timestamp = $latest_date->getTimestamp(); - - // Check if archiving is necessary - $last_archive = psm_get_conf('last_archive_time', 0); - if($timestamp <= $last_archive) { - return false; - } - - psm_update_conf('last_archive_time', $timestamp); // Lock tables to prevent simultaneous archiving (by other sessions or the cron job) $this->db->exec('LOCK TABLES ' . PSM_DB_PREFIX . 'servers_uptime WRITE, ' . PSM_DB_PREFIX . 'servers_history WRITE'); $latest_date_str = $latest_date->format('Y-m-d 00:00:00'); + $sql_where_server = $this->createSQLWhereServer($server_id); + $records = $this->db->execute( "SELECT `server_id`,`date`,`status`,`latency` FROM `" . PSM_DB_PREFIX."servers_uptime` - WHERE `date` < :latest_date - ORDER BY `date` ASC", + WHERE {$sql_where_server} `date` < :latest_date", array('latest_date' => $latest_date_str)); if(!empty($records)) { @@ -106,22 +101,24 @@ class Archiver { // now remove all records from the uptime table $this->db->execute( - "DELETE FROM `".PSM_DB_PREFIX."servers_uptime` WHERE `date` < :latest_date", + "DELETE FROM `".PSM_DB_PREFIX."servers_uptime` WHERE {$sql_where_server} `date` < :latest_date", array('latest_date' => $latest_date_str), false ); } - // Remove older history entries - $latest_date->modify('-1 year'); + $this->db->exec('UNLOCK TABLES'); + + return true; + } + + public function cleanup(\DateTime $retention_date, $server_id = null) { + $sql_where_server = $this->createSQLWhereServer($server_id); $this->db->execute( - "DELETE FROM `".PSM_DB_PREFIX."servers_history` WHERE `date` < :latest_date", - array('latest_date' => $latest_date->format('Y-m-d 00:00:00')), + "DELETE FROM `".PSM_DB_PREFIX."servers_history` WHERE {$sql_where_server} `date` < :latest_date", + array('latest_date' => $retention_date->format('Y-m-d 00:00:00')), false ); - - $this->db->exec('UNLOCK TABLES'); - return true; } @@ -156,4 +153,13 @@ class Archiver { ); return $history; } + + protected function createSQLWhereServer($server_id) { + $sql_where_server = ($server_id !== null) + // this is obviously not the cleanest way to implement this when using paramter binding.. sorry. + ? ' `server_id` = ' . intval($server_id) . ' AND ' + : ''; + + return $sql_where_server; + } } \ No newline at end of file diff --git a/src/psm/Util/Server/HistoryGraph.class.php b/src/psm/Util/Server/HistoryGraph.class.php index 5180d23a..ddc16e41 100644 --- a/src/psm/Util/Server/HistoryGraph.class.php +++ b/src/psm/Util/Server/HistoryGraph.class.php @@ -28,7 +28,6 @@ namespace psm\Util\Server; use psm\Service\Database; -use psm\Service\Archiver; /** * History util, create HTML for server graphs @@ -57,9 +56,9 @@ class HistoryGraph { * @return string */ public function createHTML($server_id) { - // Archive all records older than 1 week, if needed - $archiver = new Archiver($this->db); - $archiver->archiveStatus(); + // Archive all records for this server to make sure we have up-to-date stats + $archive = new ArchiveManager($this->db); + $archive->archive($server_id); $now = new \DateTime(); $last_week = new \DateTime('-1 week 0:0:0'); diff --git a/src/psm/Util/Updater/Autorun.class.php b/src/psm/Util/Updater/Autorun.class.php index 53c97494..70e3337e 100644 --- a/src/psm/Util/Updater/Autorun.class.php +++ b/src/psm/Util/Updater/Autorun.class.php @@ -29,7 +29,6 @@ namespace psm\Util\Updater; use psm\Service\Database; use psm\Service\User; -use psm\Service\Archiver; /** * Run an update on all servers. @@ -87,9 +86,10 @@ class Autorun { $notifier->notify($server['server_id'], $status_old, $status_new); } - // clean-up time!! archive all records older than 1 week - $archiver = new Archiver($this->db); - $archiver->archiveStatus(); + // clean-up time!! archive all records + $archive = new \psm\Util\Server\ArchiveManager($this->db); + $archive->archive(); + $archive->cleanup(); } /** diff --git a/src/templates/default/module/config/config.tpl.html b/src/templates/default/module/config/config.tpl.html index 8749ce96..88b223b8 100644 --- a/src/templates/default/module/config/config.tpl.html +++ b/src/templates/default/module/config/config.tpl.html @@ -27,8 +27,7 @@
-  {{ label_seconds }} -

{{ label_auto_refresh_servers|raw }}

+  {{ label_seconds }}
@@ -50,10 +49,15 @@ {{ label_settings_log }}
- -

{{ label_log_status_description|raw }}

+
+
+ +
+  {{ label_log_retention_days }} +
+