PMCORE-1335 ProcessMaker core should be use the native Laravel log mechanism.

This commit is contained in:
Roly Rudy Gutierrez Pinto
2020-08-10 17:11:55 -04:00
parent 061d4531f1
commit c865e65658
45 changed files with 731 additions and 1535 deletions

View File

@@ -1,5 +1,6 @@
<?php
use Illuminate\Support\Facades\Log;
use ProcessMaker\Core\System;
use ProcessMaker\Util\DateTime;
@@ -2667,87 +2668,33 @@ class Bootstrap
}
/**
* Stores a message in the log file, if the file size exceeds
*
* @param string $channel The logging channel
* @param int $level The logging level
* @param string $message The log message
* @param array $context The log context
* @param string $workspace @todo we need to remove this parameter this is not necessary
* @param string $file name file
* @param boolean $readLoggingLevel
*
* @return void
*/
public static function registerMonolog(
$channel,
$level,
$message,
$context,
$workspace = '',
$file = 'processmaker.log',
$readLoggingLevel = true
)
{
$registerLogger = MonologProvider::getSingleton($channel, $file, $readLoggingLevel);
$registerLogger->addLog($level, $message, $context);
}
/**
* Get the default information from the context
*
* Returns an array containing the values of the current execution context.
*
* @global object $RBAC
* @param array $extraParams
* @return array
*
* @see AdditionalTables->populateReportTable
* @see AppAssignSelfServiceValueGroup->createRow
* @see Bootstrap->registerMonologPhpUploadExecution()
* @see Cases->loadDataSendEmail()
* @see Cases->removeCase()
* @see Cases->reportTableDeleteRecord()
* @see Derivation->derivate
* @see G->logTriggerExecution()
* @see LdapAdvanced->VerifyLogin
* @see ldapadvancedClassCron->executeCron
* @see PmDynaform->__construct
* @see pmTablesProxy->genDataReport
* @see Processes->createFiles
* @see ProcessMaker\AuditLog\AuditLog->register
* @see ProcessMaker\Util\ParseSoapVariableName->buildVariableName
* @see RBAC->checkAutomaticRegister()
* @see workflow/engine/classes/class.pmFunctions.php::executeQuery
* @link https://wiki.processmaker.com/3.3/Actions_by_Email
* @link https://wiki.processmaker.com/3.2/ProcessMaker_Functions
* @link https://wiki.processmaker.com/3.1/Report_Tables
* @link https://wiki.processmaker.com/3.2/Cases/Running_Cases
* @link https://wiki.processmaker.com/3.3/login
* @link https://wiki.processmaker.com/3.2/Executing_cron.php
* @link https://wiki.processmaker.com/3.2/HTML5_Responsive_DynaForm_Designer
* @link https://wiki.processmaker.com/3.2/Audit_Log
* @link https://wiki.processmaker.com/3.0/ProcessMaker_WSDL_Web_Services
*/
public static function getDefaultContextLog()
public static function context(array $extraParams = []): array
{
$info = [
$context = [
'ip' => G::getIpAddress(),
'workspace' => !empty(config('system.workspace')) ? config('system.workspace') : 'Undefined Workspace',
'workspace' => config('system.workspace', 'Undefined Workspace'),
'timeZone' => DateTime::convertUtcToTimeZone(date('Y-m-d H:m:s')),
'usrUid' => G::LoadTranslation('UID_UNDEFINED_USER')
];
$context = array_merge($context, $extraParams);
//get session user
global $RBAC;
if (!empty($RBAC) && !empty($RBAC->aUserInfo['USER_INFO']) && !empty($RBAC->aUserInfo['USER_INFO']['USR_UID'])) {
$info['usrUid'] = $RBAC->aUserInfo['USER_INFO']['USR_UID'];
return $info;
$context['usrUid'] = $RBAC->aUserInfo['USER_INFO']['USR_UID'];
return $context;
}
//if default session exists
if (!empty($_SESSION['USER_LOGGED'])) {
$info['usrUid'] = $_SESSION['USER_LOGGED'];
return $info;
$context['usrUid'] = $_SESSION['USER_LOGGED'];
return $context;
}
return $info;
return $context;
}
/**
@@ -2764,27 +2711,6 @@ class Bootstrap
}
/**
* Record the action of executing a php file or attempting to upload a php
* file in server.
* @param type $channel
* @param type $level
* @param type $message
* @param type $fileName
*/
public static function registerMonologPhpUploadExecution($channel, $level, $message, $fileName)
{
$context = \Bootstrap::getDefaultContextLog();
$context['action'] = $channel;
$context['filename'] = $fileName;
if (defined("SYS_CURRENT_URI") && defined("SYS_CURRENT_PARMS")) {
$context['url'] = SYS_CURRENT_URI . '?' . SYS_CURRENT_PARMS;
}
$context['usrUid'] = isset($_SESSION['USER_LOGGED']) ? $_SESSION['USER_LOGGED'] : '';
$sysSys = !empty(config("system.workspace")) ? config("system.workspace") : "Undefined";
\Bootstrap::registerMonolog($channel, $level, $message, $context, $sysSys, 'processmaker.log');
}
/*
* Set the constant to related the Workspaces
*
* @param string $workspace

View File

@@ -2,6 +2,7 @@
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
*
@@ -234,6 +235,7 @@ class DataBaseMaintenance
*/
public function dumpData($table)
{
$sql = "";
try {
$this->outfile = $this->tmpDir . $table . '.dump';
@@ -248,10 +250,12 @@ class DataBaseMaintenance
return true;
} catch (QueryException $exception) {
$ws = (!empty(config('system.workspace'))) ? config('system.workspace') : 'Undefined Workspace';
Bootstrap::registerMonolog('MysqlCron', 400, $exception->getMessage(), ['sql' => $sql], $ws, 'processmaker.log');
$varRes = $exception->getMessage() . "\n";
G::outRes($varRes);
$message = $exception->getMessage();
$context = [
'sql' => $sql
];
Log::channel(':MysqlCron')->error($message, Bootstrap::context($context));
G::outRes($message . "\n");
return false;
}
}
@@ -265,18 +269,19 @@ class DataBaseMaintenance
*/
public function restoreData($backupFile)
{
$sql = "";
try {
$tableName = str_replace('.dump', '', basename($backupFile));
$sql = "LOAD DATA INFILE '$backupFile' INTO TABLE $tableName FIELDS TERMINATED BY '\t|\t' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\t\t\r\r\n'";
DB::connection($this->getConnect())->raw($sql);
return true;
} catch (QueryException $exception) {
$ws = (!empty(config("system.workspace"))) ? config("system.workspace") : "Wokspace Undefined";
Bootstrap::registerMonolog('MysqlCron', 400, $exception->getMessage(), ['sql' => $sql], $ws, 'processmaker.log');
$varRes = $exception->getMessage() . "\n";
G::outRes($varRes);
$message = $exception->getMessage();
$context = [
'sql' => $sql
];
Log::channel(':MysqlCron')->error($message, Bootstrap::context($context));
G::outRes($message . "\n");
return false;
}
}

View File

@@ -1,5 +1,6 @@
<?php
use Illuminate\Support\Facades\Log;
use ProcessMaker\Core\System;
use ProcessMaker\AuditLog\AuditLog;
use ProcessMaker\Plugins\PluginRegistry;
@@ -1180,12 +1181,21 @@ class G
if ($download) {
G::sendHeaders($filename, 'text/plain', $download, $downloadFileName);
} else {
if (\Bootstrap::getDisablePhpUploadExecution() === 0) {
\Bootstrap::registerMonologPhpUploadExecution('phpExecution', 200, 'Php Execution', $filename);
if (Bootstrap::getDisablePhpUploadExecution() === 0) {
$message = 'Php Execution';
$context = [
'filename' => $filename,
'url' => $_SERVER["REQUEST_URI"] ?? ''
];
Log::channel(':phpExecution')->info($message, Bootstrap::context($context));
require_once($filename);
} else {
$message = G::LoadTranslation('ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpExecution', 550, $message, $filename);
$context = [
'filename' => $filename,
'url' => $_SERVER["REQUEST_URI"] ?? ''
];
Log::channel(':phpExecution')->alert($message, Bootstrap::context($context));
echo $message;
}
return;
@@ -5699,10 +5709,14 @@ class G
}
$fullName = empty($_SESSION['USR_FULLNAME']) ? $fullName : $_SESSION['USR_FULLNAME'];
$auditLog = new AuditLog();
$auditLog->setUserLogged($userUid);
$auditLog->setUserFullname($fullName);
$auditLog->register($actionToLog, $valueToLog);
$message = $actionToLog;
$context = [
'usrUid' => $userUid,
'usrName' => $fullName,
'action' => $actionToLog,
'description' => $valueToLog
];
Log::channel('audit:' . $actionToLog)->info($message, Bootstrap::context($context));
}
/*----------------------------------********---------------------------------*/
}
@@ -6079,26 +6093,24 @@ class G
public static function logTriggerExecution($data, $error = 'NO-ERROR', $typeError = '', $executionTime = 0)
{
if ((!empty($data['_CODE_']) || $typeError == 'FATAL_ERROR') && empty($data['_DATA_TRIGGER_']['_TRI_LOG_'])) {
$lg = Bootstrap::getDefaultContextLog();
$lg['triTitle'] = isset($data['_DATA_TRIGGER_']['TRI_TITLE']) ? $data['_DATA_TRIGGER_']['TRI_TITLE'] : '';
$lg['triUid'] = isset($data['_DATA_TRIGGER_']['TRI_UID']) ? $data['_DATA_TRIGGER_']['TRI_UID'] : '';
$lg['triCode'] = isset($data['_DATA_TRIGGER_']['TRI_WEBBOT']) ? $data['_DATA_TRIGGER_']['TRI_WEBBOT'] : '';
$lg['triExecutionTime'] = $executionTime;
$lg['triMessageError'] = $error;
$lg['appUid'] = isset($data['APPLICATION']) ? $data['APPLICATION'] : '';
$lg['proUid'] = isset($data['PROCESS']) ? $data['PROCESS'] : '';
$lg['tasUid'] = isset($data['TASK']) ? $data['TASK'] : '';
$lg['usrUid'] = isset($data['USER_LOGGED']) ? $data['USER_LOGGED'] : '';
Bootstrap::registerMonolog(
(empty($error)) ? 'TriggerExecution' : 'TriggerExecutionError',
(empty($error)) ? 200 : 400,
(empty($error)) ? 'Trigger Execution' : 'Trigger Execution Error',
$lg,
$lg['workspace'],
'processmaker.log'
);
$context = [
'triTitle' => isset($data['_DATA_TRIGGER_']['TRI_TITLE']) ? $data['_DATA_TRIGGER_']['TRI_TITLE'] : '',
'triUid' => isset($data['_DATA_TRIGGER_']['TRI_UID']) ? $data['_DATA_TRIGGER_']['TRI_UID'] : '',
'triCode' => isset($data['_DATA_TRIGGER_']['TRI_WEBBOT']) ? $data['_DATA_TRIGGER_']['TRI_WEBBOT'] : '',
'triExecutionTime' => $executionTime,
'triMessageError' => $error,
'appUid' => isset($data['APPLICATION']) ? $data['APPLICATION'] : '',
'proUid' => isset($data['PROCESS']) ? $data['PROCESS'] : '',
'tasUid' => isset($data['TASK']) ? $data['TASK'] : '',
'usrUid' => isset($data['USER_LOGGED']) ? $data['USER_LOGGED'] : '',
];
if (empty($error)) {
$message = 'Trigger Execution';
Log::channel(':TriggerExecution')->info($message, Bootstrap::context($context));
} else {
$message = 'Trigger Execution Error';
Log::channel(':TriggerExecutionError')->error($message, Bootstrap::context($context));
}
$_SESSION['_DATA_TRIGGER_']['_TRI_LOG_'] = true;
}
}

