MediaMTX 日志配置实战:日志级别、多目标输出、JSONL 结构化日志与日志轮转
【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtx
MediaMTX 内置了一套轻量、可扩展的日志系统,通过logLevel、logDestinations、logFile、sysLogPrefix、logStructured等配置项即可在不重启编译的前提下完成日志级别控制、stdout / 文件 / syslog 多目标输出、JSONL 结构化日志以及基于 logrotate 的日志轮转。读完本文,你将掌握 MediaMTX 日志从"级别过滤—目标分发—结构化格式化—轮转归档"的完整链路,并能直接在生产环境中落地一套可查询、可采集、可归档的日志方案。
日志级别:用 logLevel 控制输出粒度
MediaMTX 提供 4 个日志级别,由配置项logLevel指定:
# Verbosity of the program; available values are "error", "warn", "info", "debug". logLevel: info| 取值 | 含义 | 典型场景 |
|---|---|---|
error | 仅输出错误 | 生产环境的最小化输出,适合日志量大、只关心故障的场景 |
warn | 输出警告与错误 | 关注潜在风险但不希望被常规信息刷屏 |
info | 输出常规信息、警告与错误(默认值) | 默认配置,记录服务启动、监听端口、连接会话等关键事件 |
debug | 输出全部日志(含调试信息) | 排查问题、分析推拉流细节时使用 |
从源码实现看,级别过滤发生在最前端的入口处:internal/logger/logger.go 的Log()方法首先执行if level < l.Level { return },低于配置级别的事件会被直接丢弃,不会进入任何输出目标,因此调整logLevel对性能的影响很小。级别常量定义在 internal/logger/level.go 中,按Debug → Info → Warn → Error递增;logLevel: info即意味着 Info、Warn、Error 三级事件都会被输出。级别字符串到内部枚举的解析由 internal/conf/log_level.go 完成,它同时支持 JSON 与环境变量两种反序列化方式,非法取值会直接报错invalid log level: 'xxx'。
根目录的默认配置文件 mediamtx.yml 中即采用logLevel: info;如果你希望控制台安静一些,可以改为logLevel: warn或logLevel: error。
日志输出目标:stdout / file / syslog 可组合
logDestinations决定日志写往哪些目标,它是一个数组,可以同时启用多个目标,事件会并发分发到所有已启用的目标:
# Destinations of log messages; available values are "stdout", "file" and "syslog". logDestinations: [file] # If "file" is in logDestinations, this is the file which will receive the logs. logFile: mediamtx.log默认情况下日志只打印到控制台(stdout)。可用的目标值在 internal/conf/log_destination.go 中定义并解析,三个合法值为stdout、file、syslog;在 internal/logger/logger.go 的Initialize()中,会按目标类型逐一创建对应的输出处理器:stdout 目标写入标准输出、file 目标打开指定文件、syslog 目标连接系统日志服务。目标列表也支持通过环境变量以逗号分隔传入,解析逻辑见 internal/conf/log_destinations.go。
写入文件:logFile
当logDestinations包含file时,日志会追加写入logFile指定的文件(默认mediamtx.log)。从 internal/logger/destination_file.go 可以看到,文件以O_APPEND|O_CREATE|O_WRONLY模式打开、权限为0644,因此进程启动时文件不存在会自动创建,且始终以追加方式写入,不会覆盖历史日志。日志器内部通过互斥锁串行化写入(见logger.go的mutex字段),保证多条日志并发产生时不会交错。
写入系统日志:syslog
当logDestinations包含syslog时,日志会发给系统日志服务:
# Destinations of log messages; available values are "stdout", "file" and "syslog". logDestinations: [syslog] # If "syslog" is in logDestinations, use prefix for logs. sysLogPrefix: mediamtxsysLogPrefix指定日志的标识前缀(默认mediamtx)。从 internal/logger/destination_syslog_other.go 的实现看,它调用syslog.New(syslog.LOG_DAEMON, prefix)连接系统 syslog(facility 为 daemon),并把四个日志级别分别映射为 syslog 的Debug / Info / Warning / Err方法;与 stdout、file 目标不同,syslog 目标只发送消息正文——时间戳和级别由 syslog 服务自身负责附加。注意该实现位于带!darwin && !windows构建标签的文件中,即 Linux 等 Unix 系平台可用,Windows 与 macOS 有各自的适配实现。
在 systemd 环境下,日志会进入 journald,可以通过标识符直接查询:
journalctl SYSLOG_IDENTIFIER=mediamtx以 systemd 服务运行时的日志查询
如果 MediaMTX 还以系统服务方式运行(配置方法见 17-start-on-boot.md),则可以借助 systemd 的 unit 名过滤全部日志,无需关心sysLogPrefix:
journalctl -u mediamtx这种方式会同时带出服务自身的启动、停止、崩溃等 systemd 事件与 MediaMTX 的输出日志,排查"服务为什么没起来"类问题非常高效。
结构化日志:logStructured 输出 JSONL
主流日志采集器(Loki、Logstash、CloudWatch、fluentd 等)在解析带固定字段的 JSON Lines(JSONL)时比解析自由文本可靠得多。MediaMTX 通过logStructured开启结构化输出:
# When destination is "stdout" or "file", emit logs in structured format (JSONL). logStructured: true开启后,每条日志是一个单行 JSON 对象,形如:
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[RTSP] listener opened on :8554 (TCP/RTSP), :8000 (UDP/RTP), :8001 (UDP/RTCP)"} {"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[RTMP] listener opened on :1935"} {"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[HLS] listener opened on :8888"} {"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[WebRTC] listener opened on :8889 (TCP/HTTP), :8189 (UDP/ICE)"} {"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[SRT] listener opened on :8890 (UDP)"}每个 JSON 对象包含三个字段:
timestamp:RFC3339Nano 格式的时间戳,精确到纳秒并含时区偏移(由 destination_stdout.go 与 destination_file.go 中的t.Format(time.RFC3339Nano)生成);level:级别缩写DEB/INF/WAR/ERR;message:经过转义的完整日志消息(含[RTSP]、[HLS]之类的协议模块前缀)。
结构化输出仅对stdout与file两个目标生效(配置注释与代码均如此规定);syslog 目标天然由系统日志服务结构化,因此不受影响。值得注意的是,非结构化模式下 stdout / file 输出的是YYYY/MM/DD HH:MM:SS INF message形式的纯文本,且 stdout 在连接终端时会自动着色(term.IsTerminal检测,见 destination_stdout.go),而写入文件与结构化模式不会带颜色。
日志文件轮转:借助 logrotate 归档旧日志
MediaMTX 自身不提供内置的日志分割机制,官方推荐使用外部工具定期轮转(rotate)或截断日志文件。在绝大多数 Linux 发行版上,这个任务由logrotate承担。只需在/etc/logrotate.d/mediamtx创建一个配置文件,内容如下:
/my/mediamtx/path/mediamtx.log { daily copytruncate rotate 7 compress delaycompress missingok notifempty }各指令含义:
daily:每天轮转一次;copytruncate:先复制当前文件内容再将其截断,进程不需要重启、也不影响 MediaMTX 持续持有的文件描述符,适合单写进程的日志文件;rotate 7:保留 7 份旧日志;compress:旧日志用 gzip 压缩以节省磁盘;delaycompress:最新一份旧日志延迟一个轮转周期再压缩,便于立即查阅;missingok:文件不存在时静默跳过,不报错;notifempty:文件为空时不轮转。
轮转后,旧日志会带上.1、.2、.3……的数字后缀:
mediamtx.log.1 mediamtx.log.2 mediamtx.log.3 ...如果你把logFile指向了其他路径(例如/var/log/mediamtx.log),记得同步修改 logrotate 配置文件中的路径,并在轮转策略中加入适当的权限与压缩设置。
配置热重载与日志器生命周期
日志配置并非一成不变:MediaMTX 支持配置文件变更热重载,日志器也会随重载重建。在 internal/core/core.go 中可以看到,检测到配置文件变化后会重新加载配置并重建各组件;日志器在 core.go 中通过"新建日志器 → 替换 → 关闭旧日志器"的方式平滑切换,期间旧的 file 句柄会被正确关闭。这意味着你可以在运行中把logLevel从info临时调低到debug排查问题,再调回info,无需重启进程。
小结与排查建议
- 日常运行保持
logLevel: info、logDestinations: [stdout]即可;需要审计留档时把file目标与 logrotate 组合使用,需要集中采集时开启logStructured: true并交给 Loki / Logstash / CloudWatch 等工具消费。 - 排查推拉流异常时,把
logLevel临时改为debug可看到最详细的事件链路;配合 syslog 目标与journalctl SYSLOG_IDENTIFIER=mediamtx(或 systemd 服务的journalctl -u mediamtx)可统一检索。 - 所有日志参数均定义于 internal/conf/conf.go,完整的默认值与注释可查看根目录 mediamtx.yml,更全面的配置说明见 1-configuration-file.md。
【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考