
后端【免费下载链接】monologSends your logs to files, sockets, inboxes, databases and various web services项目地址https://gitcode.com/gh_mirrors/mo/monolog点击查看免费下载Monolog 的SocketHandler允许你通过fsockopen()或pfsockopen()将日志直接写入任意 socket 端点是构建集中式日志收集、接入 syslog-ng / Fluentd / rsyslog 等日志服务时最常用的网络日志通道。本文以 doc/sockets.md 为主线结合 SocketHandler.php 源码与 SocketHandlerTest.php 测试用例完整讲解协议选择、持久连接、超时控制与写入原理读完即可在真实项目中落地可复用的 socket 日志方案。SocketHandler 能做什么SocketHandler是 Monolog 中面向「网络化日志」的通用处理器官方文档将其定位为「Logs records to sockets, use this for UNIX and TCP sockets」见 02-handlers-formatters-processors.md。它解决的核心问题是把日志记录从本地应用进程发送到另一个进程或远端服务器例如发送给本机/远程的syslog-ng、rsyslog、Fluentd等日志守护进程写入 Unix domain socket供同机其他服务消费通过 UDP 向日志收集端投递如 SyslogUdpHandler 基于 UDP 实现远程 syslog。从源码结构看SocketHandler继承自AbstractProcessingHandler因此它天然具备 Monolog 处理器栈的完整能力级别过滤isHandling、处理器级 processor、以及 formatter 格式化详见 AbstractProcessingHandler.php。每一条被处理的记录都会先被 formatter 格式化为字符串再通过 socket 写出。支持的连接协议TCP、UDP 与 Unix SocketSocketHandler默认使用TCP连接通过连接字符串前缀可以切换协议前缀协议连接字符串示例无前缀TCP默认localhost:514、tcp://127.0.0.1:9000unix://Unix domain socketunix:///var/log/httpd_app_log.socketudp://UDPudp://logs.example.com:12201这一设计对应源码中fsockopen($this-connectionString, -1, ...)与pfsockopen(...)的调用方式见 SocketHandler.phpPHP 的fsockopen原生支持在地址前加unix://打开 Unix socket、加udp://打开 UDP socketMonolog 直接复用了这套语法。由于 UDP 无连接语义官方提示 UDP 在isConnected()检查时可能看似已连接、写时才失败排障时需注意这一特性。基础示例写入 Unix Socket以下完整示例来自 doc/sockets.md创建一个向 Unix socket 写日志的 logger?php use Monolog\Logger; use Monolog\Handler\SocketHandler; // Create the logger $logger new Logger(my_logger); // Create the handler $handler new SocketHandler(unix:///var/log/httpd_app_log.socket); $handler-setPersistent(true); // Now add the handler $logger-pushHandler($handler, Level::Debug); // You can now use your logger $logger-info(My logger is now ready);提示Level::Debug是处理器的最小触发级别现代 Monolog 更推荐在构造函数中直接传入级别例如new SocketHandler(unix:///var/log/httpd_app_log.socket, Level::Debug)等价于调用setLevel()。pushHandler()只负责把处理器压入栈顶。使用 syslog-ng 作为接收端时你在日志服务器上应能看到如下记录cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []其中my_logger是 channel 名INFO是级别名末尾的[] []分别是空的 context 与 extra。该行格式来自默认的LineFormatter可通过 setFormatter 替换为 JSON、GELF 或 Fluentd 协议格式见下文「与 FluentdFormatter 组合」。构造函数参数与全部配置项SocketHandler的构造函数签名及默认值如下见 SocketHandler.phppublic function __construct( string $connectionString, // socket 连接串如 tcp://127.0.0.1:514 或 unix:///path/to.sock $level Level::Debug, // 最小日志级别 bool $bubble true, // 记录处理后是否继续向下冒泡给栈中其他 handler bool $persistent false, // 是否使用持久连接pfsockopen float $timeout 0.0, // 传输超时秒0 表示不限制 float $writingTimeout 10.0, // 写超时秒0 表示不限制 ?float $connectionTimeout null, // 连接超时秒null 时取 ini 的 default_socket_timeout ?int $chunkSize null // fwrite 写入块大小字节null 表示不设置 )此外每个参数都有对应的 getter/setter支持运行时动态调整validateTimeout()会拒绝负数并抛出InvalidArgumentException见 SocketHandler.php方法作用生效时机setPersistent(bool)/isPersistent()开关持久连接仅在连接建立前生效setConnectionTimeout(float)/getConnectionTimeout()连接建立超时仅在连接前生效setTimeout(float)/getTimeout()数据读取超时作用于整个流的stream_set_timeout仅在连接前生效setWritingTimeout(float)/getWritingTimeout()写入停滞超时防止写不出去时死循环连接后的写入阶段setChunkSize(int)/getChunkSize()设置stream_set_chunk_size的块大小连接后的写入阶段getConnectionString()读取当前连接串—持久连接persistent的意义文档明确指出持久 socket 主要在 Web 环境下有价值——每个 PHP-FPM 请求结束时关闭连接、下一个请求又重新建连的开销可以省去连接可跨请求复用。源码中的体现是close()方法的逻辑public function close(): void { if (!$this-isPersistent()) { $this-closeSocket(); } }即只有非持久连接才在close()时真正fclose()持久连接交由 PHP 进程生命周期管理见 SocketHandler.php。测试testCloseDoesNotClosePersistentSocket专门验证了这一点持久模式下close()后资源仍然存活见 SocketHandlerTest.php。持久连接由pfsockopen()建立SocketHandler.php普通连接则走fsockopen()。写入流程与底层原理SocketHandler继承自AbstractProcessingHandler一条日志的完整调用链是Logger::addRecord()生成LogRecordAbstractProcessingHandler::handle()先做级别过滤isHandling再运行处理器级 processors然后用 formatter 生成$record-formatted见 AbstractProcessingHandler.php调用SocketHandler::write($record)connectIfNotConnected()若isConnected()为假资源不存在或feof()已到 EOF说明对端关闭了连接则执行connect()connect()依次完成createSocketResource()fsockopen/pfsockopen→setSocketTimeout()stream_set_timeout→setStreamChunkSize()可选generateDataStream($record)返回(string) $record-formatted即 formatter 输出writeToSocket($data)循环写入。以上流程见 SocketHandler.php 与 SocketHandler.php。断线重连与可靠写入writeToSocket()是一个「边写边检」的循环每次fwrite后检查流元数据中的timed_out标志一旦超时立即抛RuntimeException(Write timed-out)如果写出的字节数持续不增长且超过了writingTimeout则主动closeSocket()并抛异常避免在写不出去的对端上无限循环见 SocketHandler.php。测试testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds专门用fwrite返回 0 的 mock 验证了该防护见 SocketHandlerTest.php。值得注意的健壮性设计连接失败fsockopen返回false抛UnexpectedValueException错误信息包含errno: errstr流超时设置失败、块大小设置失败同样抛UnexpectedValueExceptionfwrite返回false或写入中途对端 EOF均抛RuntimeException这些场景在测试套件中均有对应用例testExceptionIsThrownOnFsockopenError、testExceptionIsThrownOnPfsockopenError、testWriteFailsOnIfFwriteReturnsFalse、testWriteFailsIfStreamTimesOut、testWriteFailsOnIncompleteWrite等见 SocketHandlerTest.php。这带来的工程含义是当远端日志服务短暂不可用时socket 写日志会抛出异常并可能中断当前请求。如果不想让日志故障拖垮业务可以配合WhatFailureGroupHandler或FallbackGroupHandler包装见 02-handlers-formatters-processors.md 中关于远程 TCP 连接死亡的讨论。与 FluentdFormatter 组合接入 Fluentd 日志管道SocketHandler是接入 Fluentdtd-agent的推荐通道。仓库中的 FluentdFormatter.php 专门负责把LogRecord序列化为 Fluentd 的 unix socket 协议消息[tag, timestamp, message]三段式 JSON其类注释给出了完整的配套配置$logger new Monolog\Logger(fluent.tag); $fluentHandler new Monolog\Handler\SocketHandler(unix:///var/run/td-agent/td-agent.sock); $fluentHandler-setFormatter(new Monolog\Formatter\FluentdFormatter()); $logger-pushHandler($fluentHandler);对应的 Fluentd 端配置为source type unix path /var/run/td-agent/td-agent.sock /sourceFluentdFormatter构造参数$levelTag决定是否把日志级别拼进 tag如fluent.tag.warning关闭时则把level与level_name放入消息体见 FluentdFormatter.php。这也是 SocketHandler「通用 socket 通道 专用 formatter」组合能力的典型示范。UDP 场景SyslogUdpHandler 与 UdpSocket如果你需要的是标准的远程 syslogUDP 514Monolog 提供了更专业的 SyslogUdpHandler它内部使用 UdpSocketsocket_createsocket_sendto支持 RFC3164、RFC5424、RFC5424e 三种报文格式并且必须安装 PHP 的sockets扩展否则抛MissingExtensionException。一个容易被忽略的实战参数是$maxLengthUDP 数据报理论最大载荷为 65023 字节UdpSocket::DATAGRAM_MAX_LENGTH但如此大的报文会在 IP 层分片而很多路由器/防火墙会丢弃分片报文导致日志被静默丢弃。文档与源码注释建议按路径 MTU 设置如 1024UdpSocket会按maxLength - 头部长度截断消息见 UdpSocket.php相关截断行为由 UdpSocketTest.php 验证。排障要点小结验证连接串语法garbage://here这类非法地址会在首次写入时抛UnexpectedValueExceptiontestInvalidHostname用例确认接收端协议匹配TCP 用tcp://或裸 host:portUnix socket 必须加unix://前缀UDP 加udp://前缀检查超时配置负超时值会直接抛InvalidArgumentExceptionwritingTimeout建议保持默认 10 秒或调大防止大消息、慢对端场景下误判断线持久连接只影响连接生命周期setPersistent(true)必须在首次连接前调用且不会改变消息格式与超时行为。延伸阅读处理器/格式化器/处理器的完整清单02-handlers-formatters-processors.mdLogger 基本用法、channel 与处理器栈模型01-usage.mdSocketHandler 完整源码SocketHandler.phpSocketHandler 测试用例SocketHandlerTest.phpUDP syslog 实现SyslogUdpHandler.php 与 UdpSocket.phpFluentd 协议 formatterFluentdFormatter.php赞分享后端【免费下载链接】monologSends your logs to files, sockets, inboxes, databases and various web services项目地址https://gitcode.com/gh_mirrors/mo/monolog点击查看免费下载相关推荐Vector Socket Source 深度指南TCP、UDP 与 Unix Domain Socket 日志采集实战Vector Socket Source 深度指南TCP、UDP 与 Unix Domain Socket 日志采集实战 socket 是 Vector 内置可观测性数据工程数据集成日志分析Telegraf Socket Writer 输出插件完全指南通过 TCP/UDP/Unix Socket 发送指标数据Telegraf Socket Writer 输出插件完全指南通过 TCP/UDP/Unix Socket 发送指标数据 Socket Writer 是 Te可观测性指标监控运维Vector Socket Sink 深入解析通过 TCP、UDP 与 Unix 域套接字交付日志与指标Vector Socket Sink 深入解析通过 TCP、UDP 与 Unix 域套接字交付日志与指标 Vector 的 socket sink 是一个稳定可观测性数据工程数据集成日志分析上一篇开源监控利器Open-Falcon Agent下一篇推荐开源项目React-Component/Upload - 简洁高效的文件上传组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考