View File

@@ -1,500 +0,0 @@
<?php
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Monolog\Processor\IntrospectionProcessor;
use ProcessMaker\Core\System;
class MonologProvider
{
/**
* @var MonologProvider
*/
private static $instance = null;
/**
* @var LineFormatter
*/
private $formatter;
/**
* @var RotatingFileHandler
*/
private $streamRoutating;
/**
* @var Logger
*/
private $registerLogger;
//the default format "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
private $output = "<%level%> %datetime% %channel% %level_name%: %message% %context%\n";
private $dateFormat = 'M d H:i:s';
/**
* The maximal amount of files to keep (0 means unlimited)
* @var int
*/
private $maxFilesToKeep;
/**
* @var int level debug
*/
private $levelDebug;
/**
* Whether the messages that are handled can bubble up the stack or not
* @var boolean
*/
private $bubble = true;
/**
* @var int file permissions
*/
private $filePermission;
/**
* @var string path file
*/
private $pathFile;
/**
* Logging levels from loo protocol defined in RFC 5424
*
* @var array $levels Logging levels
*/
protected static $levels = [
'DEBUG' => 100,
'INFO' => 200,
'NOTICE' => 250,
'WARNING' => 300,
'ERROR' => 400,
'CRITICAL' => 500,
'ALERT' => 550,
'EMERGENCY' => 600
];
/**
* Construct of the class
*
* @param string $channel
* @param string $fileLog
* @param boolean $readLoggingLevel
*
*/
public function __construct($channel, $fileLog, $readLoggingLevel = true)
{
//Set path where the file will be saved
$pathFile = $this->definePathFile();
$this->setPathFile($pathFile);
//Set maximal amount of files to keep (0 means unlimited)
$maxFilesToRotation = $this->defineMaxFiles();
$this->setMaxFiles($maxFilesToRotation);
/**
* The permissions are normally set at the operating system level, and it's the IT administrator responsibility to set the correct file permissions
* It's not recommendable define in the env.ini configuration
*/
$permissionFile = 0666;
$permissionFile = is_int($permissionFile) ? decoct($permissionFile) : $permissionFile;
$this->setFilePermission($permissionFile);
$this->setFormatter();
//Set the config: channel, fileLog and levelDebug that will be saved
$this->setConfig($channel, $fileLog, $readLoggingLevel);
$this->testWriteLog($channel, $fileLog, [
$pathFile
]);
}
/**
* This function defines the debug level
* We will to check if the logging_level exist in the env.ini
*
* @param boolean $readLoggingLevel
*
* @return string
*/
private function defineLevelDebug($readLoggingLevel = true)
{
$levelDebug = 'INFO';
if ($readLoggingLevel) {
//In the parse_ini_file the word NONE are considered FALSE
if (defined('LOGGING_LEVEL')) {
$levelDebug = !empty(LOGGING_LEVEL) ? LOGGING_LEVEL : 'NONE';
} else {
//Getting configuration from env.ini
$sysConf = System::getSystemConfiguration();
$levelDebug = !empty($sysConf['logging_level']) ? $sysConf['logging_level'] : 'NONE';
}
}
return $levelDebug;
}
/**
* This function defines the path file
* We will to check if the logs_location exist in the env.ini
*
* @return string
*/
private function definePathFile()
{
$path = PATH_DATA . 'sites' . PATH_SEP . config('system.workspace') . PATH_SEP . 'log' . PATH_SEP;
if (defined('LOGS_LOCATION')) {
$path = !empty(LOGS_LOCATION) ? LOGS_LOCATION : $path;
} else {
$sysConf = System::getSystemConfiguration();
$path = !empty($sysConf['logs_location']) ? $sysConf['logs_location'] : $path;
}
return $path;
}
/**
* This function defines the max number of files
* We will to check if the logs_max_files exist in the env.ini
*
* @return integer
*/
private function defineMaxFiles()
{
$maxFilesToRotation = 60;
if (defined('LOGS_MAX_FILES')) {
$maxFilesToRotation = !empty(LOGS_MAX_FILES) ? LOGS_MAX_FILES : $maxFilesToRotation;
} else {
$sysConf = System::getSystemConfiguration();
$maxFilesToRotation = !empty($sysConf['logs_max_files']) ? $sysConf['logs_max_files'] : $maxFilesToRotation;
}
return $maxFilesToRotation;
}
/**
* Test write log
*
* @param string $channel
* @param string $fileLog
* @param array $paths
*/
private function testWriteLog($channel, $fileLog, $paths)
{
$fileInfo = pathinfo($fileLog);
$timedFilename = str_replace(
['{filename}', '{date}'],
[$fileInfo['filename'], date('Y-m-d')],
'{filename}-{date}'
);
if (!empty($fileInfo['extension'])) {
$timedFilename .= '.' . $fileInfo['extension'];
}
if (!file_exists($this->getPathFile() . $timedFilename)) {
try {
$level = $this->getLevelDebug();
if (!empty($level)) {
$this->getLogger()->addRecord($level, 'Start writing the log file');
}
} catch (UnexpectedValueException $exception) {
//In case that the file can not be written, it will be written to the standard log file.
error_log($exception->getMessage());
if ($paths) {
$path = array_shift($paths);
$this->setPathFile($path);
$this->setConfig($channel, $fileLog);
$this->testWriteLog($channel, $fileLog, $paths);
}
} catch (Exception $exception) {
//In case of an exception, it will be written to the standard log file.
error_log($exception->getMessage());
}
}
}
/**
* Return Formatter
*
* @return LineFormatter
*/
public function getFormatter()
{
return $this->formatter;
}
/**
* Set LineFormatter $formatter
*/
public function setFormatter()
{
$this->formatter = new LineFormatter($this->getOutput(), $this->getDateFormat());
}
/**
* @return RotatingFileHandler
*/
public function getStream()
{
return $this->streamRoutating;
}
/**
* @param string File name
*/
public function setStream($fileLog)
{
// ONLY initialize a new RotatingFileHandler if the fileLog is DIFFERENT.
//Set Routating Handler
$this->streamRoutating = new RotatingFileHandler($this->getPathFile() . $fileLog,
$this->getMaxFiles(),
$this->getLevelDebug(),
$this->isBubble(),
$this->getFilePermissionOctDec());
$this->streamRoutating->setFormatter($this->getFormatter());
}
/**
* @return Logger
*/
public function getLogger()
{
return $this->registerLogger;
}
/**
* @param string $channel The logging channel
*/
public function setLogger($channel)
{
//Create the channel and register the Logger with StreamRoutating
$this->registerLogger = new Logger($channel);
$this->registerLogger->pushProcessor(new IntrospectionProcessor());
$this->registerLogger->pushHandler($this->getStream());
}
/**
* Return format output
* @return string
*/
public function getOutput()
{
return $this->output;
}
/**
* Set format output
*
* @param string $output
*/
public function setOutput($output)
{
$this->output = $output;
}
/**
* Return date format
* @return string
*/
public function getDateFormat()
{
return $this->dateFormat;
}
/**
* Set date format
* @param string $dateFormat
*/
public function setDateFormat($dateFormat)
{
$this->dateFormat = $dateFormat;
}
/**
* Return is can bubble up the stack or not.
*
* @return boolean
*/
public function isBubble()
{
return $this->bubble;
}
/**
* Set bubble
*
* @param boolean $bubble
*/
public function setBubble($bubble)
{
$this->bubble = $bubble;
}
/**
* Return level debug
*
* @return int
*/
public function getLevelDebug()
{
return $this->levelDebug;
}
/**
* Return max files
*
* @return int
*/
public function getMaxFiles()
{
return $this->maxFilesToKeep;
}
/**
* Set max files
*
* @param int $maxFilesToKeep
*/
public function setMaxFiles($maxFilesToKeep)
{
$this->maxFilesToKeep = $maxFilesToKeep;
}
/**
* Return permissions of file
*
* @return int
*/
public function getFilePermission()
{
return $this->filePermission;
}
/**
* Returns the decimal equivalent of the octal number represented by the octal_string argument.
*
* @return int
*/
public function getFilePermissionOctDec()
{
return octdec($this->filePermission);
}
/**
* Set file permissions
*
* @param int $filePermission
*/
public function setFilePermission($filePermission)
{
$this->filePermission = $filePermission;
}
/**
* Returns the path where the file will be saved
*
* @return string
*/
public function getPathFile()
{
return $this->pathFile;
}
/**
* Set path
*
* @param string $pathFile
*/
public function setPathFile($pathFile)
{
$pathSep = '/';
if (strpos($pathFile, '\\') !== false) {
$pathSep = '\\';
}
if (substr($pathFile, -1, strlen($pathSep)) !== $pathSep) {
$pathFile .= $pathSep;
}
$this->pathFile = $pathFile;
}
/**
* Set level debug by string
*
* @param string $levelDebug
*/
public function setLevelDebug($levelDebug)
{
//If is a valid, we will to define the level
if (isset(static::$levels[$levelDebug])) {
$level = static::$levels[$levelDebug];
$this->levelDebug = $level;
} else {
//If is other value like NONE will set with empty level
$this->levelDebug = '';
}
}
/**
* To get singleton instance
*
* @access public
*
* @param string $channel
* @param string $fileLog
* @param boolean $readLoggingLevel
*
* @return object
*/
public static function getSingleton($channel, $fileLog, $readLoggingLevel = true)
{
if (self::$instance === null) {
self::$instance = new MonologProvider($channel, $fileLog, $readLoggingLevel);
self::$instance->setConfig($channel, $fileLog, $readLoggingLevel);
}
return self::$instance;
}
/**
* Set channel and fileLog
*
* @access public
*
* @param string $channel The logging channel
* @param string $fileLog name file
* @param boolean $readLoggingLevel
*/
public function setConfig($channel, $fileLog, $readLoggingLevel = true)
{
$this->setStream($fileLog);
$this->setLogger($channel);
$levelDebug = $this->defineLevelDebug($readLoggingLevel);
$this->setLevelDebug($levelDebug);
}
/**
* Register log if the level correspond to the logging_level defined
* In other way return false if the log was turn off or the actions does not logged
*
* @access public
*
* @param int $level The logging level
* @param string $message The log message
* @param array $context The log context
*
* @return bool
*/
public function addLog($level, $message, $context)
{
if (!empty($this->getLevelDebug()) && $level >= $this->getLevelDebug()) {
return $this->getLogger()->addRecord($level, $message, $context);
} else {
return false;
}
}
/**
* Set the instance property
*/
static function setInstance($instance)
{
self::$instance = $instance;
}
}

