306 lines
6.9 KiB
PHP
306 lines
6.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
* This file is part of the Froxlor project.
|
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you can also view it online at
|
|
* https://files.froxlor.org/misc/COPYING.txt
|
|
*
|
|
* @copyright the authors
|
|
* @author Froxlor team <team@froxlor.org>
|
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
|
*/
|
|
|
|
namespace Froxlor;
|
|
|
|
use Froxlor\System\MysqlHandler;
|
|
use Monolog\Handler\StreamHandler;
|
|
use Monolog\Handler\SyslogHandler;
|
|
use Monolog\Logger;
|
|
|
|
/**
|
|
* Class FroxlorLogger
|
|
*/
|
|
class FroxlorLogger
|
|
{
|
|
|
|
const USR_ACTION = '10';
|
|
const RES_ACTION = '20';
|
|
const ADM_ACTION = '30';
|
|
const CRON_ACTION = '40';
|
|
const LOGIN_ACTION = '50';
|
|
const LOG_ERROR = '99';
|
|
/**
|
|
* current \Monolog\Logger object
|
|
*
|
|
* @var ?Logger
|
|
*/
|
|
private static ?Logger $ml = null;
|
|
/**
|
|
* LogTypes Array
|
|
*
|
|
* @var ?array
|
|
*/
|
|
private static ?array $logtypes = null;
|
|
/**
|
|
* whether to output log-messages to STDOUT (cron)
|
|
*
|
|
* @var bool
|
|
*/
|
|
private static bool $crondebug_flag = false;
|
|
/**
|
|
* user info of logged-in user
|
|
*
|
|
* @var array
|
|
*/
|
|
private static array $userinfo = [];
|
|
/**
|
|
* whether the logger object has already been initialized
|
|
*
|
|
* @var bool
|
|
*/
|
|
private static bool $is_initialized = false;
|
|
|
|
/**
|
|
* Class constructor.
|
|
*
|
|
* @param array $userinfo
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
protected function __construct(array $userinfo = [])
|
|
{
|
|
$this->initMonolog();
|
|
self::$userinfo = $userinfo;
|
|
self::$logtypes = [];
|
|
|
|
if ((Settings::Get('logger.logtypes') == null || Settings::Get('logger.logtypes') == '') && (Settings::Get('logger.enabled') !== null && Settings::Get('logger.enabled'))) {
|
|
self::$logtypes[0] = 'syslog';
|
|
self::$logtypes[1] = 'mysql';
|
|
} else {
|
|
if (Settings::Get('logger.logtypes') !== null && Settings::Get('logger.logtypes') != '') {
|
|
self::$logtypes = explode(',', Settings::Get('logger.logtypes'));
|
|
} else {
|
|
self::$logtypes = null;
|
|
}
|
|
}
|
|
|
|
if (self::$is_initialized == false) {
|
|
foreach (self::$logtypes as $logger) {
|
|
switch ($logger) {
|
|
case 'syslog':
|
|
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
|
break;
|
|
case 'file':
|
|
$setings_logfile = Settings::Get('logger.logfile');
|
|
if (empty($setings_logfile)) {
|
|
Settings::Set('logger.logfile', 'froxlor.log');
|
|
}
|
|
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
|
|
// is_writable needs an existing file to check if it's actually writable
|
|
if (!@touch($logger_logfile) || !is_writable($logger_logfile)) {
|
|
// not writable in our own directory? Skip
|
|
break;
|
|
}
|
|
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
|
break;
|
|
case 'mysql':
|
|
self::$ml->pushHandler(new MysqlHandler(Logger::DEBUG));
|
|
break;
|
|
}
|
|
}
|
|
self::$is_initialized = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* initiate monolog object
|
|
*
|
|
* @return Logger
|
|
*/
|
|
private function initMonolog()
|
|
{
|
|
if (empty(self::$ml)) {
|
|
// get Theme object
|
|
self::$ml = new Logger('froxlor');
|
|
}
|
|
return self::$ml;
|
|
}
|
|
|
|
/**
|
|
* return FroxlorLogger instance
|
|
*
|
|
* @param array $userinfo
|
|
*
|
|
* @return FroxlorLogger
|
|
* @throws \Exception
|
|
*/
|
|
public static function getInstanceOf(array $userinfo = [])
|
|
{
|
|
if (empty($userinfo)) {
|
|
$userinfo = [
|
|
'loginname' => 'system'
|
|
];
|
|
}
|
|
return new FroxlorLogger($userinfo);
|
|
}
|
|
|
|
/**
|
|
* logs a given text to all enabled logger-facilities
|
|
*
|
|
* @param int $action
|
|
* @param int $type
|
|
* @param ?string $text
|
|
*/
|
|
public function logAction($action = FroxlorLogger::USR_ACTION, int $type = LOG_NOTICE, string $text = null)
|
|
{
|
|
// not logging normal stuff if not set to "paranoid" logging
|
|
if (!self::$crondebug_flag && Settings::Get('logger.severity') == '1' && $type > LOG_NOTICE) {
|
|
return;
|
|
}
|
|
|
|
if (empty(self::$ml)) {
|
|
$this->initMonolog();
|
|
}
|
|
|
|
// clean log-text
|
|
$text = preg_replace("/[^\w @#\"':.,()\[\]+\-_\/\\\!]/i", "_", $text);
|
|
|
|
if (self::$crondebug_flag || ($action == FroxlorLogger::CRON_ACTION && $type <= LOG_WARNING)) {
|
|
echo "[" . $this->getLogLevelDesc($type) . "] " . $text . PHP_EOL;
|
|
}
|
|
|
|
// warnings, errors and critical messages WILL be logged
|
|
if (Settings::Get('logger.log_cron') == '0' && $action == FroxlorLogger::CRON_ACTION && $type > LOG_WARNING) {
|
|
return;
|
|
}
|
|
|
|
$logExtra = [
|
|
'source' => $this->getActionTypeDesc($action),
|
|
'action' => $action,
|
|
'user' => self::$userinfo['loginname']
|
|
];
|
|
|
|
switch ($type) {
|
|
case LOG_DEBUG:
|
|
self::$ml->addDebug($text, $logExtra);
|
|
break;
|
|
case LOG_INFO:
|
|
self::$ml->addInfo($text, $logExtra);
|
|
break;
|
|
case LOG_NOTICE:
|
|
self::$ml->addNotice($text, $logExtra);
|
|
break;
|
|
case LOG_WARNING:
|
|
self::$ml->addWarning($text, $logExtra);
|
|
break;
|
|
case LOG_ERR:
|
|
self::$ml->addError($text, $logExtra);
|
|
break;
|
|
default:
|
|
self::$ml->addDebug($text, $logExtra);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param int $type
|
|
* @return string
|
|
*/
|
|
public function getLogLevelDesc(int $type): string
|
|
{
|
|
switch ($type) {
|
|
case LOG_INFO:
|
|
$_type = 'information';
|
|
break;
|
|
case LOG_NOTICE:
|
|
$_type = 'notice';
|
|
break;
|
|
case LOG_WARNING:
|
|
$_type = 'warning';
|
|
break;
|
|
case LOG_ERR:
|
|
$_type = 'error';
|
|
break;
|
|
case LOG_CRIT:
|
|
$_type = 'critical';
|
|
break;
|
|
case LOG_DEBUG:
|
|
$_type = 'debug';
|
|
break;
|
|
default:
|
|
$_type = 'unknown';
|
|
break;
|
|
}
|
|
return $_type;
|
|
}
|
|
|
|
/**
|
|
* @param $action
|
|
* @return string
|
|
*/
|
|
private function getActionTypeDesc($action): string
|
|
{
|
|
switch ($action) {
|
|
case FroxlorLogger::USR_ACTION:
|
|
$_action = 'user';
|
|
break;
|
|
case FroxlorLogger::ADM_ACTION:
|
|
$_action = 'admin';
|
|
break;
|
|
case FroxlorLogger::RES_ACTION:
|
|
$_action = 'reseller';
|
|
break;
|
|
case FroxlorLogger::CRON_ACTION:
|
|
$_action = 'cron';
|
|
break;
|
|
case FroxlorLogger::LOGIN_ACTION:
|
|
$_action = 'login';
|
|
break;
|
|
default:
|
|
$_action = 'unknown';
|
|
break;
|
|
}
|
|
return $_action;
|
|
}
|
|
|
|
/**
|
|
* Set whether to log cron-runs
|
|
*
|
|
* @param int $cronlog
|
|
*
|
|
* @return int
|
|
*/
|
|
public function setCronLog(int $cronlog = 0): int
|
|
{
|
|
if ($cronlog < 0 || $cronlog > 2) {
|
|
$cronlog = 0;
|
|
}
|
|
Settings::Set('logger.log_cron', $cronlog);
|
|
return $cronlog;
|
|
}
|
|
|
|
/**
|
|
* setter for crondebug-flag
|
|
*
|
|
* @param bool $flag
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setCronDebugFlag(bool $flag = false)
|
|
{
|
|
self::$crondebug_flag = $flag;
|
|
}
|
|
}
|