Merge remote-tracking branch 'origin/support/3.2' into develop

# Conflicts:
#	sources/Core/Kpi/KpiLogData.php
This commit is contained in:
Eric Espie
2026-02-05 15:33:25 +01:00
5 changed files with 175 additions and 84 deletions

View File

@@ -1,18 +1,20 @@
<?php <?php
/** /**
* @copyright Copyright (C) 2010-2024 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
use Combodo\iTop\Application\EventRegister\ApplicationEvents;
use Combodo\iTop\Core\Kpi\KpiLogData; use Combodo\iTop\Core\Kpi\KpiLogData;
use Combodo\iTop\Service\Events\EventService;
use Combodo\iTop\Service\Events\iEventServiceSetup;
use Combodo\iTop\Service\Module\ModuleService; use Combodo\iTop\Service\Module\ModuleService;
/** /**
* Measures operations duration, memory usage, etc. (and some other KPIs) * Measures operations duration, memory usage, etc. (and some other KPIs)
*/ */
class ExecutionKPI implements iEventServiceSetup
class ExecutionKPI
{ {
protected static $m_bEnabled_Duration = false; protected static $m_bEnabled_Duration = false;
protected static $m_bEnabled_Memory = false; protected static $m_bEnabled_Memory = false;
@@ -23,15 +25,18 @@ class ExecutionKPI
protected static $m_aStats = []; // Recurrent operations protected static $m_aStats = []; // Recurrent operations
protected static $m_aExecData = []; // One shot operations protected static $m_aExecData = []; // One shot operations
/** /** @var true */
* @var array[ExecutionKPI] private static bool $bMetamodelStarted = false;
*/
protected static $m_aExecutionStack = []; // embedded execution stats
private static ?float $fLastReportTime = null;
private static ?float $iLastReportMemory = null;
// For stats
protected $m_fStarted = null; protected $m_fStarted = null;
protected $m_fChildrenDuration = 0; // Count embedded
protected $m_iInitialMemory = null; protected $m_iInitialMemory = null;
private static array $aBootstrapOperations = [];
public static function EnableDuration($iLevel) public static function EnableDuration($iLevel)
{ {
if ($iLevel > 0) { if ($iLevel > 0) {
@@ -71,6 +76,7 @@ class ExecutionKPI
return true; return true;
} }
} }
return false; return false;
} }
@@ -97,7 +103,7 @@ class ExecutionKPI
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'"; $sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
$sSlowQueries = ''; $sSlowQueries = '';
if (self::$m_fSlowQueries > 0) { if (self::$m_fSlowQueries > 0) {
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s"; $sSlowQueries = '. Slow Queries: '.self::$m_fSlowQueries.'s';
} }
$aExtensions = []; $aExtensions = [];
@@ -127,7 +133,7 @@ class ExecutionKPI
$sRequest .= ' operation: '.$_POST['operation']; $sRequest .= ' operation: '.$_POST['operation'];
} }
$fStop = MyHelpers::getmicrotime(); $fStop = microtime(true);
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) { if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
// Invoke extensions to log the KPI operation // Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */ /** @var \iKPILoggerExtension $oExtensionInstance */
@@ -151,17 +157,17 @@ class ExecutionKPI
$sTableStyle = 'background-color: #ccc; margin: 10px;'; $sTableStyle = 'background-color: #ccc; margin: 10px;';
$sHtml = "<hr/>"; $sHtml = '<hr/>';
$sHtml .= "<div style=\"background-color: grey; padding: 10px;\">"; $sHtml .= "<div style=\"background-color: grey; padding: 10px;\">";
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>"; $sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>";
$oStarted = DateTime::createFromFormat('U.u', $fItopStarted); $oStarted = DateTime::createFromFormat('U.u', $fItopStarted);
$sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>'; $sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>';
$sHtml .= "<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>"; $sHtml .= '<p>log_kpi_user_id: '.UserRights::GetUserId().'</p>';
$sHtml .= "<div>"; $sHtml .= '<div>';
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">"; $sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= "<thead>"; $sHtml .= '<thead>';
$sHtml .= " <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>"; $sHtml .= ' <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>';
$sHtml .= "</thead>"; $sHtml .= '</thead>';
foreach (self::$m_aExecData as $aOpStats) { foreach (self::$m_aExecData as $aOpStats) {
$sOperation = $aOpStats['op']; $sOperation = $aOpStats['op'];
$sBegin = round($aOpStats['time_begin'], 3); $sBegin = round($aOpStats['time_begin'], 3);
@@ -180,12 +186,12 @@ class ExecutionKPI
} }
} }
$sHtml .= "<tr>"; $sHtml .= '<tr>';
$sHtml .= " <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>"; $sHtml .= " <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>";
$sHtml .= "</tr>"; $sHtml .= '</tr>';
} }
$sHtml .= "</table>"; $sHtml .= '</table>';
$sHtml .= "</div>"; $sHtml .= '</div>';
$aConsolidatedStats = []; $aConsolidatedStats = [];
foreach (self::$m_aStats as $sOperation => $aOpStats) { foreach (self::$m_aStats as $sOperation => $aOpStats) {
@@ -217,11 +223,11 @@ class ExecutionKPI
]; ];
} }
$sHtml .= "<div>"; $sHtml .= '<div>';
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">"; $sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= "<thead>"; $sHtml .= '<thead>';
$sHtml .= " <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>"; $sHtml .= ' <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>';
$sHtml .= "</thead>"; $sHtml .= '</thead>';
foreach ($aConsolidatedStats as $sOperation => $aOpStats) { foreach ($aConsolidatedStats as $sOperation => $aOpStats) {
$sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>'; $sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
$sCount = $aOpStats['count']; $sCount = $aOpStats['count'];
@@ -230,14 +236,14 @@ class ExecutionKPI
$sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>'; $sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>';
$sAvg = round($aOpStats['avg'], 3); $sAvg = round($aOpStats['avg'], 3);
$sHtml .= "<tr>"; $sHtml .= '<tr>';
$sHtml .= " <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>"; $sHtml .= " <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>";
$sHtml .= "</tr>"; $sHtml .= '</tr>';
} }
$sHtml .= "</table>"; $sHtml .= '</table>';
$sHtml .= "</div>"; $sHtml .= '</div>';
$sHtml .= "</div>"; $sHtml .= '</div>';
$sHtml .= "<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>"; $sHtml .= "<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>";
@@ -287,18 +293,18 @@ class ExecutionKPI
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>'; $sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
$sHtml .= "<h4>$sOperationHtml</h4>"; $sHtml .= "<h4>$sOperationHtml</h4>";
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">"; $sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= "<thead>"; $sHtml .= '<thead>';
$sHtml .= " <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>"; $sHtml .= ' <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>';
$sHtml .= "</thead>"; $sHtml .= '</thead>';
$bDisplayHeader = false; $bDisplayHeader = false;
} }
$sHtml .= "<tr>"; $sHtml .= '<tr>';
$sHtml .= " <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>"; $sHtml .= " <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>";
$sHtml .= "</tr>"; $sHtml .= '</tr>';
} }
} }
if (!$bDisplayHeader) { if (!$bDisplayHeader) {
$sHtml .= "</table>"; $sHtml .= '</table>';
$sHtml .= "<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>"; $sHtml .= "<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>";
} }
self::Report($sHtml); self::Report($sHtml);
@@ -333,39 +339,50 @@ class ExecutionKPI
$aNewEntry = null; $aNewEntry = null;
$fStarted = $this->m_fStarted; if (is_null(static::$fLastReportTime)) {
$fStopped = $this->m_fStarted; static::$fLastReportTime = $fItopStarted;
if (self::$m_bEnabled_Duration) {
$fStopped = MyHelpers::getmicrotime();
$aNewEntry = [
'op' => $sOperationDesc,
'time_begin' => $this->m_fStarted - $fItopStarted,
'time_end' => $fStopped - $fItopStarted,
];
// Reset for the next operation (if the object is recycled)
$this->m_fStarted = $fStopped;
} }
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory; if (is_null(static::$iLastReportMemory)) {
$iCurrentMemory = 0; global $iItopInitialMemory;
$iPeakMemory = 0; static::$iLastReportMemory = $iItopInitialMemory;
}
$fStarted = static::$fLastReportTime;
$fStopped = microtime(true);
if (self::$m_bEnabled_Duration) {
$aNewEntry = [
'op' => $sOperationDesc,
'time_begin' => $fStarted - $fItopStarted,
'time_end' => $fStopped - $fItopStarted,
];
}
static::$fLastReportTime = $fStopped;
$iInitialMemory = static::$iLastReportMemory;
$iCurrentMemory = $iInitialMemory;
$iPeakMemory = $iInitialMemory;
if (self::$m_bEnabled_Memory) { if (self::$m_bEnabled_Memory) {
$iCurrentMemory = self::memory_get_usage(); $iCurrentMemory = self::memory_get_usage();
if (is_null($aNewEntry)) { if (is_null($aNewEntry)) {
$aNewEntry = ['op' => $sOperationDesc]; $aNewEntry = ['op' => $sOperationDesc];
} }
$aNewEntry['mem_begin'] = $this->m_iInitialMemory; $aNewEntry['mem_begin'] = $iInitialMemory;
$aNewEntry['mem_end'] = $iCurrentMemory; $aNewEntry['mem_end'] = $iCurrentMemory;
$iPeakMemory = self::memory_get_peak_usage(); $iPeakMemory = self::memory_get_peak_usage();
$aNewEntry['mem_peak'] = $iPeakMemory; $aNewEntry['mem_peak'] = $iPeakMemory;
// Reset for the next operation (if the object is recycled) // Reset for the next operation (if the object is recycled)
$this->m_iInitialMemory = $iCurrentMemory; static::$iLastReportMemory = $iCurrentMemory;
} }
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) { if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
$aCallstack = ['callstack' => $this->GetCallStack()];
if (static::$bMetamodelStarted) {
foreach (static::$aBootstrapOperations as $oLog) {
$this->LogOperation($oLog);
}
static::$aBootstrapOperations = [];
// Invoke extensions to log the KPI operation // Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1); $sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$oKPILogData = new KpiLogData( $oKPILogData = new KpiLogData(
KpiLogData::TYPE_REPORT, KpiLogData::TYPE_REPORT,
@@ -376,9 +393,24 @@ class ExecutionKPI
$sExtension, $sExtension,
$iInitialMemory, $iInitialMemory,
$iCurrentMemory, $iCurrentMemory,
$iPeakMemory $iPeakMemory,
$aCallstack
); );
$oExtensionInstance->LogOperation($oKPILogData); $this->LogOperation($oKPILogData);
} else {
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_REPORT,
'Step',
$sOperationDesc,
$fStarted,
$fStopped,
'',
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
);
static::$aBootstrapOperations[] = $oKPILogData;
} }
} }
@@ -388,6 +420,14 @@ class ExecutionKPI
$this->ResetCounters(); $this->ResetCounters();
} }
private function LogOperation(KpiLogData $oKPILogData): void
{
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$oExtensionInstance->LogOperation($oKPILogData);
}
}
/** /**
* Compute statistics for a call to an extension * Compute statistics for a call to an extension
* Note: not working in dev mode (with links to env-production) * Note: not working in dev mode (with links to env-production)
@@ -423,7 +463,7 @@ class ExecutionKPI
$fDuration = 0; $fDuration = 0;
if (self::$m_bEnabled_Duration) { if (self::$m_bEnabled_Duration) {
$fStopped = MyHelpers::getmicrotime(); $fStopped = microtime(true);
$fDuration = $fStopped - $this->m_fStarted; $fDuration = $fStopped - $this->m_fStarted;
$aCallstack = []; $aCallstack = [];
if (self::$m_bGenerateLegacyReport) { if (self::$m_bGenerateLegacyReport) {
@@ -438,6 +478,8 @@ class ExecutionKPI
'time' => $fDuration, 'time' => $fDuration,
]; ];
} }
} else {
$aCallstack = ['callstack' => $this->GetCallStack()];
} }
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory; $iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
@@ -448,33 +490,45 @@ class ExecutionKPI
$iPeakMemory = self::memory_get_peak_usage(); $iPeakMemory = self::memory_get_peak_usage();
} }
// Invoke extensions to log the KPI operation if (static::$bMetamodelStarted) {
/** @var \iKPILoggerExtension $oExtensionInstance */ foreach (static::$aBootstrapOperations as $oLog) {
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) { $this->LogOperation($oLog);
//$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1); }
$sExtension = ''; static::$aBootstrapOperations = [];
$oKPILogData = new KpiLogData( $oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS, KpiLogData::TYPE_STATS,
$sOperation, $sOperation,
$sArguments, $sArguments,
$this->m_fStarted, $this->m_fStarted,
$fStopped, $fStopped,
$sExtension, '',
$iInitialMemory, $iInitialMemory,
$iCurrentMemory, $iCurrentMemory,
$iPeakMemory, $iPeakMemory,
$aCallstack $aCallstack
); );
$oExtensionInstance->LogOperation($oKPILogData); $this->LogOperation($oKPILogData);
} else {
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS,
$sOperation,
$sArguments,
$this->m_fStarted,
$fStopped,
'',
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
);
static::$aBootstrapOperations[] = $oKPILogData;
} }
} }
} }
protected function ResetCounters() protected function ResetCounters()
{ {
if (self::$m_bEnabled_Duration) {
$this->m_fStarted = microtime(true); $this->m_fStarted = microtime(true);
}
if (self::$m_bEnabled_Memory) { if (self::$m_bEnabled_Memory) {
$this->m_iInitialMemory = self::memory_get_usage(); $this->m_iInitialMemory = self::memory_get_usage();
@@ -503,7 +557,33 @@ class ExecutionKPI
if (function_exists('memory_get_peak_usage')) { if (function_exists('memory_get_peak_usage')) {
return memory_get_peak_usage($bRealUsage); return memory_get_peak_usage($bRealUsage);
} }
// PHP > 5.2.1 - this verb depends on a compilation option // PHP > 5.2.1 - this verb depends on a compilation option
return 0; return 0;
} }
/*
* ModuleHandlerApiInterface methods
*/
public static function OnMetaModelStarted()
{
static::$bMetamodelStarted = true;
}
public function RegisterEventsAndListeners()
{
EventService::RegisterListener(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED, [$this, 'OnMetaModelStarted']);
}
private function GetCallStack(): string
{
$aCallStack = MyHelpers::get_callstack(2);
$sCallStack = "Call stack:\n";
foreach ($aCallStack as $index => $aLine) {
$sCallStack .= "#$index ".$aLine['File'].'('.$aLine['Line'].'): '.$aLine['Function']."\n";
}
return $sCallStack;
}
} }