View File

@@ -1,27 +1,29 @@
<?php
use Illuminate\Support\Facades\Log;
/**
* HttpProxyController
*
* @author Erik Amaru Ortiz <erik@colosa.com, aortiz.erik@gmail.com>
* @package gulliver.system
* @access public
*/
class PMException extends Exception
{
public function __construct ($message, $code = 0, $previous = null)
public function __construct($message, $code = 0, $previous = null)
{
parent::__construct( $message, 1 );
parent::__construct($message, 1);
}
public function __toString ()
public function __toString()
{
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public static function registerErrorLog($error, $token){
$ws = (!empty(config("system.workspace")))? config("system.workspace") : "Undefined Workspace";
Bootstrap::registerMonolog('ExceptionCron', 400, $error->getMessage(), array('token'=>$token), $ws, 'processmaker.log');
public static function registerErrorLog($error, $token)
{
$message = $error->getMessage();
$context = [
'token' => $token
];
Log::channel(':ExceptionCron')->error($message, Bootstrap::context($context));
}
}

View File

@@ -1,5 +1,6 @@
<?php
use Illuminate\Support\Facades\Log;
use ProcessMaker\Exception\RBACException;
class RBAC
@@ -917,10 +918,12 @@ class RBAC
return $res;
}
} catch (Exception $e) {
$context = Bootstrap::getDefaultContextLog();
$context["action"] = "ldapSynchronize";
$context["authSource"] = $row;
Bootstrap::registerMonolog("ldapSynchronize", 400, $e->getMessage(), $context, $context["workspace"], "processmaker.log");
$message = $e->getMessage();
$context = [
'action' => 'ldapSynchronize',
'authSource' => $row
];
Log::channel(':ldapSynchronize')->error($message, Bootstrap::context($context));
}
}