1. vLLM日志体系总览

日志,说白了就是系统的「黑匣子」。我做了这么多年运维,每次排查问题,第一件事就是翻日志。vLLM也不例外,它的日志体系设计得挺清晰,但如果你不了解它的「语言」,翻起来会很痛苦。

这一章,我带你把vLLM的日志体系从头捋一遍。从日志级别到格式,从输出到轮转,全给你讲透。

1.1 日志级别:从DEBUG到ERROR

vLLM的日志级别,跟Python标准库logging保持一致。一共四个级别,从低到高分别是:

级别 数值 什么时候出现 我的建议
DEBUG 10 开发调试、内部状态打印 生产环境别开,日志量太大
INFO 20 启动信息、请求统计、模型加载进度 日常监控用这个就够了
WARNING 30 配置不推荐、资源紧张、降级行为 需要关注,但不一定立即处理
ERROR 40 请求失败、OOM、模型加载失败 必须立刻处理

重要提醒:vLLM默认日志级别是INFO。我个人习惯在排查问题时临时切到DEBUG,排查完立刻切回来。否则日志文件一天能涨几个GB。

你可能会问:为什么没有FATAL或CRITICAL?嗯,vLLM的设计理念是「尽量优雅降级」。遇到严重错误时,它通常直接抛异常退出,而不是打一条FATAL日志继续跑。这一点跟很多Java框架不太一样。

1.2 日志格式解析:每一段都有含义

vLLM的日志格式长这样:

2025-03-15 14:32:18,123 INFO vllm.engine.llm_engine.py:456] Starting to load model 'meta-llama/Llama-2-7b-hf'...

拆开来看,一共五个部分:

  1. 时间戳2025-03-15 14:32:18,123,精确到毫秒。注意是本地时间,不是UTC。
  2. 日志级别INFO,固定5个字符宽度,对齐用的。
  3. 模块路径vllm.engine.llm_engine.py:456,文件名加行号。这个信息特别有用,我经常靠它定位到具体代码行。
  4. 分隔符],没什么特别含义,就是格式统一。
  5. 消息正文Starting to load model...,真正的日志内容。

小技巧:如果你用ELK或Splunk做日志聚合,建议把时间戳、级别、模块路径单独提取成字段。这样搜索起来快得多。我曾经在排查一个性能问题时,就是靠模块路径字段快速过滤出所有engine模块的日志,省了一半时间。

1.3 日志输出目标:stdout还是文件?

vLLM默认把日志打到标准输出(stdout)。这在容器化部署时很方便——docker logs直接能看到。但如果你需要持久化保存,就得配文件输出。

配置方式有两种:

  • 环境变量:设置VLLM_LOG_FILE=/var/log/vllm/server.log
  • 启动参数--log-file /var/log/vllm/server.log

我个人更推荐用环境变量。为什么?因为启动参数容易被遗忘,而环境变量可以写在Dockerfile或K8s的ConfigMap里,统一管理。

避坑指南:我曾经遇到过一个问题——同时设置了环境变量和启动参数,结果vLLM把日志打到了两个地方。排查了半天才发现是配置冲突。记住:启动参数优先级高于环境变量,但不要同时设置。

另外,vLLM的日志输出目标还有一个隐藏选项:syslog。不过这个功能目前还不太成熟,我试过一次,格式有点乱,不建议生产环境用。

1.4 日志轮转策略:别让日志撑爆磁盘

日志轮转,说白了就是「日志文件不能无限长大」。vLLM本身没有内置轮转机制,它依赖外部工具。常用的方案有两种:

方案一:Linux logrotate(推荐)

配置一个/etc/logrotate.d/vllm文件:

/var/log/vllm/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

解释一下关键参数:

  • daily:每天轮转一次
  • rotate 7:保留最近7天的日志
  • compress:轮转后压缩成.gz
  • copytruncate:这个很重要!vLLM打开文件后不会重新打开,所以不能用默认的create模式,必须用copytruncate,否则日志会丢失。

方案二:Docker日志驱动

如果你用容器部署,可以直接用Docker的日志驱动:

docker run --log-driver=json-file --log-opt max-size=100m --log-opt max-file=3 ...

这样每个日志文件最大100MB,保留3个文件。超过就自动删除最旧的。

我的经验:在K8s环境里,我一般用logrotate方案。因为Docker日志驱动在节点重启后可能丢失部分日志,而logrotate配合持久化存储更可靠。当然,如果你用EFK或Loki做日志收集,那日志轮转其实没那么重要——反正都发到远端了。

知识体系总览

下面这张图,把vLLM日志体系的四个核心维度串起来了。你可以把它当作本章的「地图」:

vLLM日志体系 总览 日志级别 DEBUG / INFO WARNING / ERROR 日志格式 时间戳 | 级别 | 模块 行号 | 消息正文 输出目标 stdout(默认) 文件 / syslog 轮转策略 logrotate Docker日志驱动

这张图你看懂了吗?四个维度互相独立,但又共同构成了完整的日志体系。你不需要一次性全记住,但遇到问题时,能快速定位到是哪个维度出了问题。

好了,第一章就到这里。日志体系是基础,后面几章我们会深入每个维度的实战技巧。记住:日志不是用来「看」的,是用来「查」的。掌握好它,你排查问题的速度能快一倍。


公众号:蓝海资料掘金营,微信deep3321