ThinkPHP项目监控与告警集成

wen PHP项目 3

本文目录导读:

ThinkPHP项目监控与告警集成

  1. 性能监控
  2. 日志监控
  3. 异常监控
  4. 告警通知
  5. 集成管理平台
  6. 配置文件模板
  7. 启动脚本
  8. 最佳实践建议

在ThinkPHP项目中集成监控与告警系统,可以从以下几个方面进行:

性能监控

集成SkyWalking

// config/skywalking.php
return [
    'enabled' => env('SW_ENABLED', true),
    'service_name' => env('SW_SERVICE_NAME', 'thinkphp-app'),
    'server' => env('SW_SERVER', '127.0.0.1:11800'),
];
// app/middleware/SkyWalkingMiddleware.php
namespace app\middleware;
use Closure;
use think\Request;
class SkyWalkingMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        $startTime = microtime(true);
        $response = $next($request);
        // 记录请求耗时
        $duration = microtime(true) - $startTime;
        // 发送追踪数据到SkyWalking
        $this->sendTrace($request, $response, $duration);
        return $response;
    }
    private function sendTrace($request, $response, $duration)
    {
        // 集成SkyWalking SDK发送追踪数据
    }
}

使用Prometheus

// config/prometheus.php
return [
    'namespace' => 'thinkphp_app',
    'metrics' => [
        'http_requests_total',
        'http_request_duration_seconds',
    ],
];
// app/common/Collector.php
namespace app\common;
use Prometheus\CollectorRegistry;
use Prometheus\RenderTextFormat;
class Collector
{
    protected $registry;
    public function __construct()
    {
        // 初始化Registry
        $this->registry = new CollectorRegistry();
    }
    public function collect()
    {
        // 收集性能指标
        $counter = $this->registry->getOrRegisterCounter(
            'app', 'http_requests_total', 'Total requests', ['method', 'uri']
        );
        $counter->incBy(1, [request()->method(), request()->url()]);
    }
}

日志监控

配置日志系统

// config/log.php
return [
    'default' => env('log.channel', 'file'),
    'channels' => [
        'file' => [
            'type' => 'File',
            'path' => './runtime/log/',
            'level' => ['error', 'info', 'notice', 'warning'],
        ],
        'stdout' => [
            'type' => 'stdout',
            'level' => ['error'],
        ],
        // 集成日志服务
        'elasticsearch' => [
            'type' => 'custom',
            'class' => \app\log\ElasticsearchLogger::class,
            'hosts' => ['http://elasticsearch:9200'],
            'level' => ['error', 'warning'],
        ],
    ],
];

日志告警过滤器

// app/log/LogAlert.php
namespace app\log;
class LogAlert
{
    public function process($level, $message, $context)
    {
        // 错误日志级别
        if ($level == 'error' || $level == 'critical') {
            $this->sendAlert($level, $message, $context);
        }
        // 特定错误码
        if (isset($context['code']) && in_array($context['code'], [500, 502, 503])) {
            $this->sendAlert('http_error', $message, $context);
        }
        return $message;
    }
    private function sendAlert($level, $message, $context)
    {
        // 发送告警通知
        Notification::send($level, $message, $context);
    }
}

异常监控

全局异常处理

