Redis Lua脚本中唯一能写入redis-server.log的是redis.log()函数,需指定WARNING及以上级别且配置loglevel匹配,拼接变量须用tostring()防nil错误,避免高频DEBUG日志影响性能。

Redis Lua脚本里不能用 print() 输出到服务端日志
直接在 Lua 脚本里写 print("debug"),输出只会进客户端响应或被静默丢弃,**完全不会落到 Redis 的 redis-server.log 里**。这是新手最常踩的坑——以为和本地调试一样,结果日志石沉大海。
根本原因:Redis 的 Lua 环境是沙箱化的,print 被重定向到了 Lua 栈,不是系统 stdout/stderr;服务端日志走的是 Redis 自己的日志系统,必须显式调用对应接口。
-
redis.log()是唯一能写入 Redis 日志文件的函数 - 它只接受两个参数:
level(日志级别)和message(字符串) - 不支持格式化占位符(如
%s),拼接得用.. - 消息长度超过 1024 字节会被截断,超长内容需手动分段
redis.log() 的可用日志级别和实际效果
Redis 支持 5 个级别,但只有 redis.LOG_WARNING 及以上(即 WARNING、NOTICE、VERBOSE、DEBUG)会真正写入日志文件,前提是 Redis 配置的 loglevel ≥ 对应级别。
例如:如果 redis.conf 中设了 loglevel notice,那么 redis.LOG_DEBUG 的日志就看不到;而 redis.LOG_WARNING 一定可见。
-
redis.LOG_DEBUG→ 对应配置loglevel debug,适合临时排障,上线前务必删掉或降级 -
redis.LOG_VERBOSE→ 比NOTICE更细,但部分 Redis 版本(如 6.0 之前)可能不识别,建议优先用NOTICE -
redis.LOG_WARNING→ 最稳妥的选择,生产环境可保留,不影响性能,也足够定位多数逻辑分支 - 避免用
redis.LOG_RAW:它绕过日志前缀(时间、级别等),格式混乱,且 Redis 7+ 已标记为 deprecated
正确拼接变量并防止 nil 报错的写法
Lua 脚本里变量可能是 nil,直接 .. 拼接会触发 attempt to concatenate a nil value 错误,整个脚本中断——这比没日志更糟。
必须对所有可能为 nil 的值做防御性处理,推荐统一转成字符串再拼接:
local key = KEYS[1]
local val = redis.call("GET", key)
redis.log(redis.LOG_WARNING, "key=" .. tostring(key) .. ", val=" .. tostring(val) .. ", type=" .. type(val))
-
tostring(nil)返回字符串"nil",安全 - 不要用
tonumber()或json.encode():Lua 沙箱里没有json库,tonumber()遇到非数字字符串会返回nil,又回到上一个问题 - 如果要打数组(如
ARGV),用table.concat(ARGV, "|"),但得先确保每个元素都tostring过
日志太多会拖慢脚本,尤其在高并发场景
redis.log() 不是免费的:每次调用都要加锁、格式化、写磁盘(取决于配置),在 QPS 上万的 Lua 脚本里频繁打 DEBUG 级日志,可能让延迟翻倍甚至触发慢日志告警。
- 上线前把所有
LOG_DEBUG改成LOG_WARNING或直接删掉 - 关键路径只记录「决策点」:比如
if ttl - 避免在循环内打日志,宁可在外层汇总后打一条
- 注意 Redis 日志文件滚动策略(
logfile+loglevel+ 外部 logrotate),否则磁盘可能被撑爆
真正难的不是“怎么打”,而是“打什么”和“什么时候停”。线上脚本的日志开关,最好能通过一个全局 key 控制,而不是硬编码——但这已经超出 Lua 本身能力,得靠外围机制配合。











