N°4261 Refactor ExceptionLog (#239)

Doing a code review with Bruno, we agreed to do some little refactoring :

* Level per exception class
  - Before the whole ExceptionLog::Log method was a total rewrite of its parent, with some code duplicates... not a good idea : we should better improve LogAPI to make other similar uses possible in the future !
  - The logic to get level from config must be in a GetMinLogLevel override
* Write to DB
  - Pull up this functionnality in LogAPI
  - Add a sCode parameter in GetLevelDefault

Doing this refactoring, I also improved :

* Test the attributes set when creating the EventIssue object : during my dev I had crashes because I didn't filled all the mandatory fields... Having a PHPUnit test checking this will prevent future bugs to happen if attributes are modified in the class or in the object creation method
* Use Throwable instead of Exception : this was added in PHP 7.0 and will allow to catch both Exception and Error
* Because we need to have 2 statements on the same line in \Combodo\iTop\Test\UnitTest\Core\Log\ExceptionLogTest::testLogInFile, I modified the editorConfig file to allow disabling the formatter using comments.
This commit is contained in:
Pierre Goiffon
2021-10-20 16:01:08 +02:00
committed by GitHub
parent ef6d7925fc
commit 0e14be8b15
6 changed files with 587 additions and 289 deletions

View File

@@ -72,17 +72,22 @@ class ExceptionLogTest extends ItopDataTestCase
$aContext = ['contextKey1' => 'value'];
foreach ($aLevels as $i => $sLevel) {
$sExpectedFile = __FILE__;
// @formatter:off
$oException = new $aExceptions[$i]("Iteration number $i"); $sExpectedLine = __LINE__; //Both should remain on the same line
// @formatter:on
$iExpectedWriteNumber = $aExpectedWriteNumber[$i];
$iExpectedDbWriteNumber = $aExpectedDbWriteNumber[$i];
$aExpectedFileContext = array_merge($aContext, ['exception class' => get_class($oException), 'file' => $sExpectedFile, 'line' => $sExpectedLine]); //The context is preserved, and, if the key 'exception class' is not yet in the array, it is added
$aExpectedFileContext = array_merge($aContext, [
'exception class' => get_class($oException),
'file' => $sExpectedFile,
'line' => $sExpectedLine,
]
); //The context is preserved, and, if the key 'exception class' is not yet in the array, it is added
$mockFileLog->expects($this->exactly($iExpectedWriteNumber))
->method($sLevel)
->with($oException->GetMessage(), $sChannel, $aExpectedFileContext)
;
->with($oException->GetMessage(), $sChannel, $aExpectedFileContext);
ExceptionLog::MockStaticObjects($mockFileLog, $oMockConfig);
@@ -165,7 +170,7 @@ class ExceptionLogTest extends ItopDataTestCase
'iExpectedDbWriteNumber' => [0],
'logLevelMinWriteInDb' => ['Exception' => 'Error'],
],
'default channel, default conf' => [
'default channel, default conf' => [
'aLevels' => ['Warning'],
'aExceptions' => [\Exception::class],
'sChannel' => 'Exception',
@@ -174,7 +179,7 @@ class ExceptionLogTest extends ItopDataTestCase
'iExpectedDbWriteNumber' => [0],
'logLevelMinWriteInDb' => null,
],
'enabled' => [
'enabled' => [
'aLevels' => ['Debug'],
'aExceptions' => [\Exception::class],
'sChannel' => 'Exception',
@@ -184,17 +189,84 @@ class ExceptionLogTest extends ItopDataTestCase
'logLevelMinWriteInDb' => ['Exception' => 'Debug'],
],
'file: 2 enabled, 2 filtered, db: 1 enabled, 3 filtered' => [
'aLevels' => ['Debug', 'Trace', 'Warning', 'Error'],
'aExceptions' => [\Exception::class, \Exception::class, \Exception::class, \Exception::class],
'sChannel' => 'Exception',
'aExpectedWriteNumber' => [0, 0, 1, 1],
'logLevelMin' => null,
'aLevels' => ['Debug', 'Trace', 'Warning', 'Error'],
'aExceptions' => [\Exception::class, \Exception::class, \Exception::class, \Exception::class],
'sChannel' => 'Exception',
'aExpectedWriteNumber' => [0, 0, 1, 1],
'logLevelMin' => null,
'iExpectedDbWriteNumber' => [0, 0, 0, 1],
'logLevelMinWriteInDb' => null,
'logLevelMinWriteInDb' => null,
],
'Simple Error (testing Throwable signature)' => [
'aLevels' => ['Debug'],
'aExceptions' => [\Error::class],
'sChannel' => 'Error',
'aExpectedWriteNumber' => [1],
'logLevelMin' => 'Debug',
'iExpectedDbWriteNumber' => [1],
'logLevelMinWriteInDb' => 'Debug',
],
];
}
/**
* @dataProvider exceptionClassProvider
*/
public function testExceptionClassFromHierarchy($aLogConfig, $sActualExceptionClass, $sExpectedExceptionClass)
{
$oMockConfig = $this->createMock('Config');
$oMockConfig
->method('Get')
->willReturn($aLogConfig);
ExceptionLog::MockStaticObjects(null, $oMockConfig);
$sReturnedExceptionClass = $this->InvokeNonPublicStaticMethod(ExceptionLog::class, 'ExceptionClassFromHierarchy', [$sActualExceptionClass]);
static::assertEquals($sExpectedExceptionClass, $sReturnedExceptionClass, 'Not getting correct exception in hierarchy !');
}
public function exceptionClassProvider()
{
// WARNING : cannot use Exception::class or LogAPI constants for levels :/
return [
'Exception, defined in config' => [
'aLogConfig' => ['Exception' => 'Debug'],
'sActualExceptionClass' => 'Exception',
'sExpectedExceptionClass' => 'Exception',
],
'Child of Exception, Exception defined in config' => [
'aLogConfig' => ['Exception' => 'Debug'],
'sActualExceptionClass' => 'ChildException',
'sExpectedExceptionClass' => 'Exception',
],
'Grand child of Exception, Exception defined in config' => [
'aLogConfig' => ['Exception' => 'Debug'],
'sActualExceptionClass' => 'GrandChildException',
'sExpectedExceptionClass' => 'Exception',
],
'Exception, just a default level defined in config' => [
'aLogConfig' => 'Debug',
'sActualExceptionClass' => 'Exception',
'sExpectedExceptionClass' => null,
],
'Exception, no exception class defined in config' => [
'aLogConfig' => ['IssueLog' => 'Debug'],
'sActualExceptionClass' => 'Exception',
'sExpectedExceptionClass' => null,
],
'Exception, just the child defined in config' => [
'aLogConfig' => ['ChildException' => 'Debug'],
'sActualExceptionClass' => 'Exception',
'sExpectedExceptionClass' => null,
],
'Exception, Exception and the child defined in config' => [
'aLogConfig' => ['Exception' => 'Debug', 'ChildException' => 'Debug'],
'sActualExceptionClass' => 'Exception',
'sExpectedExceptionClass' => 'Exception',
],
];
}
}