Update Logging Class and add phpunit for Logging Class

Various fixes in the logging class for more clear internal flags setting
and clearn up of complex type checks and debug validation checks.
Add basic debugger logging class phpunit checker (based on debug/print
and only very basic for echo)

Other minor fixes and updates (phpunit with inital dead code check)
This commit is contained in:
Clemens Schwaighofer
2022-02-22 17:56:00 +09:00
parent 0109a67b20
commit 8267bcd8b8
6 changed files with 957 additions and 203 deletions

View File

@@ -26,6 +26,8 @@
use Phan\Config;
return [
// turn color on (-C)
"color_issue_messages_if_supported" => true,
// If true, missing properties will be created when
// they are first seen. If false, we'll report an
// error message.
@@ -36,7 +38,7 @@ return [
"null_casts_as_any_type" => false,
// Backwards Compatibility Checking
'backward_compatibility_checks' => true,
'backward_compatibility_checks' => false,
// Run a quick version of checks that takes less
// time
@@ -46,6 +48,12 @@ return [
// (0 is low severity, 5 is normal severity, 10 is critical)
"minimum_severity" => 0,
// enable for dead code check
// this will spill out errors for all methods never called
// use after all is OK to try to find unused code blocks
// ignore recommended: PhanUnreferencedPublicMethod
// "dead_code_detection" => true,
// default false for include path check
"enable_include_path_checks" => true,
"include_paths" => [
@@ -120,6 +128,13 @@ return [
'suppress_issue_types' => [
// 'PhanUndeclaredMethod',
'PhanEmptyFile',
// ignore unreferences public methods, etc here (for dead code check)
'PhanUnreferencedPublicMethod',
'PhanUnreferencedClass',
'PhanWriteOnlyPublicProperty',
'PhanUnreferencedConstant',
'PhanWriteOnlyPublicProperty',
'PhanReadOnlyPublicProperty'
],
// Override to hardcode existence and types of (non-builtin) globals in the global scope.

View File

@@ -15,6 +15,19 @@ final class CoreLibsDebugLoggingTest extends TestCase
{
public $log;
/**
* test set for options BASIC
*
* 0: options
* - null for NOT set
* 1: expected
* 2: override
* override:
* - constant for COSNTANTS
* - global for _GLOBALS
*
* @return array
*/
public function optionsProvider(): array
{
return [
@@ -68,12 +81,395 @@ final class CoreLibsDebugLoggingTest extends TestCase
];
}
// init tests
// - __construct call with options
/**
* adds log ID settings based on basic options
*
* @return array
*/
public function logIdOptionsProvider(): array
{
// 0: options
// 1: expected
// 2: override
return [
'no log id set' => [
null,
[
'log_file_id' => ''
],
[]
],
// set log id manually afterwards
'set log id manually' => [
null,
[
'log_file_id' => '',
'set_log_file_id' => 'abc123',
],
[
// set post launch
'values' => [
'log_file_id' => 'abc123'
]
]
],
// set log id from options
'set log id via options' => [
[
'file_id' => 'abc456',
],
[
'log_file_id' => 'abc456'
],
[]
],
// set log id from GLOBALS [DEPRECATED]
'set log id via globals' => [
null,
[
'log_file_id' => 'def123'
],
[
'globals' => [
'LOG_FILE_ID' => 'def123'
]
]
],
// set log id from CONSTANT [DEPRECATED]
'set log id via constant' => [
null,
[
'log_file_id' => 'ghi123'
],
[
// reset global
'globals' => [
'LOG_FILE_ID' => null
],
'constant' => [
'LOG_FILE_ID' => 'ghi123'
]
]
],
// invalid, keep previous set
'invalid log id' => [
[
'file_id' => 'jkl456'
],
[
'log_file_id' => 'jkl456',
'set_log_file_id' => 'jkl456',
],
[
'values' => [
'log_file_id' => './#'
]
]
]
];
}
/**
* Undocumented function
*
* @return array
*/
public function logLevelAllProvider(): array
{
return [
'debug all true' => [
'debug',
true,
true,
true,
],
'echo all true' => [
'echo',
true,
true,
true,
],
'print all true' => [
'print',
true,
true,
true,
],
'set invalid level' => [
'invalud',
true,
false,
false,
],
];
}
/**
* Undocumented function
*
* @return array
*/
public function logLevelProvider(): array
{
return [
'set debug on for level A,B,C and check full set' => [
'debug',
'on',
['A', 'B', 'C'],
true,
null,
[
'A' => true,
'B' => true,
'C' => true,
]
],
'set debug off for level A,B,C and check A' => [
'debug',
'off',
['A', 'B', 'C'],
true,
'A',
true,
],
// set one to false
'set debug off for level A, B to false and check all' => [
'debug',
'off',
['A', 'B' => false],
true,
null,
[
'A' => true,
'B' => false,
],
],
// set invalid type
'set invalid level' => [
'invalid',
'',
[],
false,
null,
false
],
// set invalid flag
'set invalid on flag' => [
'print',
'invalid',
[],
false,
null,
false
],
// missing debug array set
'missing debug level array' => [
'print',
'off',
[],
false,
null,
[]
],
// set but check no existing
'set level but check no exisitng' => [
'print',
'on',
['A'],
true,
'C',
false
]
];
}
/**
* Undocumented function
*
* @return array
*/
public function logPerProvider(): array
{
return [
'level set true' => [
'level',
true,
true,
true,
],
'class set true' => [
'class',
true,
true,
true,
],
'page set true' => [
'page',
true,
true,
true,
],
'run set true' => [
'run',
true,
true,
true,
],
'set invalid type' => [
'invalid',
true,
false,
false,
]
];
}
/**
* Undocumented function
*
* @return array
*/
public function prArProvider(): array
{
return [
'simple array' => [
[
'A' => 'foobar'
],
"##HTMLPRE##Array\n(\n"
. " [A] => foobar\n"
. ")\n"
. "##/HTMLPRE##"
],
'empty array' => [
[],
"##HTMLPRE##Array\n(\n"
. ")\n"
. "##/HTMLPRE##"
],
'nested array' => [
[
'A' => [
'B' => 'bar'
]
],
"##HTMLPRE##Array\n(\n"
. " [A] => Array\n"
. " (\n"
. " [B] => bar\n"
. " )\n"
. "\n"
. ")\n"
. "##/HTMLPRE##"
],
];
}
/**
* Undocumented function
*
* 0: array $options
* 1: array $debug_msg
* 2: boolean $expected_debug
* 3: string $expected_file
* 4: string $expected_string_start
* 5: string $expected_string_contains
*
* @return array
*/
public function debugProvider(): array
{
// error message to pass in
$error_msg['A'] = [
'level' => 'A',
'string' => 'error msg',
'strip' => false,
'prefix' => '',
];
// file content to check
$file_msg['A'] = "{PHPUnit\TextUI\Command} <A> - error msg\n";
// string messages to check
$string_msg['A'] = [
's' => '<div style="text-align: left; padding: 5px; font-size: 10px; '
. 'font-family: sans-serif; border-top: 1px solid black; '
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: '
. 'italic; color: #928100;">PHPUnit\TextUI\Command</span>}'
. '</div><div style="font-size: 12px;">[<span style="font-style: '
. 'italic; color: #c56c00;">A</span>] </div><div>[<span '
. 'style="font-weight: bold; color: #5e8600;">',
'c' => 'PHPUnit\TextUI\Command</span>} - error msg</div><!--#BR#-->',
];
// array provider
return [
'A debug: on, print: on, echo: on' => [
[
'debug_all' => true,
'print_all' => true,
'echo_all' => true,
],
$error_msg['A'],
true,
$file_msg['A'],
$string_msg['A']['s'],
$string_msg['A']['c'],
],
'B debug: on, print: off, echo: on' => [
[
'debug_all' => true,
'print_all' => false,
'echo_all' => true,
],
$error_msg['A'],
true,
'',
$string_msg['A']['s'],
$string_msg['A']['c'],
],
'C debug: on, print: on, echo: off' => [
[
'debug_all' => true,
'print_all' => true,
'echo_all' => false,
],
$error_msg['A'],
true,
$file_msg['A'],
'',
'',
],
'D debug: on, print: off, echo: off' => [
[
'debug_all' => true,
'print_all' => false,
'echo_all' => false,
],
$error_msg['A'],
false,
'',
'',
''
],
'E debug: off, print: off, echo: off' => [
[
'debug_all' => false,
'print_all' => false,
'echo_all' => false,
],
$error_msg['A'],
false,
'',
'',
''
]
// TODO more tests with different error messages
];
}
/**
* init logging class
*
* @dataProvider optionsProvider
* @testdox init test [$_dataName]
*
@@ -101,34 +497,340 @@ final class CoreLibsDebugLoggingTest extends TestCase
);
$this->assertEquals(
$expected['debug_all'],
$this->log->getSetting('debug_all')
$this->log->getSetting('debug_output_all')
);
$this->assertEquals(
$expected['print_all'],
$this->log->getSetting('print_all')
$this->log->getSetting('print_output_all')
);
print "LOG: " . $this->log->getSetting('log_folder') . "\n";
print "DEBUG: " . $this->log->getSetting('debug_all') . "\n";
print "PRINT: " . $this->log->getSetting('print_all') . "\n";
// print "LOG: " . $this->log->getSetting('log_folder') . "\n";
// print "DEBUG: " . $this->log->getSetting('debug_output_all') . "\n";
// print "PRINT: " . $this->log->getSetting('print_output_all') . "\n";
}
// setting tests
// - basicSetLogId
// - getLogId
// - setLogLevelAll
// - getLogLevelAll
// - debugFor
// - setLogLevel
// - getLogLevel
// - setLogPer
// - getLogPer
// debug tets
// - pr
// - debug
// - mergeErrors
// - printErrorMsg
// - resetErrorMsg
// - getErrorMsg
/**
* test the setting and getting of LogId
*
* @covers ::setLogId
* @dataProvider logIdOptionsProvider
* @testdox log id set/get tests [$_dataName]
*
* @param array|null $options
* @param array $expected
* @param array $override
* @return void
*/
public function testLogId(?array $options, array $expected, array $override): void
{
// we need to set with file_id option, globals LOG_FILE_ID, constant LOG_FILE_ID
if (!empty($override['constant'])) {
foreach ($override['constant'] as $var => $value) {
define($var, $value);
}
}
if (!empty($override['globals'])) {
foreach ($override['globals'] as $var => $value) {
$GLOBALS[$var] = $value;
}
}
if ($options === null) {
$this->log = new \CoreLibs\Debug\Logging();
} else {
$this->log = new \CoreLibs\Debug\Logging($options);
}
// check current
$this->assertEquals(
$this->log->getLogId(),
$expected['log_file_id']
);
// we need to override now too
if (!empty($override['values'])) {
// check if we have values, set them post and assert
$this->log->basicSetLogId($override['values']['log_file_id']);
$this->assertEquals(
$this->log->getLogId(),
$expected['set_log_file_id']
);
}
}
/**
* check set/get for log level all flag
*
* @dataProvider logLevelAllProvider
* @testdox set/get all log level $type with flag $flag [$_dataName]
*
* @param string $type
* @param bool $flag
* @param bool $expected_set
* @param bool $expected_get
* @return void
*/
public function testSetGetLogLevelAll(
string $type,
bool $flag,
bool $expected_set,
bool $expected_get
): void {
// neutral start with default
$this->log = new \CoreLibs\Debug\Logging();
// set and check
$this->assertEquals(
$this->log->setLogLevelAll($type, $flag),
$expected_set
);
// get and check
$this->assertEquals(
$this->log->getLogLevelAll($type),
$expected_get
);
}
/**
* checks setting for per log info level
*
* @covers ::setLogLevel
* @dataProvider logLevelProvider
* @testdox set/get log level $type to $flag check with $level [$_dataName]
*
* @param string $type
* @param string $flag
* @param array $debug_on
* @param bool $expected_set
* @param string|null $level
* @param bool|array<mixed> $expected_get
* @return void
*/
public function testSetGetLogLevel(
string $type,
string $flag,
array $debug_on,
bool $expected_set,
?string $level,
$expected_get
): void {
// neutral start with default
$this->log = new \CoreLibs\Debug\Logging();
// set
$this->assertEquals(
$this->log->setLogLevel($type, $flag, $debug_on),
$expected_set
);
// get, if level is null compare to?
$this->assertEquals(
$this->log->getLogLevel($type, $flag, $level),
$expected_get
);
}
/**
* set and get per log
* for level/class/page/run flags
*
* @covers ::setLogPer
* @dataProvider logPerProvider
* @testdox set/get log per $type with $set [$_dataName]
*
* @param string $type
* @param boolean $set
* @param boolean $expected_set
* @param boolean $expected_get
* @return void
*/
public function testSetGetLogPer(
string $type,
bool $set,
bool $expected_set,
bool $expected_get
): void {
// neutral start with default
$this->log = new \CoreLibs\Debug\Logging();
// set and check
$this->assertEquals(
$this->log->setLogPer($type, $set),
$expected_set
);
// get and check
$this->assertEquals(
$this->log->getLogPer($type),
$expected_get
);
}
/**
* set the print log file date part
*
* @covers ::setGetLogPrintFileDate
* @testWith [true, true, true]
* [false, false, false]
* @testdox set/get log file date to $input [$_dataName]
*
* @param boolean $input
* @param boolean $expected_set
* @param boolean $expected_get
* @return void
*/
public function testSetGetLogPrintFileDate(bool $input, bool $expected_set, bool $expected_get): void
{
// neutral start with default
$this->log = new \CoreLibs\Debug\Logging();
// set and check
$this->assertEquals(
$this->log->setGetLogPrintFileDate($input),
$expected_set
);
$this->assertEquals(
$this->log->setGetLogPrintFileDate(),
$expected_get
);
}
/**
* convert array to string with ## pre replace space holders
*
* @covers ::prAr
* @dataProvider prArProvider
* @testdox check prAr array to string conversion [$_dataName]
*
* @param array $input
* @param string $expected
* @return void
*/
public function testPrAr(array $input, string $expected): void
{
$this->log = new \CoreLibs\Debug\Logging();
$this->assertEquals(
$this->log->prAr($input),
$expected
);
}
// from here are complex debug tests
/**
* Test debug flow
*
* @covers ::debug
* @dataProvider debugProvider
* @testdox check debug flow: $expected_debug [$_dataName]
*
* @param array $options
* @param array $debug_msg
* @param boolean $expected_debug
* @param string $expected_file
* @param string $expected_string_start
* @param string $expected_string_contains
* @return void
*/
public function testDebug(
array $options,
array $debug_msg,
bool $expected_debug,
string $expected_file,
string $expected_string_start,
string $expected_string_contains,
): void {
// must run with below matrix
// level | debug | print | echo | debug() | printErrorMsg() | file
// A 1/1/1 | on | on | on | true | 'string' | on
// B 1/0/1 | on | off | on | true | 'string' | off
// C 1/1/0 | on | on | off | true | '' | on
// D 1/0/0 | on | off | off | false | '' | off
// E 0/1/1 | off | on | on | false | '' | off
// F 0/0/1 | off | off | on | false | '' | off
// G 0/1/0 | off | on | off | false | '' | off
// H 0/0/0 | off | off | off | false | '' | off
// * debug off
// return false on debug(),
// return false on writeErrorMsg()
// empty string on printErrorMsg
// * print off
// return true on debug(),
// return false on writeErrorMsg()
// empty string on printErrorMsg
// * echo off
// return true on debug(),
// empty string on printErrorMsg
// fillxed error_msg array
// overwrite any previous set from test
$options['file_id'] = 'TestDebug';
// set log folder to temp
$options['log_folder'] = '/tmp/';
// remove any files named /tmp/error_log_TestDebug*.log
array_map('unlink', glob($options['log_folder'] . 'error_msg_' . $options['file_id'] . '*.log'));
// init logger
$this->log = new \CoreLibs\Debug\Logging($options);
// * debug (A/B)
// NULL check for strip/prefix
$this->assertEquals(
$this->log->debug(
$debug_msg['level'],
$debug_msg['string'],
$debug_msg['strip'],
$debug_msg['prefix'],
),
$expected_debug
);
// * if print check data in log file
$log_file = $this->log->getLogFileName();
if (!empty($options['debug_all']) && !empty($options['print_all'])) {
// file name matching
$this->assertStringStartsWith(
$options['log_folder'] . 'error_msg_' . $options['file_id'],
$log_file,
);
// cotents check
if (!is_file($log_file)) {
$this->fail('error msg file not found: ' . $log_file);
} else {
$log_data = file_get_contents($log_file);
if ($log_data === null) {
$this->fail('error msg file not readable or not data: ' . $log_file);
}
// file content matching
$this->assertStringEndsWith(
$expected_file,
$log_data,
);
}
} else {
// there should be no file there
$this->assertEquals(
$log_file,
''
);
}
// ** ECHO ON
$log_string = $this->log->printErrorMsg();
// * print
if (!empty($options['debug_all']) && !empty($options['echo_all'])) {
// print $this->log->printErrorMsg() . "\n";
// echo string must start with
$this->assertStringStartsWith(
$expected_string_start,
$log_string
);
// echo string must containt
$this->assertStringContainsString(
$expected_string_contains,
$log_string
);
// TODO: as printing directly is not really done anymore tests below are todo
// * get error msg (getErrorMsg)
// * merge error msg (mergeErrors)
// * print merged (printErrorMsg)
// * reset A (resetErrorMsg)
// * reset ALL (resetErrorMsg)
} else {
$this->assertEquals(
$log_string,
''
);
}
}
}
// __END__

View File

@@ -87,6 +87,8 @@ $new_log = new CoreLibs\Debug\Logging([
]);
$new_log->debug('OPTIONS TYPE', 'New Type error');
print "OPTIONS LOGGER:<br>" . $new_log->printErrorMsg();
$new_log->setLogLevel('debug', 'on', ['A', 'B', 'C' => false]);
print "LOG LEVEL: " . DebugSupport::printAr($new_log->getLogLevel('debug', 'on')) . "<br>";
echo "<b>CLASS DEBUG CALL</b><br>";

View File

@@ -173,7 +173,7 @@ class Basic
public function basicSetLogId(string $string): string
{
trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->basicSetLogId() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED);
return $this->log->basicSetLogId($string);
return $this->log->setLogId($string);
}
// ****** DEBUG/ERROR FUNCTIONS ******
@@ -263,7 +263,7 @@ class Basic
{
trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->debugFor() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED);
/** @phan-suppress-next-line PhanTypeMismatchArgumentReal, PhanParamTooFew @phpstan-ignore-next-line */
$this->log->debugFor(...[func_get_args()]);
$this->log->setLogLevel(...[func_get_args()]);
}
/**

View File

@@ -361,9 +361,6 @@ class ArrayIO extends \CoreLibs\DB\IO
$this->table_array[$column]['value'] = '';
} else {
if ($this->table_array[$column]['tmp'] != 'none' && $this->table_array[$column]['tmp']) {
// Dateiname zusammenbasteln: org-name + _pkid liste + .ext
list($name, $ext) = explode('.', $this->table_array[$column]['dn']);
// mozilla, patch
$fn_name = explode('/', $this->table_array[$column]['dn']);
$this->table_array[$column]['dn'] = $fn_name[count($fn_name) - 1];

View File

@@ -173,16 +173,17 @@ class Logging
// can be overridden with basicSetLogFileId later
if (!empty($this->options['file_id'])) {
$this->basicSetLogId($this->options['file_id'] ?? '');
$this->setLogId($this->options['file_id'] ?? '');
} elseif (!empty($GLOBALS['LOG_FILE_ID'])) {
// legacy flow, should be removed and only set via options
$this->basicSetLogId($GLOBALS['LOG_FILE_ID']);
$this->setLogId($GLOBALS['LOG_FILE_ID']);
} elseif (defined('LOG_FILE_ID')) {
$this->basicSetLogId(LOG_FILE_ID);
// legacy flow, should be removed and only set via options
$this->setLogId(LOG_FILE_ID);
}
// init the log levels
$this->setLogLevels();
$this->initLogLevels();
}
// *** PRIVATE ***
@@ -192,80 +193,84 @@ class Logging
*
* @return void
*/
private function setLogLevels(): void
private function initLogLevels(): void
{
// if given via parameters, only for all
// globals overrule given settings, for one (array), eg $ECHO['db'] = 1;
if (isset($this->options['debug']) && is_array($this->options['debug'])) {
$this->debug_output = $this->options['debug'];
} elseif (isset($GLOBALS['DEBUG']) && is_array($GLOBALS['DEBUG'])) {
$this->debug_output = $GLOBALS['DEBUG'];
}
if (isset($this->options['echo']) && is_array($this->options['echo'])) {
$this->debug_output = $this->options['echo'];
} elseif (isset($GLOBALS['ECHO']) && is_array($GLOBALS['ECHO'])) {
$this->echo_output = $GLOBALS['ECHO'];
}
if (isset($this->options['print']) && is_array($this->options['print'])) {
$this->debug_output = $this->options['print'];
} elseif (isset($GLOBALS['PRINT']) && is_array($GLOBALS['PRINT'])) {
$this->print_output = $GLOBALS['PRINT'];
}
// exclude these ones from output
if (isset($this->options['debug_not']) && is_array($this->options['debug_not'])) {
$this->debug_output = $this->options['debug_not'];
} elseif (isset($GLOBALS['DEBUG_NOT']) && is_array($GLOBALS['DEBUG_NOT'])) {
$this->debug_output_not = $GLOBALS['DEBUG_NOT'];
}
if (isset($this->options['echo_not']) && is_array($this->options['echo_not'])) {
$this->debug_output = $this->options['echo_not'];
} elseif (isset($GLOBALS['ECHO_NOT']) && is_array($GLOBALS['ECHO_NOT'])) {
$this->echo_output_not = $GLOBALS['ECHO_NOT'];
}
if (isset($this->options['print_not']) && is_array($this->options['print_not'])) {
$this->debug_output = $this->options['print_not'];
} elseif (isset($GLOBALS['PRINT_NOT']) && is_array($GLOBALS['PRINT_NOT'])) {
$this->print_output_not = $GLOBALS['PRINT_NOT'];
foreach (['debug', 'echo', 'print'] as $type) {
// include or exclude (off) from output
foreach (['on', 'off'] as $flag) {
$in_type = $type;
if ($flag == 'off') {
$in_type .= '_not';
}
$up_type = strtoupper($in_type);
if (
isset($this->options[$in_type]) &&
is_array($this->options[$in_type])
) {
$this->setLogLevel($type, $flag, $this->options[$in_type]);
} elseif (
isset($GLOBALS[$up_type]) &&
is_array($GLOBALS[$up_type])
) {
$this->setLogLevel($type, $flag, $GLOBALS[$up_type]);
}
}
}
// all overrule
$this->debug_output_all =
$this->setLogLevelAll(
'debug',
$this->options['debug_all'] ??
$GLOBALS['DEBUG_ALL'] ??
false;
$this->echo_output_all =
$GLOBALS['DEBUG_ALL'] ??
false
);
$this->setLogLevelAll(
'echo',
$this->options['echo_all'] ??
$GLOBALS['ECHO_ALL'] ??
false;
$this->print_output_all =
$GLOBALS['ECHO_ALL'] ??
false
);
$this->setLogLevelAll(
'print',
$this->options['print_all'] ??
$GLOBALS['PRINT_ALL'] ??
false;
$GLOBALS['PRINT_ALL'] ??
false
);
// GLOBAL rules for log writing
$this->log_print_file_date =
$this->setGetLogPrintFileDate(
$this->options['print_file_date'] ??
$GLOBALS['LOG_PRINT_FILE_DATE'] ??
true;
$this->log_per_level =
$GLOBALS['LOG_PRINT_FILE_DATE'] ??
true
);
$this->setLogPer(
'level',
$this->options['per_level'] ??
$GLOBALS['LOG_PER_LEVEL'] ??
false;
$this->log_per_class =
$GLOBALS['LOG_PER_LEVEL'] ??
false
);
$this->setLogPer(
'class',
$this->options['per_class'] ??
$GLOBALS['LOG_PER_CLASS'] ??
false;
$this->log_per_page =
$GLOBALS['LOG_PER_CLASS'] ??
false
);
$this->setLogPer(
'page',
$this->options['per_page'] ??
$GLOBALS['LOG_PER_PAGE'] ??
false;
$this->log_per_run =
$GLOBALS['LOG_PER_PAGE'] ??
false
);
$this->setLogPer(
'run',
$this->options['per_run'] ??
$GLOBALS['LOG_PER_RUN'] ??
false;
$GLOBALS['LOG_PER_RUN'] ??
false
);
// set log per date
if ($this->log_print_file_date) {
if ($this->setGetLogPrintFileDate()) {
$this->log_file_date = date('Y-m-d');
}
// set per run ID
@@ -295,46 +300,14 @@ class Logging
{
$access = false;
// check if we do debug, echo or print
switch ($target) {
case 'debug':
if (
(
(isset($this->debug_output[$level]) && $this->debug_output[$level]) ||
$this->debug_output_all
) &&
(!isset($this->debug_output_not[$level]) ||
(isset($this->debug_output_not[$level]) && !$this->debug_output_not[$level])
)
) {
$access = true;
}
break;
case 'echo':
if (
(
(isset($this->echo_output[$level]) && $this->echo_output[$level]) ||
$this->echo_output_all
) &&
(!isset($this->echo_output_not[$level]) ||
(isset($this->echo_output_not[$level]) && !$this->echo_output_not[$level])
)
) {
$access = true;
}
break;
case 'print':
if (
(
(isset($this->print_output[$level]) && $this->print_output[$level]) ||
$this->print_output_all
) &&
(!isset($this->print_output_not[$level]) ||
(isset($this->print_output_not[$level]) && !$this->print_output_not[$level])
)
) {
$access = true;
}
break;
if (
(
$this->getLogLevel($target, 'on', $level) ||
$this->getLogLevelAll($target)
) &&
!$this->getLogLevel($target, 'off', $level)
) {
$access = true;
}
return $access;
}
@@ -355,8 +328,6 @@ class Logging
return false;
}
// init output variable
$output = $error_string; // output formated error string to output file
// init base file path
$fn = $this->log_folder . $this->log_print_file . '.' . $this->log_file_name_ext;
// log ID prefix settings, if not valid, replace with empty
@@ -369,8 +340,10 @@ class Logging
if ($this->log_per_run) {
$rpl_string = '_' . $this->log_file_unique_id; // add 8 char unique string
} elseif ($this->log_print_file_date) {
} elseif ($this->setGetLogPrintFileDate()) {
$rpl_string = '_' . $this->log_file_date; // add date to file
} else {
$rpl_string = '';
}
$fn = str_replace('##DATE##', $rpl_string, $fn); // create output filename
@@ -397,12 +370,13 @@ class Logging
$this->log_file_name = $fn;
$fp = fopen($this->log_file_name, 'a');
if ($fp !== false) {
fwrite($fp, $output);
fwrite($fp, $error_string);
fclose($fp);
return true;
} else {
echo "<!-- could not open file: " . $this->log_file_name . " //-->";
return false;
}
return true;
}
// *** PUBLIC ***
@@ -424,8 +398,21 @@ class Logging
* if non valid string is given it returns the previous set one only
* @param string $string log file id string value
* @return string returns the set log file id string
* @deprecated Use $log->setLogId()
*/
public function basicSetLogId(string $string): string
{
return $this->setLogId($string);
}
/**
* sets the internal log file prefix id
* string must be a alphanumeric string
* if non valid string is given it returns the previous set one only
* @param string $string log file id string value
* @return string returns the set log file id string
*/
public function setLogId(string $string): string
{
if (preg_match("/^[\w\-]+$/", $string)) {
$this->log_file_id = $string;
@@ -448,6 +435,7 @@ class Logging
* @param string $flag on/off
* array $array of levels to turn on/off debug
* @return bool Return false if type or flag is invalid
* @deprecated Use setLogLevel
*/
public function debugFor(string $type, string $flag): bool
{
@@ -489,13 +477,15 @@ class Logging
/**
* passes list of level names, to turn on debug
* eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']);
* TODO: currently we can only turn ON
* @param string $type debug, echo, print
* @param string $flag on/off
* array $array of levels to turn on/off debug
* @return bool Return false if type or falg invalid
* @param string $type debug, echo, print
* @param string $flag on/off
* @param array<mixed> $debug_on Array of levels to turn on/off debug
* To turn off a level set 'Level' => false,
* If not set, switches to on
* @return bool Return false if type or flag invalid
* also false if debug array is empty
*/
public function setLogLevel(string $type, string $flag): bool
public function setLogLevel(string $type, string $flag, array $debug_on): bool
{
// abort if not valid type
if (!in_array($type, ['debug', 'echo', 'print'])) {
@@ -505,14 +495,17 @@ class Logging
if (!in_array($flag, ['on', 'off'])) {
return false;
}
$debug_on = func_get_args();
array_shift($debug_on); // kick out type
array_shift($debug_on); // kick out flag (on/off)
if (count($debug_on) >= 1) {
foreach ($debug_on as $level) {
foreach ($debug_on as $level => $set) {
$switch = $type . '_output' . ($flag == 'off' ? '_not' : '');
$this->{$switch}[$level] = true;
if (!is_bool($set)) {
$level = $set;
$set = true;
}
$this->{$switch}[$level] = $set;
}
} else {
return false;
}
return true;
}
@@ -536,8 +529,8 @@ class Logging
return false;
}
$switch = $type . '_output' . ($flag == 'off' ? '_not' : '');
// bool
if ($level !== null) {
// log level direct check must be not null or not empty string
if (!empty($level)) {
return $this->{$switch}[$level] ?? false;
}
// array
@@ -576,6 +569,30 @@ class Logging
return $this->{'log_per_' . $type};
}
/**
* Set or get the log file date extension flag
* if null or empty parameter gets current flag
* @param boolean|null $set Set the date suffix for log files
* If set to null return current set
* @return boolean Current set flag
*/
public function setGetLogPrintFileDate(?bool $set = null): bool
{
if ($set !== null) {
$this->log_print_file_date = $set;
}
return $this->log_print_file_date;
}
/**
* Return current set log file name
* @return string Filename set set after the last time debug was called
*/
public function getLogFileName(): string
{
return $this->log_file_name;
}
/**
* A replacement for the \CoreLibs\Debug\Support::printAr
* But this does not wrap it in <pre></pre>
@@ -602,10 +619,23 @@ class Logging
* if strip is false, recommended to add that to $string
* @return bool True if logged, false if not logged
*/
public function debug(string $level, string $string, bool $strip = false, string $prefix = ''): bool
{
if (!$this->doDebugTrigger('debug', $level)) {
return false;
public function debug(
string $level,
string $string,
bool $strip = false,
string $prefix = ''
): bool {
$status = false;
// must be debug on and either echo or print on
if (
!$this->doDebugTrigger('debug', $level) ||
(
// if debug is on, either print or echo must be set to on
!$this->doDebugTrigger('print', $level) &&
!$this->doDebugTrigger('echo', $level)
)
) {
return $status;
}
// get the last class entry and wrie that
$class = Support::getCallerClass();
@@ -613,7 +643,7 @@ class Logging
$timestamp = Support::printTime();
// same string put for print (no html data inside)
// write to file if set
$this->writeErrorMsg(
$status = $this->writeErrorMsg(
$level,
'[' . $timestamp . '] '
. '[' . $this->host_name . '] '
@@ -662,66 +692,62 @@ class Logging
Html::htmlent($string)
)
. "</div><!--#BR#-->";
$status = true;
}
return true;
return $status;
}
/**
* merges the given error array with the one from this class
* only merges visible ones
* @param array<mixed> $error_msg error array
* @return void has no return
* for ECHO ON only
* returns error data as string so it can be echoed out
* @param string $header_prefix prefix string for header
* @return string error msg for all levels
*/
public function mergeErrors(array $error_msg = []): void
{
if (!is_array($error_msg)) {
$error_msg = [];
}
array_push($this->error_msg, ...$error_msg);
}
/**
* prints out the error string
* @param string $string prefix string for header
* @return string error msg for all levels
*/
public function printErrorMsg(string $string = ''): string
public function printErrorMsg(string $header_prefix = ''): string
{
$string_output = '';
if ($this->debug_output_all) {
if ($this->error_msg_prefix) {
$string = $this->error_msg_prefix;
}
$script_end = microtime(true) - $this->script_starttime;
foreach ($this->error_msg as $level => $temp_debug_output) {
if ($this->doDebugTrigger('debug', $level)) {
if ($this->doDebugTrigger('echo', $level)) {
$string_output .= '<div style="font-size: 12px;">'
. '[<span style="font-style: italic; color: #c56c00;">' . $level . '</span>] '
. ($string ? "<b>**** " . Html::htmlent($string) . " ****</br>\n" : "")
. '</div>'
. join('', $temp_debug_output);
} // echo it out
} // do printout
} // for each level
// create the output wrapper around, so we have a nice formated output per class
if ($string_output) {
$string_prefix = '<div style="text-align: left; padding: 5px; font-size: 10px; '
. 'font-family: sans-serif; border-top: 1px solid black; '
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. Support::getCallerClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>'
. '</div>';
}
// if not debug && echo on, do not return anything
if (
!$this->getLogLevelAll('debug') ||
!$this->getLogLevelAll('echo')
) {
return $string_output;
}
if ($this->error_msg_prefix) {
$header_prefix = $this->error_msg_prefix;
}
$script_end = microtime(true) - $this->script_starttime;
foreach ($this->error_msg as $level => $temp_debug_output) {
if ($this->doDebugTrigger('debug', $level)) {
if ($this->doDebugTrigger('echo', $level)) {
$string_output .= '<div style="font-size: 12px;">'
. '[<span style="font-style: italic; color: #c56c00;">' . $level . '</span>] '
. ($header_prefix ? "<b>**** " . Html::htmlent($header_prefix) . " ****</br>\n" : '')
. '</div>'
. join('', $temp_debug_output);
} // echo it out
} // do printout
} // for each level
// create the output wrapper around
// so we have a nice formated output per class
if ($string_output) {
$string_prefix = '<div style="text-align: left; padding: 5px; font-size: 10px; '
. 'font-family: sans-serif; border-top: 1px solid black; '
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. Support::getCallerClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>'
. '</div>';
}
// }
return $string_output;
}
/**
* for ECHO ON only
* unsests the error message array
* can be used if writing is primary to file
* if no level given resets all
@@ -738,14 +764,26 @@ class Logging
}
/**
* for ECHO ON only
* Get current error message array
*
* @return array<mixed> error messages collected
*/
public function getErrorMsg(): array
{
return $this->error_msg;
}
/**
* for ECHO ON only
* merges the given error array with the one from this class
* only merges visible ones
* @param array<mixed> $error_msg error array
* @return void has no return
*/
public function mergeErrors(array $error_msg = []): void
{
array_push($this->error_msg, ...$error_msg);
}
}
// __END__