View File

@@ -5,9 +5,11 @@
$ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */ $ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */
$ibo-multi-column--margin-y: $ibo-spacing-0 !default; $ibo-multi-column--margin-y: $ibo-spacing-0 !default;
$ibo-multi-column--row-gap: $ibo-spacing-800 !default;
.ibo-multi-column { .ibo-multi-column {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin: $ibo-multi-column--margin-y $ibo-multi-column--margin-x; margin: $ibo-multi-column--margin-y $ibo-multi-column--margin-x;
row-gap: $ibo-multi-column--row-gap;
} }

View File

@@ -19,7 +19,7 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:FAQ/Attribute:summary+' => '', 'Class:FAQ/Attribute:summary+' => '',
'Class:FAQ/Attribute:description' => 'Description', 'Class:FAQ/Attribute:description' => 'Description',
'Class:FAQ/Attribute:description+' => '', 'Class:FAQ/Attribute:description+' => '',
'Class:FAQ/Attribute:category_id' => 'Categorie', 'Class:FAQ/Attribute:category_id' => 'Catégorie',
'Class:FAQ/Attribute:category_id+' => '', 'Class:FAQ/Attribute:category_id+' => '',
'Class:FAQ/Attribute:category_name' => 'Nom catégorie', 'Class:FAQ/Attribute:category_name' => 'Nom catégorie',
'Class:FAQ/Attribute:category_name+' => '', 'Class:FAQ/Attribute:category_name+' => '',

