本文目录导读:

在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
最佳实践建议
- 分层监控:基础监控(CPU/内存)、应用监控(状态码/响应时间)、业务监控(订单量/用户量)
- 告警分级:Warning(注意)、Error(错误)、Critical(严重)
- 告警去重:避免重复告警,设置合理的告警间隔
- 日志分级:保留不同粒度的日志,便于问题定位
- 自动化恢复:配置自动重启、故障转移等策略
通过以上方案,可以构建一个完整的ThinkPHP监控告警体系,确保项目的稳定运行。