// app/ExceptionHandle.php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use Throwable;
class ExceptionHandle extends Handle
{
    protected $report = [
        // 需要报告的异常
        \think\exception\ErrorException::class,
        \think\exception\DbException::class,
    ];
    public function render($request, Throwable $e): Response
    {
        // 异常监控和告警
        $this->monitorException($e);
        return parent::render($request, $e);
    }
    protected function monitorException($e)
    {
        $data = [
            'message' => $e->getMessage(),
            'code' => $e->getCode(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTraceAsString(),
            'request_uri' => request()->url(),
            'request_method' => request()->method(),
        ];
        // 记录到监控系统
        Monitor::reportException($data);
        // 发送告警
        if ($e instanceof \ErrorException) {
            Alert::error('系统错误', $data);
        } elseif ($e instanceof \think\exception\DbException) {
            Alert::critical('数据库异常', $data);
        }
    }
}

数据库监控

// app/listener/DbQueryListener.php
namespace app\listener;
use think\facade\Db;
use think\facade\Event;
class DbQueryListener
{
    public function handle()
    {
        // 监听SQL执行
        Event::listen('db_query', function ($sql, $time) {
            // 慢查询监控
            if ($time > 1000) { // 超过1秒
                $this->reportSlowQuery($sql, $time);
            }
            // 记录查询日志
            Monitor::recordDbQuery($sql, $time);
        });
    }
    protected function reportSlowQuery($sql, $time)
    {
        Alert::warning('慢查询', [
            'sql' => $sql,
            'time' => $time,
            'uri' => request()->url(),
        ]);
    }
}

告警通知

通知服务接口

// app/service/AlertService.php
namespace app\service;
class AlertService
{
    protected $channels = [
        'email',
        'slack',
        'dingtalk',
        'wechat',
        'sms',
    ];
    public function send($level, $title, $content, $options = [])
    {
        $channels = $options['channels'] ?? ['email', 'slack'];
        foreach ($channels as $channel) {
            // 根据级别决定是否发送
            if (!$this->shouldSend($level, $channel)) {
                continue;
            }
            // 发送通知
            $this->{"sendTo" . ucfirst($channel)}($title, $content, $options);
        }
    }
    protected function shouldSend($level, $channel)
    {
        // 配置规则:某些级别只通过特定渠道发送
        $config = [
            'error' => ['email', 'slack', 'dingtalk'],
            'warning' => ['slack', 'dingtalk'],
            'info' => ['dingtalk'],
        ];
        return in_array($channel, $config[$level] ?? []);
    }
}

钉钉告警示例

// app/service/DingtalkAlert.php
namespace app\service;
class DingtalkAlert
{
    protected $webhook;
    public function __construct()
    {
        $this->webhook = env('DINGTALK_WEBHOOK');
    }
    public function send($title, $content, $mentioned = [])
    {
        $data = [
            'msgtype' => 'markdown',
            'markdown' => [
                'title' => $title,
                'text' => $content,
            ],
            'at' => [
                'atMobiles' => $mentioned,
                'isAtAll' => false,
            ],
        ];
        $result = Http::post($this->webhook, $data);
        return $result->successful();
    }
}

集成管理平台

Grafana监控面板配置

// public/grafana/dashboard.json
{
    "dashboard": {
        "templating": {
            "list": [
                {
                    "name": "app",
                    "query": "label_values(app)",
                    "type": "query"
                }
            ]
        },
        "panels": [
            {
                "title": "请求量",
                "type": "graph",
                "targets": [
                    {
                        "expr": "sum(rate(http_requests_total[5m])) by (app)",
                        "legendFormat": "{{app}}"
                    }
                ]
            },
            {
                "title": "错误率",
                "type": "graph",
                "targets": [
                    {
                        "expr": "sum(rate(http_errors_total[5m])) / sum(rate(http_requests_total[5m]))",
                        "legendFormat": "错误率"
                    }
                ]
            }
        ]
    }
}

健康检查接口

// app/controller/HealthCheck.php
namespace app\controller;
use think\Response;
use think\facade\Cache;
use think\facade\Db;
class HealthCheck
{
    public function index()
    {
        $checks = [
            'database' => $this->checkDatabase(),
            'cache' => $this->checkCache(),
            'storage' => $this->checkStorage(),
            'queue' => $this->checkQueue(),
        ];
        $status = !in_array(false, $checks);
        return json([
            'status' => $status ? 'UP' : 'DOWN',
            'checks' => $checks,
            'timestamp' => time(),
        ]);
    }
    protected function checkDatabase()
    {
        try {
            Db::query('SELECT 1');
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }
    protected function checkCache()
    {
        try {
            Cache::set('health_check', 'ok', 5);
            return Cache::get('health_check') === 'ok';
        } catch (\Exception $e) {
            return false;
        }
    }
}

配置文件模板

// config/monitoring.php
return [
    // 是否开启监控
    'enabled' => env('MONITORING_ENABLED', true),
    // 告警渠道配置
    'alert' => [
        'channels' => [
            'email' => [
                'enabled' => true,
                'hosts' => ['admin@example.com'],
                'level' => ['error', 'critical'],
            ],
            'dingtalk' => [
                'enabled' => true,
                'webhook' => env('DINGTALK_WEBHOOK'),
                'level' => ['error', 'warning'],
            ],
            'slack' => [
                'enabled' => false,
                'webhook' => env('SLACK_WEBHOOK'),
            ],
        ],
    ],
    // 性能阈值
    'threshold' => [
        'slow_query' => 1000,        // 慢查询时间(ms)
        'slow_request' => 3000,      // 慢请求时间(ms)
        'memory_limit' => 128 * 1024 * 1024,  // 内存限制
    ],
    // 监控指标
    'metrics' => [
        'enabled' => true,
        'prefix' => 'thinkphp_app',
        'collect' => [
            'status_code',
            'response_time',
            'db_query',
            'cache_hit',
        ],
    ],
];

启动脚本

#!/bin/bash
# bin/monitor.sh
# 启动监控服务
php think monitor:start &
# 检查健康状态
while true; do
    if curl -f http://localhost/health; then
        echo "$(date): System is healthy"
    else
        echo "$(date): System is unhealthy" | mail -s "Alert" admin@example.com
    fi
    sleep 60
done

最佳实践建议

  1. 分层监控:基础监控(CPU/内存)、应用监控(状态码/响应时间)、业务监控(订单量/用户量)
  2. 告警分级:Warning(注意)、Error(错误)、Critical(严重)
  3. 告警去重:避免重复告警,设置合理的告警间隔
  4. 日志分级:保留不同粒度的日志,便于问题定位
  5. 自动化恢复:配置自动重启、故障转移等策略

通过以上方案,可以构建一个完整的ThinkPHP监控告警体系,确保项目的稳定运行。

抱歉,评论功能暂时关闭!