当前位置:首页 > 文章列表 > Golang > Go教程 > Go slog.NewJSONHandler 怎样输出结构化 JSON 日志

Go slog.NewJSONHandler 怎样输出结构化 JSON 日志

来源:17golang原创 2026-10-29 09:43:16 0浏览 收藏

如果 Go 服务的日志要交给采集系统按字段检索,关键不是把字符串拼成“看起来像 JSON”,而是让日志记录由标准库统一编码。slog.NewJSONHandler 会把每次日志调用写成一行 JSON 对象,再交给指定的 io.Writer。这样 level、msg 和业务属性都能保持字段边界。

官方文档:https://pkg.go.dev/log/slog

小型服务可以从 os.Stdout 加默认选项开始;进入生产采集后,再按日志量、来源定位和敏感字段要求配置 Level、AddSource 与 ReplaceAttr。

先把 JSON 日志的输入与输出边界定下来

NewJSONHandler(w, opts) 接收一个输出目标和可选配置,返回实现了 slog.Handler 的 JSON 处理器。opts 传 nil 时使用默认选项;处理器负责把记录编码成逐行 JSON,而不是让业务代码自己拼接引号、逗号和转义符。

下面的初始化把应用日志绑定到标准输出。标准输出只是一个 Writer 选择,容器运行时、日志代理或本地进程可以在边界外继续接收它:

package main

import (
    "log/slog"
    "os"
)

func newLogger() *slog.Logger {
    // nil 使用默认 HandlerOptions,适合先建立最小 JSON 输出边界。
    handler := slog.NewJSONHandler(os.Stdout, nil)
    return slog.New(handler)
}

func main() {
    logger := newLogger()
    // 键值属性会成为 JSON 字段,调用方不需要拼接 JSON 字符串。
    logger.Info("请求完成", "request_id", "req-42", "status", 200)
}

架构上可以把它拆成三层:业务调用方产生 Record,JSONHandler 负责编码,io.Writer 负责承接结果。这样将来把输出从标准输出换成文件或自定义 Writer 时,业务日志调用不必跟着改。

slog.Logger、JSONHandler、HandlerOptions、Record、逐行 JSON 对象和 io.Writer 的静态关系说明图
图1:slog.Logger 经过 JSONHandler 写入 io.Writer 的输出边界说明图,展示结构化日志的静态关系,不是截图。

按采集负载配置 HandlerOptions

默认配置能输出 JSON,但生产环境通常需要先做三项决策。Level 决定最低记录级别;低于它的记录会被处理器忽略。AddSource 会增加日志调用位置,适合排查问题但会带来额外字段和定位开销。ReplaceAttr 则可以重命名、改写或丢弃属性,包括内置的 time、level、source 和 msg。

package main

import (
    "log/slog"
    "os"
    "strings"
)

func newProductionLogger() *slog.Logger {
    options := &slog.HandlerOptions{
        Level:     slog.LevelInfo,
        AddSource: true,
        ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr {
            // 只示意脱敏边界:不要把令牌、密码等原始值写入日志。
            if strings.EqualFold(attr.Key, "token") || strings.EqualFold(attr.Key, "password") {
                return slog.String(attr.Key, "[REDACTED]")
            }
            return attr
        },
    }
    // Writer 决定日志交给哪里,选项决定写出哪些字段。
    return slog.New(slog.NewJSONHandler(os.Stdout, options))
}

脱敏函数要按你的字段命名规范扩展,并考虑分组属性;不能只依赖“调用方自觉不打印”。如果开启 AddSource,先确认采集端允许并索引该字段;如果日志量很大,可以让 LevelVar 参与动态调节,而不是把所有调试信息长期写入生产出口。

HandlerOptions、Level、AddSource、ReplaceAttr、字段契约、输出 Writer 和日志采集端的静态关系说明图
图2:HandlerOptions 与日志采集边界说明图,展示级别过滤、来源字段和属性改写如何连接到下游 Writer。

把结构化字段设计成稳定契约

JSON 只是编码格式,真正方便检索的是稳定的字段名和类型。建议把 request_id、service、operation、status 这类跨模块都会使用的字段固定下来;数值就保持数值,不要一会儿写成 200、一会儿写成 "200"。

同时要区分三类内容:msg 描述人类可读的事件,业务属性承担机器检索,错误对象只记录必要的错误信息。不要把一整段已经序列化的 JSON 再作为字符串传入,否则采集端看到的会是嵌套转义文本,失去字段级查询价值。

设计项推荐做法常见问题
事件名称短而稳定,放在 msg把动态参数拼进长句
业务字段使用固定键名和稳定类型同一字段在字符串和数字间切换
敏感信息在 HandlerOptions 统一改写或删除只在少数调用点手工脱敏
错误信息保留可定位的摘要和分类直接输出凭据、请求体或完整隐私数据

根据运行场景选择落地方案

在容器或进程管理环境里,标准输出通常是最简单的出口:应用只负责写 JSON,采集层负责转发、索引和保留策略。写本地文件时,要额外面对文件轮转、磁盘容量和进程权限;把 Writer 换成自定义实现时,则要明确并发安全、短写入和错误处理契约。

可以按下面的决策收口:

  • 服务交给平台采集:优先 os.Stdout,保持单条日志一行,避免混入非 JSON 文本。
  • 需要源码定位:开启 AddSource,但把它当成排障字段,不要让业务查询依赖路径字符串。
  • 日志字段受合规约束:集中使用 ReplaceAttr 做删减或替换,并把新增敏感字段纳入评审清单。
  • 日志量不可控:先用级别和采集端过滤控制体量;不要为了“完整”永久保留所有调试日志。

落地前至少确认输出 Writer、最低级别、字段命名、脱敏策略和采集端的单行约束。这样 slog.NewJSONHandler 才是一个清晰的日志架构边界,而不是把格式转换责任散落在每个业务函数里。

常见问题

NewJSONHandler 会输出一整个 JSON 数组吗?

不会。它按日志记录逐行写出 JSON 对象,采集端应按行读取,而不是等待一个完整数组结束。

为什么已经使用 JSONHandler,还要固定字段类型?

JSONHandler 只负责编码;如果同一个键在不同事件里使用不同类型,检索、聚合和告警规则仍然会变得不稳定。

AddSource 要不要一直开启?

它适合需要源码位置的排障场景。是否长期开启应结合日志量、采集字段和定位收益决定,不要把它当成业务字段的替代品。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Linux systemd CPUWeight 与 CPUQuota 组合限制服务 CPU 的配置方法Linux systemd CPUWeight 与 CPUQuota 组合限制服务 CPU 的配置方法
上一篇
Linux systemd CPUWeight 与 CPUQuota 组合限制服务 CPU 的配置方法
Go io.TeeReader 怎样统计流经读取器的字节数
下一篇
Go io.TeeReader 怎样统计流经读取器的字节数
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    769次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    766次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    847次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    817次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    646次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码