View File

@@ -238,6 +238,11 @@
<action id="action:bulk delete">allow</action> <action id="action:bulk delete">allow</action>
</actions> </actions>
</group> </group>
<group id="Ticketing">
<actions>
<action id="stimulus:ev_close">allow</action>
</actions>
</group>
<group id="UserRequest"> <group id="UserRequest">
<actions> <actions>
<action id="stimulus:ev_approve">allow</action> <action id="stimulus:ev_approve">allow</action>

View File

@@ -34,7 +34,7 @@ class KpiLogData
/** @var array */ /** @var array */
public $aData; public $aData;
// Computed // Computed
public float $fDuration; public string $sDuration;
/** /**
* @param string $sType * @param string $sType
@@ -45,9 +45,10 @@ class KpiLogData
* @param string $sExtension * @param string $sExtension
* @param int $iInitialMemory * @param int $iInitialMemory
* @param int $iCurrentMemory * @param int $iCurrentMemory
* @param int $iPeakMemory
* @param array $aData * @param array $aData
*/ */
public function __construct($sType, $sOperation, $sArguments, $fStartTime, $fStopTime, $sExtension, $iInitialMemory = 0, $iCurrentMemory = 0, $iPeakMemory = 0, $aData = []) public function __construct($sType, $sOperation, $sArguments, float $fStartTime, float $fStopTime, $sExtension, $iInitialMemory = 0, $iCurrentMemory = 0, $iPeakMemory = 0, $aData = [])
{ {
$this->sType = $sType; $this->sType = $sType;
$this->sOperation = $sOperation; $this->sOperation = $sOperation;
@@ -59,7 +60,7 @@ class KpiLogData
$this->iCurrentMemory = $iCurrentMemory; $this->iCurrentMemory = $iCurrentMemory;
$this->iPeakMemory = $iPeakMemory; $this->iPeakMemory = $iPeakMemory;
$this->aData = $aData; $this->aData = $aData;
$this->fDuration = sprintf('%01.4f', $this->fStopTime - $this->fStartTime); $this->sDuration = sprintf('%01.3f', $fStopTime - $fStartTime);
} }
/** /**
@@ -69,11 +70,12 @@ class KpiLogData
*/ */
public static function GetCSVHeader() public static function GetCSVHeader()
{ {
return "Type,Operation,Arguments,StartTime,StopTime,Duration,Extension,InitialMemory,CurrentMemory,PeakMemory"; return 'Type,Operation,Arguments,StartTime,StopTime,Duration,Extension,InitialMemory,CurrentMemory,PeakMemory';
} }
/** /**
* Return the CSV line for the values * Return the CSV line for the values
*
* @return string * @return string
*/ */
public function GetCSV() public function GetCSV()
@@ -82,7 +84,8 @@ class KpiLogData
$sOperation = $this->RemoveQuotes($this->sOperation); $sOperation = $this->RemoveQuotes($this->sOperation);
$sArguments = $this->RemoveQuotes($this->sArguments); $sArguments = $this->RemoveQuotes($this->sArguments);
$sExtension = $this->RemoveQuotes($this->sExtension); $sExtension = $this->RemoveQuotes($this->sExtension);
return "\"$sType\",\"$sOperation\",\"$sArguments\",$this->fStartTime,$this->fStopTime,$this->fDuration,\"$sExtension\",$this->iInitialMemory,$this->iCurrentMemory,$this->iPeakMemory";
return "\"$sType\",\"$sOperation\",\"$sArguments\",$this->fStartTime,$this->fStopTime,$this->sDuration,\"$sExtension\",$this->iInitialMemory,$this->iCurrentMemory,$this->iPeakMemory";
} }
private function RemoveQuotes(string $sEntry): string private function RemoveQuotes(string $sEntry): string
@@ -100,6 +103,7 @@ class KpiLogData
if ($oOther->fStartTime > $this->fStartTime) { if ($oOther->fStartTime > $this->fStartTime) {
return -1; return -1;
} }
return 1; return 1;
} }