...
This commit is contained in:
14
src/etc/php/8.3/fpm/pool.d/www-zabbix.conf
Normal file
14
src/etc/php/8.3/fpm/pool.d/www-zabbix.conf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
; Zabbix PHP Exception Monitoring - www pool override
|
||||||
|
; This file modifies the default www pool to include Zabbix exception monitoring
|
||||||
|
; Place this file AFTER the www.conf is loaded (higher number or 'z' prefix)
|
||||||
|
|
||||||
|
[www]
|
||||||
|
; Add Zabbix PHP Exception Handler to existing www pool
|
||||||
|
; This will override any previous auto_prepend_file setting
|
||||||
|
php_admin_value[auto_prepend_file] = /usr/lib/zabbix-php.php
|
||||||
|
|
||||||
|
; Ensure error logging is enabled
|
||||||
|
php_admin_value[log_errors] = On
|
||||||
|
|
||||||
|
; Optional: Set custom error log location
|
||||||
|
; php_admin_value[error_log] = /var/log/php/www-error.log
|
||||||
44
src/etc/zabbix/zabbix_agentd.d/php-exceptions.conf
Normal file
44
src/etc/zabbix/zabbix_agentd.d/php-exceptions.conf
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Zabbix Agent configuration for PHP Exception Monitoring
|
||||||
|
# UserParameter ohne jq-Abhängigkeit für passive checks
|
||||||
|
|
||||||
|
# Vollständigen Log-Inhalt lesen (für neue Einträge)
|
||||||
|
UserParameter=php.exception.log.content,cat /var/log/zabbix/php.exceptions.log 2>/dev/null || echo ""
|
||||||
|
|
||||||
|
# Neueste Exception (letzte Zeile)
|
||||||
|
UserParameter=php.exception.latest,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null || echo ""
|
||||||
|
|
||||||
|
# Get last exception timestamp (mit jq)
|
||||||
|
UserParameter=php.exception.last,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null | jq -r '.timestamp // "never"' 2>/dev/null || echo "never"
|
||||||
|
|
||||||
|
# Get last exception message (mit jq)
|
||||||
|
UserParameter=php.exception.message,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null | jq -r '.message // ""' 2>/dev/null || echo ""
|
||||||
|
|
||||||
|
# Get last exception file (mit jq)
|
||||||
|
UserParameter=php.exception.file,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null | jq -r '.file // ""' 2>/dev/null || echo ""
|
||||||
|
|
||||||
|
# Get last exception line (mit jq)
|
||||||
|
UserParameter=php.exception.line,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null | jq -r '.line // 0' 2>/dev/null || echo "0"
|
||||||
|
|
||||||
|
# Get last exception unique_id (mit jq)
|
||||||
|
UserParameter=php.exception.unique_id,tail -n 1 /var/log/zabbix/php.exceptions.log 2>/dev/null | jq -r '.unique_id // ""' 2>/dev/null || echo ""
|
||||||
|
|
||||||
|
# Count recent exceptions (last hour)
|
||||||
|
UserParameter=php.exception.count.hour,awk -v since="$(date -d '1 hour ago' '+%Y-%m-%d %H:%M:%S')" '$0 > since' /var/log/zabbix/php.exceptions.log 2>/dev/null | wc -l
|
||||||
|
|
||||||
|
# Count recent exceptions (last 24 hours)
|
||||||
|
UserParameter=php.exception.count.day,awk -v since="$(date -d '1 day ago' '+%Y-%m-%d %H:%M:%S')" '$0 > since' /var/log/zabbix/php.exceptions.log 2>/dev/null | wc -l
|
||||||
|
|
||||||
|
# Log-Datei Größe (für Änderungsüberwachung)
|
||||||
|
UserParameter=php.exception.log.size,stat -c%s /var/log/zabbix/php.exceptions.log 2>/dev/null || echo "0"
|
||||||
|
|
||||||
|
# Letzte Änderungszeit der Log-Datei
|
||||||
|
UserParameter=php.exception.log.mtime,stat -c%Y /var/log/zabbix/php.exceptions.log 2>/dev/null || echo "0"
|
||||||
|
|
||||||
|
# Anzahl Zeilen in Log-Datei
|
||||||
|
UserParameter=php.exception.log.lines,wc -l < /var/log/zabbix/php.exceptions.log 2>/dev/null || echo "0"
|
||||||
|
|
||||||
|
# Check ob Log-Datei existiert und lesbar ist
|
||||||
|
UserParameter=php.exception.log.accessible,[ -r /var/log/zabbix/php.exceptions.log ] && echo "1" || echo "0"
|
||||||
|
|
||||||
|
# Check if PHP exception handler is active
|
||||||
|
# UserParameter=php.exception.handler.active,php -r "echo (class_exists('ZabbixPHPExceptionHandler') ? 1 : 0);" 2>/dev/null || echo "0"
|
||||||
@@ -72,7 +72,7 @@ class ZabbixPHPExceptionHandler {
|
|||||||
|
|
||||||
// Get HTTP_HOST or set default
|
// Get HTTP_HOST or set default
|
||||||
$httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] :
|
$httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] :
|
||||||
(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'cli');
|
(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'cli');
|
||||||
|
|
||||||
// Create unique identifier for deduplication
|
// Create unique identifier for deduplication
|
||||||
$uniqueId = md5($httpHost . '|' . $exception->getFile() . '|' . $exception->getLine() . '|' . $exception->getMessage());
|
$uniqueId = md5($httpHost . '|' . $exception->getFile() . '|' . $exception->getLine() . '|' . $exception->getMessage());
|
||||||
@@ -84,7 +84,7 @@ class ZabbixPHPExceptionHandler {
|
|||||||
'file' => $exception->getFile(),
|
'file' => $exception->getFile(),
|
||||||
'line' => $exception->getLine(),
|
'line' => $exception->getLine(),
|
||||||
'message' => $exception->getMessage(),
|
'message' => $exception->getMessage(),
|
||||||
'stacktrace' => $exception->getTraceAsString(),
|
'stacktrace' => self::makePrettyException($exception),
|
||||||
'unique_id' => $uniqueId,
|
'unique_id' => $uniqueId,
|
||||||
'request_uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '',
|
'request_uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '',
|
||||||
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
|
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
|
||||||
@@ -110,8 +110,43 @@ class ZabbixPHPExceptionHandler {
|
|||||||
error_log("Zabbix PHP Exception Handler failed: " . $e->getMessage());
|
error_log("Zabbix PHP Exception Handler failed: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static function makePrettyException(Throwable $e) {
|
||||||
|
$ret=["# Exception: {$e->getMessage()}", "Traceback (most recent call last) "];
|
||||||
|
foreach((array)$e->getTrace() as $index => $trace){
|
||||||
|
$o=[];
|
||||||
|
$result = "* #{$index} @ File: {$trace['file']}:{$trace['line']} - ";
|
||||||
|
if(!empty($trace['class'])) {
|
||||||
|
$result .= $trace['class'];
|
||||||
|
$result .= '->';
|
||||||
|
}
|
||||||
|
if(!empty($trace['function'])){
|
||||||
|
$result .= $trace['function'];
|
||||||
|
$result .= '();';
|
||||||
|
}
|
||||||
|
if(!empty($trace['file'])){
|
||||||
|
$von = intval($trace['line']) - 8;
|
||||||
|
$von = max($von, 1);
|
||||||
|
$bis = intval($trace['line']) + 8;
|
||||||
|
exec("sed -n '{$von},{$bis}p' {$trace['file']}", $o, $e);
|
||||||
|
if(!$e && $o){
|
||||||
|
$result .= "\n";
|
||||||
|
# $result.="\n<code>\n";
|
||||||
|
foreach($o as $line => $_){
|
||||||
|
$result.=str_pad(strval($line+$von), 6, " ", \STR_PAD_LEFT) .": $_\n";
|
||||||
|
}
|
||||||
|
# $result.='</code>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret[]=$result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return join("\n", $ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Initialize the exception handler
|
// Initialize the exception handler
|
||||||
ZabbixPHPExceptionHandler::init();
|
ZabbixPHPExceptionHandler::init();
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ zabbix_export:
|
|||||||
var formattedStack = 'No stacktrace available';
|
var formattedStack = 'No stacktrace available';
|
||||||
if (entry.stacktrace && entry.stacktrace.length > 0) {
|
if (entry.stacktrace && entry.stacktrace.length > 0) {
|
||||||
formattedStack = entry.stacktrace.split('\n').map(function(line, index) {
|
formattedStack = entry.stacktrace.split('\n').map(function(line, index) {
|
||||||
return (index + 1) + ': ' + line.trim();
|
// return (index + 1) + ': ' + line.trim();
|
||||||
|
return line.trim();
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,27 +68,34 @@ zabbix_export:
|
|||||||
event_name: 'New PHP Exception Logged'
|
event_name: 'New PHP Exception Logged'
|
||||||
priority: HIGH
|
priority: HIGH
|
||||||
description: |
|
description: |
|
||||||
===============================================
|
🚨 PHP EXCEPTION DETECTED 🚨
|
||||||
PHP EXCEPTION DETAILS
|
═══════════════════════════════════════════════════════
|
||||||
===============================================
|
|
||||||
|
|
||||||
Raw Exception Data:
|
📊 FORMATTED EXCEPTION DATA:
|
||||||
{ITEM.LASTVALUE}
|
{ITEM.LASTVALUE}
|
||||||
|
|
||||||
===============================================
|
═══════════════════════════════════════════════════════
|
||||||
STACKTRACE AND FULL DETAILS
|
🔍 QUICK ACCESS LINKS:
|
||||||
===============================================
|
|
||||||
|
|
||||||
This section contains the complete exception information including:
|
• Latest Data: Monitoring → Latest Data → {HOST.NAME}
|
||||||
- Exception message and location
|
• Full History: Monitoring → Latest Data → "PHP Exception Monitor"
|
||||||
- Full stacktrace with line numbers
|
• Host Overview: Monitoring → Hosts → {HOST.NAME}
|
||||||
- Request context (host, URI, user agent)
|
|
||||||
- Unique identifier for deduplication
|
|
||||||
- Timestamp of occurrence
|
|
||||||
|
|
||||||
Click on "Latest Data" for this item to see the formatted JSON.
|
═══════════════════════════════════════════════════════
|
||||||
|
ℹ️ INFORMATION:
|
||||||
|
|
||||||
Note: This alert requires manual acknowledgment.
|
This alert contains the complete exception details including:
|
||||||
|
✓ Exception message and exact location
|
||||||
|
✓ Full stacktrace with numbered lines
|
||||||
|
✓ Request context (host, URI, headers)
|
||||||
|
✓ Unique identifier for correlation
|
||||||
|
✓ Exact timestamp of occurrence
|
||||||
|
|
||||||
|
⚠️ ACTION REQUIRED: This alert requires manual acknowledgment.
|
||||||
|
Use "Actions" → "Close" to dismiss after reviewing.
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════
|
||||||
|
Host: {HOST.NAME} | Time: {EVENT.TIME} | Severity: {TRIGGER.SEVERITY}
|
||||||
manual_close: 'YES'
|
manual_close: 'YES'
|
||||||
tags:
|
tags:
|
||||||
- tag: scope
|
- tag: scope
|
||||||
|
|||||||
Reference in New Issue
Block a user