BxDolAlertsStats.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php defined('BX_DOL') or defined('BX_DOL_INSTALL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. class BxDolAlertsStats extends BxDol
  10. {
  11. private static array $logs = [];
  12. private static array $stats = [];
  13. private static bool $registered = false;
  14. public static function log(object $oAlert): void
  15. {
  16. if (!self::$registered) {
  17. self::$registered = true;
  18. register_shutdown_function([self::class, 'flush']);
  19. }
  20. $s = $oAlert->sUnit . ':' . $oAlert->sAction;
  21. if (!isset(self::$logs[$s])) {
  22. self::$logs[$s] = [
  23. 'unit' => $oAlert->sUnit,
  24. 'action' => $oAlert->sAction,
  25. 'object' => $oAlert->iObject,
  26. 'sender' => $oAlert->iSender,
  27. 'extra' => $oAlert->aExtras,
  28. 'counter' => 1,
  29. ];
  30. }
  31. else {
  32. self::$logs[$s]['counter']++;
  33. }
  34. }
  35. public static function hit(string $hookName, float $timing): void
  36. {
  37. if (!self::$registered) {
  38. self::$registered = true;
  39. register_shutdown_function([self::class, 'flush']);
  40. }
  41. if (!isset(self::$stats[$hookName])) {
  42. self::$stats[$hookName] = [
  43. 'count' => 0,
  44. 'last' => time(),
  45. 'timing' => $timing,
  46. ];
  47. }
  48. self::$stats[$hookName]['count']++;
  49. self::$stats[$hookName]['last'] = time();
  50. self::$stats[$hookName]['timing'] += $timing;
  51. }
  52. public static function flush(): void
  53. {
  54. self::flushStats();
  55. self::flushLogs();
  56. }
  57. public static function flushStats(): void
  58. {
  59. if (!self::$stats || !getParam('sys_alerts_stats'))
  60. return;
  61. foreach (self::$stats as $hookName => $data) {
  62. $sql = "
  63. UPDATE `sys_alerts_handlers`
  64. SET
  65. `ts` = :last,
  66. `timing` = :timing,
  67. `call_count` = call_count + :count,
  68. `calls_per_request` = GREATEST(`calls_per_request`, :count)
  69. WHERE `name` = :name
  70. ";
  71. BxDolDb::getInstance()->query($sql, [
  72. 'count' => $data['count'],
  73. 'last' => $data['last'],
  74. 'timing' => $data['timing'],
  75. 'name' => $hookName,
  76. ]);
  77. }
  78. }
  79. public static function flushLogs(): void
  80. {
  81. if (!self::$logs)
  82. return;
  83. $oDb = BxDolDb::getInstance();
  84. if (!getParam('sys_alerts_stats'))
  85. $aMap = $oDb->getPairs('SELECT CONCAT(unit, ":", action) AS `key`, 1 AS `val` FROM sys_alerts_log', 'key', 'val');
  86. foreach (self::$logs as $s => $data) {
  87. $aExtraRefs = [];
  88. foreach($data['extra'] as $sKey => $mixedValue) {
  89. if (preg_match('/^(ref|override|return)_/', $sKey) || preg_match('/_(ref|override|return)$/', $sKey) || $sKey == 'result' || $sKey == 'res' || $sKey == 'return' || $sKey == 'ret' || $sKey == 'check_result') {
  90. self::$logs[$s]['extra_refs'][] = $sKey;
  91. }
  92. }
  93. self::$logs[$s]['extra_refs'] = json_encode(self::$logs[$s]['extra_refs'] ?? []);
  94. self::$logs[$s]['extra'] = json_encode(self::$logs[$s]['extra']);
  95. if (getParam('sys_alerts_stats')) {
  96. $oDb->query("
  97. INSERT INTO sys_alerts_log
  98. SET
  99. unit = :unit,
  100. action = :action,
  101. object = :object,
  102. sender = :sender,
  103. extra = :extra,
  104. extra_refs = :extra_refs,
  105. ts = UNIX_TIMESTAMP(),
  106. counter_total = :counter,
  107. counter_24h = :counter,
  108. counter_per_request = :counter
  109. ON DUPLICATE KEY UPDATE
  110. ts = UNIX_TIMESTAMP(),
  111. counter_total = counter_total + :counter,
  112. counter_24h = counter_24h + :counter,
  113. counter_per_request = GREATEST(counter_per_request, :counter)
  114. ", self::$logs[$s]);
  115. } else {
  116. $sKey = self::$logs[$s]['unit'] . ':' . self::$logs[$s]['action'];
  117. if (!isset($aMap[$sKey])) {
  118. $oDb->query("
  119. INSERT IGNORE INTO sys_alerts_log
  120. SET
  121. unit = :unit,
  122. action = :action,
  123. object = :object,
  124. sender = :sender,
  125. extra = :extra,
  126. extra_refs = :extra_refs,
  127. ts = 0,
  128. counter_per_request = :counter
  129. ", self::$logs[$s]);
  130. }
  131. }
  132. }
  133. }
  134. }
  135. /** @} */