Merge pull request #101 from Combodo/feature/faf_log_modularity

Feature/faf log modularity
This commit is contained in:
odain-cbd
2019-12-12 14:44:02 +01:00
committed by GitHub
3 changed files with 323 additions and 29 deletions

View File

@@ -99,6 +99,14 @@ class Config
* @since 2.7.0 export_pdf_font param
*/
protected $m_aSettings = array(
'log_level_min' => array(
'type' => 'array',
'description' => 'Optional min log level per channel',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'app_env_label' => array(
'type' => 'string',
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',

View File

@@ -199,28 +199,36 @@ class FileLog
}
}
public function Error($sText)
public function Error($sText, $sChannel = '', $aContext = array())
{
$this->Write('Error | '.$sText);
$this->Write($sText, __FUNCTION__, $sChannel, $aContext);
}
public function Warning($sText)
public function Warning($sText, $sChannel = '', $aContext = array())
{
$this->Write('Warning | '.$sText);
$this->Write($sText, __FUNCTION__, $sChannel, $aContext);
}
public function Info($sText)
public function Info($sText, $sChannel = '', $aContext = array())
{
$this->Write('Info | '.$sText);
$this->Write($sText, __FUNCTION__, $sChannel, $aContext);
}
public function Ok($sText)
public function Ok($sText, $sChannel = '', $aContext = array())
{
$this->Write('Ok | '.$sText);
$this->Write($sText, __FUNCTION__, $sChannel, $aContext);
}
protected function Write($sText)
public function Debug($sText, $sChannel = '', $aContext = array())
{
$this->Write($sText, __FUNCTION__, $sChannel, $aContext);
}
protected function Write($sText, $sLevel = '', $sChannel = '', $aContext = array())
{
$sTextPrefix = empty($sLevel) ? '' : (str_pad($sLevel, 7).' | ');
$sTextSuffix = empty($sChannel) ? '' : " | $sChannel";
$sText = "{$sTextPrefix}{$sText}{$sTextSuffix}";
$sLogFilePath = $this->oFileNameBuilder->GetLogFilePath();
if (empty($sLogFilePath))
@@ -233,6 +241,15 @@ class FileLog
{
flock($hLogFile, LOCK_EX);
$sDate = date('Y-m-d H:i:s');
if (empty($aContext))
{
fwrite($hLogFile, "$sDate | $sText\n");
}
else
{
$sContext = var_export($aContext, true);
fwrite($hLogFile, "$sDate | $sText\n$sContext\n");
}
fwrite($hLogFile, "$sDate | $sText\n");
fflush($hLogFile);
flock($hLogFile, LOCK_UN);
@@ -243,53 +260,161 @@ class FileLog
abstract class LogAPI
{
const CHANNEL_DEFAULT = '';
const LEVEL_DEBUG = 'Debug';
const LEVEL_OK = 'Ok';
const LEVEL_INFO = 'Info';
const LEVEL_WARNING = 'Warning';
const LEVEL_ERROR = 'Error';
// const LEVEL_CRITICAL = 'Critical';
// const LEVEL_ALERT = 'Alert';
// const LEVEL_EMERGENCY = 'Emergency';
protected static $m_oMockMetaModelConfig = null;
protected static $aLevelsPriority = array(
self::LEVEL_DEBUG => 100,
self::LEVEL_OK => 150,
self::LEVEL_INFO => 200,
self::LEVEL_WARNING => 300,
self::LEVEL_ERROR => 400,
);
public static function Enable($sTargetFile)
{
// m_oFileLog is not defined as a class attribute so that each impl will have its own
static::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
public static function MockStaticObjects($oFileLog, $oMetaModelConfig=null)
{
if (static::$m_oFileLog)
{
static::$m_oFileLog->Error($sText);
}
static::$m_oFileLog = $oFileLog;
static::$m_oMockMetaModelConfig = $oMetaModelConfig;
}
public static function Warning($sText)
public static function Error($sMessage, $sChannel = null, $aContext = array())
{
if (static::$m_oFileLog)
{
static::$m_oFileLog->Warning($sText);
}
static::Log(self::LEVEL_ERROR, $sMessage, $sChannel, $aContext);
}
public static function Info($sText)
public static function Warning($sMessage, $sChannel = null, $aContext = array())
{
if (static::$m_oFileLog)
{
static::$m_oFileLog->Info($sText);
}
static::Log(self::LEVEL_WARNING, $sMessage, $sChannel, $aContext);
}
public static function Ok($sText)
public static function Info($sMessage, $sChannel = null, $aContext = array())
{
if (static::$m_oFileLog)
{
static::$m_oFileLog->Ok($sText);
}
static::Log(self::LEVEL_INFO, $sMessage, $sChannel, $aContext);
}
public static function Ok($sMessage, $sChannel = null, $aContext = array())
{
static::Log(self::LEVEL_OK, $sMessage, $sChannel, $aContext);
}
public static function Debug($sMessage, $sChannel = null, $aContext = array())
{
static::Log(self::LEVEL_DEBUG, $sMessage, $sChannel, $aContext);
}
public static function Log($sLevel, $sMessage, $sChannel = null, $aContext = array())
{
if (! static::$m_oFileLog)
{
return;
}
if (! isset(self::$aLevelsPriority[$sLevel]))
{
IssueLog::Error("invalid log level '{$sLevel}'");
return;
}
if (is_null($sChannel))
{
$sChannel = static::CHANNEL_DEFAULT;
}
$sMinLogLevel = self::GetMinLogLevel($sChannel);
if ($sMinLogLevel === false || $sMinLogLevel === 'false')
{
return;
}
if (is_string($sMinLogLevel))
{
if (! isset(self::$aLevelsPriority[$sMinLogLevel]))
{
throw new Exception("invalid configuration for log_level '{$sMinLogLevel}' is not within the list: ".implode(',', array_keys(self::$aLevelsPriority)));
}
elseif (self::$aLevelsPriority[$sLevel] < self::$aLevelsPriority[$sMinLogLevel])
{
//priority too low regarding the conf, do not log this
return;
}
}
static::$m_oFileLog->$sLevel($sMessage, $sChannel, $aContext);
}
/**
* @param $sChannel
*
* @return mixed|null
*/
private static function GetMinLogLevel($sChannel)
{
$oConfig = (static::$m_oMockMetaModelConfig !== null) ? static::$m_oMockMetaModelConfig : \MetaModel::GetConfig();
if (!$oConfig instanceof Config)
{
return self::LEVEL_OK;
}
$sLogLevelMin = $oConfig->Get('log_level_min');
if (empty($sLogLevelMin))
{
return self::LEVEL_OK;
}
if (!is_array($sLogLevelMin))
{
return $sLogLevelMin;
}
if (isset($sLogLevelMin[$sChannel]))
{
return $sLogLevelMin[$sChannel];
}
if (isset($sLogLevelMin[static::CHANNEL_DEFAULT]))
{
return $sLogLevelMin[$sChannel];
}
return self::LEVEL_OK;
}
}
class SetupLog extends LogAPI
{
const CHANNEL_DEFAULT = 'SetupLog';
protected static $m_oFileLog = null;
}
class IssueLog extends LogAPI
{
const CHANNEL_DEFAULT = 'IssueLog';
protected static $m_oFileLog = null;
}
class ToolsLog extends LogAPI
{
const CHANNEL_DEFAULT = 'ToolsLog';
protected static $m_oFileLog = null;
}

161
test/core/LogAPITest.php Normal file
View File

@@ -0,0 +1,161 @@
<?php
/**
* Created by PhpStorm.
* User: Eric
* Date: 31/08/2018
* Time: 17:03
*/
namespace Combodo\iTop\Test\UnitTest\Core;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class LogAPITest extends ItopTestCase
{
private $mockFileLog;
private $oMetaModelConfig;
protected function setUp()
{
parent::setUp();
$this->mockFileLog = $this->createMock('FileLog');
$this->oMetaModelConfig = $this->createMock('Config');
}
/**
* @dataProvider LogApiProvider
* @test
* @backupGlobals disabled
*/
public function TestLogApi($oConfigObject, $sMessage, $Channel, $sExpectedLevel, $sExpectedMessage, $sExpectedChannel = '')
{
\IssueLog::MockStaticObjects($this->mockFileLog, $oConfigObject);
$this->mockFileLog->expects($this->exactly(1))
->method($sExpectedLevel)
->with($sExpectedMessage, $sExpectedChannel);
\IssueLog::Error($sMessage, $Channel);
}
public function LogApiProvider()
{
return [
[ $this->oMetaModelConfig, "log msg", '' , "Error", "log msg"],
[ $this->oMetaModelConfig, "log msg", 'PoudlardChannel' , "Error", "log msg", 'PoudlardChannel'],
[ array(), "log msg", '' , "Error", "log msg"], // Bruno?
];
}
/**
* @test
* @backupGlobals disabled
*/
public function TestUnknownLevel()
{
$this->mockFileLog->expects($this->exactly(1))
->method("Error")
->with("invalid log level 'TotoLevel'");
\IssueLog::Log('TotoLevel', "log msg");
}
/**
* @dataProvider LogWarningWithASpecificChannelProvider
* @test
* @backupGlobals disabled
*/
public function TestLogWarningWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false)
{
$this->oMetaModelConfig
->method("Get")
->with('log_level_min')
->willReturn($ConfigReturnedObject);
\IssueLog::MockStaticObjects($this->mockFileLog, $this->oMetaModelConfig);
$this->mockFileLog->expects($this->exactly($expectedCallNb))
->method($sExpectedLevel)
->with("log msg", "GaBuZoMeuChannel");
try{
\IssueLog::Warning("log msg", "GaBuZoMeuChannel");
if ($bExceptionRaised)
{
$this->fail("raised should have been raised");
}
}
catch(\Exception $e)
{
if (!$bExceptionRaised)
{
$this->fail("raised should NOT have been raised");
}
}
}
public function LogWarningWithASpecificChannelProvider()
{
return [
"empty config" => [ 0, "Ok", ''],
"Default Unknown Level" => [ 0, "Ok", 'TotoLevel', true],
"Info as Default Level" => [ 1 , "Warning", 'Info'],
"Error as Default Level" => [ 0, "Warning", 'Error'],
"Empty array" => [ 0, "Ok", array()],
"Channel configured on an undefined level" => [ 0, "Ok", ["GaBuZoMeuChannel" => "TotoLevel"], true],
"Channel defined with Error" => [ 0, "Warning", ["GaBuZoMeuChannel" => "Error"]],
"Channel defined with Info" => [ 1, "Warning", ["GaBuZoMeuChannel" => "Info"]],
];
}
/**
* @dataProvider LogOkWithASpecificChannel
* @test
* @backupGlobals disabled
*/
public function TestLogOkWithASpecificChannel($expectedCallNb, $sExpectedLevel, $ConfigReturnedObject, $bExceptionRaised=false)
{
$this->oMetaModelConfig
->method("Get")
->with('log_level_min')
->willReturn($ConfigReturnedObject);
\IssueLog::MockStaticObjects($this->mockFileLog, $this->oMetaModelConfig);
$this->mockFileLog->expects($this->exactly($expectedCallNb))
->method($sExpectedLevel)
->with("log msg", "GaBuZoMeuChannel");
try{
\IssueLog::Ok("log msg", "GaBuZoMeuChannel");
if ($bExceptionRaised)
{
$this->fail("raised should have been raised");
}
}
catch(\Exception $e)
{
if (!$bExceptionRaised)
{
$this->fail("raised should NOT have been raised");
}
}
}
public function LogOkWithASpecificChannel()
{
return [
"empty config" => [ 1, "Ok", ''],
"Empty array" => [ 1, "Ok", array()],
];
}
}