必须使用GELF协议将日志发送至Graylog,具体路径有四:一、Monolog+graylog/gelf-php直连;二、中间件拦截日志重定向;三、Filebeat采集文件转发;四、HTTP Input配合自定义推送器。

如果您使用ThinkPHP开发的应用需要将日志集中发送至Graylog进行统一分析与监控,则必须绕过默认的文件写入方式,改用GELF协议构造结构化日志并经UDP/TCP传输至Graylog服务端。以下是实现集成的具体路径:
一、通过Monolog + graylog/gelf-php扩展直连Graylog
此方法利用Monolog作为日志抽象层,结合graylog/gelf-php包构造标准GELF消息,确保字段完整、格式合规,适用于对日志上下文要求较高的生产环境。
1、执行Composer命令安装依赖:
composer require monolog/monolog graylog/gelf-php
2、在ThinkPHP的config/log.php中新增自定义通道配置,禁用默认file handler:
立即学习“PHP免费学习笔记(深入)”;
3、创建app/common/log/GelfHandler.php,继承Monolog\Handler\AbstractProcessingHandler,内部实例化\Gelf\Transport\UdpTransport并绑定Graylog服务IP与端口(如127.0.0.1:12201)
4、在handler的write方法中,将记录内容封装为\Gelf\Message对象,调用setLevel()传入\Gelf\Message::LEVEL_ERROR等常量,禁止使用字符串或数字
5、通过addAdditional()注入业务字段,键名须为纯字母+下划线组合(如trace_id、user_id),严禁含空格或点号
二、基于中间件拦截日志输出并重定向至Graylog
该方案不修改日志通道配置,而是在请求生命周期末尾捕获已生成的日志内容,解析其时间戳、级别、消息体后构造GELF包,适合无法改动log配置的遗留项目。
1、新建中间件app/middleware/GraylogLogMiddleware.php,在after方法中读取think\Log实例的缓冲日志数组
2、遍历每条日志,提取[date]、[type]、[content]三段原始文本,映射为GELF的timestamp、level、short_message
3、对[content]中可能存在的JSON结构尝试json_decode,成功则将其键值对通过addAdditional()批量注入
4、构造\Gelf\Sender并调用publish(),包裹try/catch防止网络异常阻塞响应
5、在app/middleware.php中全局注册该中间件,置于最后执行顺序
三、通过Filebeat采集runtime/log文件并转发至Graylog
此方式完全解耦应用代码,由外部轻量代理实时监控日志文件变更,适用于无法修改PHP逻辑、或需兼容多语言服务的混合架构场景。
1、确认ThinkPHP日志目录为runtime/log/,且文件命名含日期(如20260425.log)
2、编辑/etc/filebeat/filebeat.yml,在inputs节下添加filestream类型输入:
3、设置paths指向/path/to/thinkphp/runtime/log/*.log,启用close_inactive: 5m避免句柄泄漏
4、在output节配置graylog输出插件,指定hosts: ["127.0.0.1:12201"]及protocol: udp
5、启动Filebeat服务:
systemctl daemon-reload && systemctl enable filebeat && systemctl start filebeat
四、使用HTTP Input配合自定义日志推送器
当UDP/TCP端口受限或需穿透防火墙时,可启用Graylog的HTTP GELF Input,由PHP主动发起POST请求,兼顾可控性与部署灵活性。
1、在Graylog Web界面进入System > Inputs,创建新Input,类型选GELF HTTP,记下绑定地址(如http://127.0.0.1:12900/gelf)
2、在ThinkPHP中创建app/library/GraylogHttpSender.php,使用cURL构造POST请求,Header设置Content-Type: application/json
3、将日志数据序列化为GELF JSON对象,必填字段包括version(固定"1.1")、host($_SERVER['SERVER_NAME'])、short_message、timestamp(microtime(true))
4、通过_json字段嵌套原始日志结构,例如:
{"_level":"error","_request_id":"abc123","_ip":"192.168.1.100"}
5、在app/common.php中覆写think\facade\Log::record方法,调用该Sender异步发送(建议使用fastcgi_finish_request()释放连接)



















