|
|
@@ -0,0 +1,129 @@
|
|
|
+<?php defined('BX_DOL') or defined('BX_DOL_INSTALL') or die('hack attempt');
|
|
|
+/**
|
|
|
+ * Copyright (c) UNA, Inc - https://una.io
|
|
|
+ * MIT License - https://opensource.org/licenses/MIT
|
|
|
+ *
|
|
|
+ * @defgroup UnaCore UNA Core
|
|
|
+ * @{
|
|
|
+ */
|
|
|
+
|
|
|
+class BxDolAlertsStats extends BxDol
|
|
|
+{
|
|
|
+ private static array $logs = [];
|
|
|
+ private static array $stats = [];
|
|
|
+ private static bool $registered = false;
|
|
|
+
|
|
|
+ public static function log(object $oAlert): void
|
|
|
+ {
|
|
|
+ if (!self::$registered) {
|
|
|
+ self::$registered = true;
|
|
|
+ register_shutdown_function([self::class, 'flush']);
|
|
|
+ }
|
|
|
+
|
|
|
+ $s = $oAlert->sUnit . ':' . $oAlert->sAction;
|
|
|
+ if (!isset(self::$logs[$s])) {
|
|
|
+ self::$logs[$s] = [
|
|
|
+ 'unit' => $oAlert->sUnit,
|
|
|
+ 'action' => $oAlert->sAction,
|
|
|
+ 'object' => $oAlert->iObject,
|
|
|
+ 'sender' => $oAlert->iSender,
|
|
|
+ 'extra' => $oAlert->aExtras,
|
|
|
+ 'counter' => 1,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self::$logs[$s]['counter']++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function hit(string $hookName, float $timing): void
|
|
|
+ {
|
|
|
+ if (!self::$registered) {
|
|
|
+ self::$registered = true;
|
|
|
+ register_shutdown_function([self::class, 'flush']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isset(self::$stats[$hookName])) {
|
|
|
+ self::$stats[$hookName] = [
|
|
|
+ 'count' => 0,
|
|
|
+ 'last' => time(),
|
|
|
+ 'timing' => $timing,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ self::$stats[$hookName]['count']++;
|
|
|
+ self::$stats[$hookName]['last'] = time();
|
|
|
+ self::$stats[$hookName]['timing'] += $timing;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function flush(): void
|
|
|
+ {
|
|
|
+ self::flushStats();
|
|
|
+ self::flushLogs();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function flushStats(): void
|
|
|
+ {
|
|
|
+ if (!self::$stats)
|
|
|
+ return;
|
|
|
+
|
|
|
+ foreach (self::$stats as $hookName => $data) {
|
|
|
+
|
|
|
+ $sql = "
|
|
|
+ UPDATE `sys_alerts_handlers`
|
|
|
+ SET
|
|
|
+ `ts` = :last,
|
|
|
+ `timing` = :timing,
|
|
|
+ `call_count` = call_count + :count,
|
|
|
+ `calls_per_request` = GREATEST(`calls_per_request`, :count)
|
|
|
+ WHERE `name` = :name
|
|
|
+ ";
|
|
|
+
|
|
|
+ BxDolDb::getInstance()->query($sql, [
|
|
|
+ 'count' => $data['count'],
|
|
|
+ 'last' => $data['last'],
|
|
|
+ 'timing' => $data['timing'],
|
|
|
+ 'name' => $hookName,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function flushLogs(): void
|
|
|
+ {
|
|
|
+ if (!self::$logs)
|
|
|
+ return;
|
|
|
+
|
|
|
+ foreach (self::$logs as $s => $data) {
|
|
|
+ $aExtraRefs = [];
|
|
|
+ foreach($data['extra'] as $sKey => $mixedValue) {
|
|
|
+ if (preg_match('/^(ref|override|return)_/', $sKey) || preg_match('/_(ref|override|return)$/', $sKey) || $sKey == 'result' || $sKey == 'res' || $sKey == 'return' || $sKey == 'ret' || $sKey == 'check_result') {
|
|
|
+ self::$logs[$s]['extra_refs'][] = $sKey;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ self::$logs[$s]['extra_refs'] = json_encode(self::$logs[$s]['extra_refs'] ?? []);
|
|
|
+ self::$logs[$s]['extra'] = json_encode(self::$logs[$s]['extra']);
|
|
|
+
|
|
|
+ BxDolDb::getInstance()->query("
|
|
|
+ INSERT INTO sys_alerts_log
|
|
|
+ SET
|
|
|
+ unit = :unit,
|
|
|
+ action = :action,
|
|
|
+ object = :object,
|
|
|
+ sender = :sender,
|
|
|
+ extra = :extra,
|
|
|
+ extra_refs = :extra_refs,
|
|
|
+ ts = UNIX_TIMESTAMP(),
|
|
|
+ counter_total = :counter,
|
|
|
+ counter_24h = :counter,
|
|
|
+ counter_per_request = :counter
|
|
|
+ ON DUPLICATE KEY UPDATE
|
|
|
+ ts = UNIX_TIMESTAMP(),
|
|
|
+ counter_total = counter_total + :counter,
|
|
|
+ counter_24h = counter_24h + :counter,
|
|
|
+ counter_per_request = GREATEST(counter_per_request, :counter)
|
|
|
+ ", self::$logs[$s]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** @} */
|