Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 52 additions & 16 deletions CommonLogic/Monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
namespace exface\Core\CommonLogic;

use exface\Core\CommonLogic\Debugger\Profiler;
use exface\Core\DataTypes\PhpClassDataType;
use exface\Core\Events\Action\OnBeforeActionPerformedEvent;
use exface\Core\Events\Action\OnActionPerformedEvent;
use exface\Core\Exceptions\Actions\ActionRuntimeError;
use exface\Core\Facades\AbstractAjaxFacade\AbstractAjaxFacade;
use exface\Core\Interfaces\Tasks\HttpTaskInterface;
use exface\Core\Interfaces\WorkbenchInterface;
use exface\Core\Interfaces\Actions\ActionInterface;
use exface\Core\Interfaces\Actions\iReadData;
Expand Down Expand Up @@ -40,6 +44,12 @@ class Monitor extends Profiler

private $actionsEnabled = false;

private $longRunningActionsLogged = false;

private $longRunningActionsThreshold = 10;

private $longRunningActionsLevel = 'CRITICAL';

private $errorsEnabled = false;

/**
Expand All @@ -51,18 +61,24 @@ public function __construct(WorkbenchInterface $workbench, float $startTimeMs =
{
parent::__construct($workbench, $startTimeMs);
}

/**
*
*
* @param WorkbenchInterface $workbench
* @param float|null $startTimeMs
*/
public static function register(WorkbenchInterface $workbench, float $startTimeMs = null)
public static function register(WorkbenchInterface $workbench, float $startTimeMs = null) : void
{
$self = new self($workbench, $startTimeMs);
$config = $workbench->getConfig();

$self->actionsEnabled = $config->getOption('MONITOR.ACTIONS.ENABLED');
$self->errorsEnabled = $config->getOption('MONITOR.ERRORS.ENABLED');

$self->longRunningActionsLogged = $config->getOption('DEBUG.LOG_LONG_RUNNING_READS');
$self->longRunningActionsThreshold = $config->getOption('DEBUG.LOG_LONG_RUNNING_READS_THRESHOLD');
$self->longRunningActionsLevel = $config->getOption('DEBUG.LOG_LONG_RUNNING_READS_LEVEL');

// Do not monitor anything while installing the workbench
if ($workbench->isInstalled() === false) {
return;
Expand Down Expand Up @@ -157,7 +173,7 @@ public static function onCleanUp(OnCleanUpEvent $event)
* @param OnBeforeActionPerformedEvent $event
* @return void
*/
public function onActionStart(OnBeforeActionPerformedEvent $event)
public function onActionStart(OnBeforeActionPerformedEvent $event) : void
{
if (! $this->isActionMonitored($event->getAction())) {
return;
Expand All @@ -171,18 +187,33 @@ public function onActionStart(OnBeforeActionPerformedEvent $event)
* @param OnActionPerformedEvent $event
* @return void
*/
public function onActionStop(ActionEventInterface $event)
public function onActionStop(ActionEventInterface $event) : void
{
if (! $this->isActionMonitored($event->getAction())) {
$action = $event->getAction();

if (! $this->isActionMonitored($action)) {
return;
}

$ms = null;
if ($this->actionsEnabled) {
$ms = $this->stop($event->getAction())->getTimeTotalMs();
}
$this->addRowFromAction($event->getAction(), $event->getTask(), $ms);
return;
$ms = $this->stop($action)->getTimeTotalMs();
$s = $ms / 1000;

if($s > $this->longRunningActionsThreshold) {
$this->getWorkbench()->getLogger()->logException(new ActionRuntimeError(
$action,
'Action "' . $action->getName() . '" ran for ' . $s . 's!',
$this->longRunningActionsLevel
));
}
}

if($action instanceof iReadData) {
return;
}

$this->addRowFromAction($action, $event->getTask(), $ms);
}

/**
Expand Down Expand Up @@ -224,7 +255,8 @@ public function addLogIdToLastRowObject(string $ids) : void
protected function isActionMonitored(ActionInterface $action) : bool
{
switch (true) {
case $action instanceof iReadData:
// Ignore ReadData, unless we are logging long-running actions.
case $action instanceof iReadData && !$this->longRunningActionsLogged:
case $action instanceof UxonAutosuggest:
case $action instanceof ContextBarApi:
case $action instanceof ShowContextPopup:
Expand All @@ -233,12 +265,12 @@ protected function isActionMonitored(ActionInterface $action) : bool
return true;
}
}

/**
*
*
* @param ActionInterface $action
* @param TaskInterface $task
* @param float $duration
* @param TaskInterface $task
* @param float|null $duration
* @return Monitor
*/
protected function addRowFromAction(ActionInterface $action, TaskInterface $task, float $duration = null) : Monitor
Expand Down Expand Up @@ -323,8 +355,12 @@ protected function saveData() : Monitor
'USER' => $this->getWorkbench()->getSecurity()->getAuthenticatedUser()->getUid(),
'TIME' => $item['time'],
'DATE' => DateDataType::cast($item['time']),
'DURATION' => $this->getTimeTotalMs()
'DURATION' => $this->getTimeTotalMs(),
'TASK_CLASS' => PhpClassDataType::findClassNameWithoutNamespace($task),
'REQUEST_SIZE' => $task instanceof HttpTaskInterface ? $task->getHttpRequest()->getHeader('Content-Length')[0] : null,
'UI_FLAG' => $task->getFacade() instanceof AbstractAjaxFacade
]);

$ds->dataCreate();

$logIds = $item['logIds'];
Expand Down
31 changes: 17 additions & 14 deletions Config/System.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,25 @@
"DEBUG.SQL_FORMATTING_MAX_CHARS": 20000,
"DEBUG.AUTOMATIC_UXON_VALIDATION": true,
"DEBUG.MAINTENANCE_MODE": false,

"LOG.MINIMUM_LEVEL_TO_LOG": "debug",
"LOG.MAX_DAYS_TO_KEEP": "14",
"LOG.PERSIST_LOG_LEVEL": "critical",
"LOG.PASSTHROUGH_LOG_LEVEL": "error",
"DEBUG.LOG_LONG_RUNNING_READS": false,
"DEBUG.LOG_LONG_RUNNING_READS_THRESHOLD": 10,
"DEBUG.LOG_LONG_RUNNING_READS_LEVEL": "CRITICAL",

"LOG.MINIMUM_LEVEL_TO_LOG": "debug",
"LOG.MAX_DAYS_TO_KEEP": "14",
"LOG.PERSIST_LOG_LEVEL": "critical",
"LOG.PASSTHROUGH_LOG_LEVEL": "error",

"LOGIN.PROMPT.MESSAGES": [],
"MONITOR.ENABLED": true,
"MONITOR.ACTIONS.ENABLED": false,
"MONITOR.ACTIONS.DAYS_TO_KEEP": 30,
"MONITOR.ERRORS.ENABLED": true,
"MONITOR.ERRORS.MINIMUM_LEVEL_TO_LOG": "critical",
"MONITOR.ERRORS.DAYS_TO_KEEP": 30,
"FOLDERS.USERDATA_PATH_ABSOLUTE": "",

"MONITOR.ENABLED": true,
"MONITOR.ACTIONS.ENABLED": true,
"MONITOR.ACTIONS.DAYS_TO_KEEP": 30,
"MONITOR.ERRORS.ENABLED": true,
"MONITOR.ERRORS.MINIMUM_LEVEL_TO_LOG": "critical",
"MONITOR.ERRORS.DAYS_TO_KEEP": 30,
"FOLDERS.USERDATA_PATH_ABSOLUTE": "",
"FOLDERS.CACHE_PATH_ABSOLUTE": "",
"FOLDERS.BACKUP_PATH_ABSOLUTE": "",
"FOLDERS.LOGS_PATH_ABSOLUTE": "",
Expand Down
16 changes: 14 additions & 2 deletions Model/99_PAGE/exface.core.monitor.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"replaces_page_selector": null,
"created_by_user_selector": "0x31000000000000000000000000000000",
"created_on": "2020-11-17 13:30:20",
"modified_by_user_selector": "0x11edb424effd2980b424025041000001",
"modified_on": "2024-03-12 09:53:45",
"modified_by_user_selector": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"modified_on": "2026-02-06 11:46:25",
"icon": "tachometer",
"contents": {
"widget_type": "SplitVertical",
Expand Down Expand Up @@ -45,6 +45,12 @@
"value": 0,
"hidden": true
},
{
"attribute_alias": "MONITOR_ACTION__UI_FLAG",
"value": 0,
"comparator": "!==",
"apply_to_aggregates": true
},
{
"/*": "",
"hidden": true,
Expand Down Expand Up @@ -401,6 +407,12 @@
"apply_on_change": true,
"hidden": true
},
{
"attribute_alias": "UI_FLAG",
"comparator": "!==",
"value": 0,
"hidden": true
},
{
"attribute_alias": "ACTION_NAME"
},
Expand Down
152 changes: 152 additions & 0 deletions Model/exface.Core.MONITOR_ACTION/04_ATTRIBUTE.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,158 @@
"DEFAULT_VALUE": "",
"FIXED_VALUE": "",
"CUSTOM_DATA_TYPE": null
},
{
"_EXPORT_SUMMARY": "Task Class [TASK_CLASS]",
"CREATED_ON": "2026-01-29 10:53:24",
"MODIFIED_ON": "2026-01-29 10:55:05",
"CREATED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"MODIFIED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"UID": "0x11f09f045a3808dc9f047722c9cadff2",
"SORTABLEFLAG": 1,
"FILTERABLEFLAG": 1,
"AGGREGATABLEFLAG": 1,
"DEFAULT_AGGREGATE_FUNCTION": "",
"VALUE_LIST_DELIMITER": ",",
"READABLEFLAG": 1,
"WRITABLEFLAG": 1,
"SYSTEMFLAG": 0,
"DEFAULT_EDITOR_UXON": null,
"COPY_WITH_RELATED_OBJECT": 0,
"DELETE_WITH_RELATED_OBJECT": 0,
"DEFAULT_DISPLAY_UXON": null,
"COMMENTS": "",
"NAME": "Task Class",
"RELATION_CARDINALITY": "",
"TYPE": "D",
"COPYABLEFLAG": 1,
"ICON": "",
"ICON_SET": "",
"ABBREVIATION": "",
"ALIAS": "TASK_CLASS",
"DATATYPE": "0x30000000000000000000000000000000",
"DATA_ADDRESS": "task_class",
"OBJECT": "0x11eb830a07a3fc70830a025041000001",
"FORMATTER": "",
"DISPLAYORDER": null,
"LABELFLAG": 0,
"UIDFLAG": 0,
"HIDDENFLAG": 0,
"EDITABLEFLAG": 1,
"REQUIREDFLAG": 0,
"RELATED_OBJ": null,
"SORTERPOS": null,
"SORTERDIR": "",
"RELATED_OBJ_ATTR": null,
"SHORT_DESCRIPTION": "",
"DATA_ADDRESS_PROPS": null,
"DEFAULT_VALUE": "",
"FIXED_VALUE": "",
"CUSTOM_DATA_TYPE": {
"length_max": 100
}
},
{
"_EXPORT_SUMMARY": "Request Size [REQUEST_SIZE]",
"CREATED_ON": "2026-01-29 10:53:24",
"MODIFIED_ON": "2026-01-29 10:55:19",
"CREATED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"MODIFIED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"UID": "0x11f0a1ea5a38373aa1ea8d10d37f0bc3",
"SORTABLEFLAG": 1,
"FILTERABLEFLAG": 1,
"AGGREGATABLEFLAG": 1,
"DEFAULT_AGGREGATE_FUNCTION": "",
"VALUE_LIST_DELIMITER": ",",
"READABLEFLAG": 1,
"WRITABLEFLAG": 1,
"SYSTEMFLAG": 0,
"DEFAULT_EDITOR_UXON": null,
"COPY_WITH_RELATED_OBJECT": 0,
"DELETE_WITH_RELATED_OBJECT": 0,
"DEFAULT_DISPLAY_UXON": null,
"COMMENTS": "",
"NAME": "Request Size",
"RELATION_CARDINALITY": "",
"TYPE": "D",
"COPYABLEFLAG": 1,
"ICON": "",
"ICON_SET": "",
"ABBREVIATION": "",
"ALIAS": "REQUEST_SIZE",
"DATATYPE": "0x11e7b0277435425e98350205857feb80",
"DATA_ADDRESS": "request_size",
"OBJECT": "0x11eb830a07a3fc70830a025041000001",
"FORMATTER": "",
"DISPLAYORDER": null,
"LABELFLAG": 0,
"UIDFLAG": 0,
"HIDDENFLAG": 0,
"EDITABLEFLAG": 1,
"REQUIREDFLAG": 0,
"RELATED_OBJ": null,
"SORTERPOS": null,
"SORTERDIR": "",
"RELATED_OBJ_ATTR": null,
"SHORT_DESCRIPTION": "",
"DATA_ADDRESS_PROPS": null,
"DEFAULT_VALUE": "",
"FIXED_VALUE": "",
"CUSTOM_DATA_TYPE": null
},
{
"_EXPORT_SUMMARY": "UI Flag [UI_FLAG]",
"CREATED_ON": "2026-01-29 10:53:24",
"MODIFIED_ON": "2026-02-05 15:19:04",
"CREATED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"MODIFIED_BY_USER": "0x11e8fe1c902c8ebea23ee4b318306b9a",
"UID": "0x11f0af1d5a382380af1d635c9e1d6249",
"SORTABLEFLAG": 1,
"FILTERABLEFLAG": 1,
"AGGREGATABLEFLAG": 1,
"DEFAULT_AGGREGATE_FUNCTION": "",
"VALUE_LIST_DELIMITER": ",",
"READABLEFLAG": 1,
"WRITABLEFLAG": 1,
"SYSTEMFLAG": 0,
"DEFAULT_EDITOR_UXON": null,
"COPY_WITH_RELATED_OBJECT": 0,
"DELETE_WITH_RELATED_OBJECT": 0,
"DEFAULT_DISPLAY_UXON": null,
"COMMENTS": "",
"NAME": "UI Flag",
"RELATION_CARDINALITY": "",
"TYPE": "D",
"COPYABLEFLAG": 1,
"ICON": "",
"ICON_SET": "",
"ABBREVIATION": "",
"ALIAS": "UI_FLAG",
"DATATYPE": "0x11e7b0277435425e98350205857feb80",
"DATA_ADDRESS": [
"// Multiline text delimited by `\n`",
"(CASE",
" WHEN ui_flag IS NULL THEN -1",
" ELSE ui_flag",
"END)"
],
"OBJECT": "0x11eb830a07a3fc70830a025041000001",
"FORMATTER": "",
"DISPLAYORDER": null,
"LABELFLAG": 0,
"UIDFLAG": 0,
"HIDDENFLAG": 0,
"EDITABLEFLAG": 1,
"REQUIREDFLAG": 0,
"RELATED_OBJ": null,
"SORTERPOS": null,
"SORTERDIR": "",
"RELATED_OBJ_ATTR": null,
"SHORT_DESCRIPTION": "",
"DATA_ADDRESS_PROPS": null,
"DEFAULT_VALUE": "",
"FIXED_VALUE": "",
"CUSTOM_DATA_TYPE": null
}
],
"totals_rows": [],
Expand Down