Golang 从入门到放弃 -0x11
配置、环境变量与日志的组织方式,开始让服务更像一个正经工程。
写到这里,你的程序差不多已经开始从“会跑的小玩具”往“像样的服务”进化了。这个阶段有三样东西会越来越频繁地出现:配置、环境变量、日志。少了它们,程序不是不好跑,而是不好养。
别把配置写死在代码里
开发时图省事,把数据库地址、端口、密钥直接写死在代码里,好像很爽。但只要一上环境,这种爽就会很快反噬你。
type Config struct {
Port string
DSN string
}
func LoadConfig() Config {
port := os.Getenv("APP_PORT")
if port == "" {
port = "8080"
}
dsn := os.Getenv("MYSQL_DSN")
return Config{
Port: port,
DSN: dsn,
}
}这个模式非常常见:优先从环境变量读,没配就用默认值。
环境变量的价值
环境变量最大的好处,是让同一份代码在不同环境下表现不同,而不用改源码。比如:
- 本地开发连本地数据库
- 测试环境连测试库
- 生产环境连正式库
代码还是那份代码,差别在启动时给了什么参数。
日志别只会 Println
fmt.Println 不是不能用,但当服务真正跑起来以后,你会越来越希望日志至少带上时间、级别、上下文。标准库的 log 包先用起来就够了。
logger := log.New(os.Stdout, "[app] ", log.LstdFlags|log.Lshortfile)
logger.Println("service started")如果只是做简单服务,这套已经比满地散落的 fmt.Println 强不少。
错误日志和业务日志分开想
不是所有日志都一个待遇。很多人刚开始写日志时喜欢啥都打一遍,最后线上一看,信息很多,但没用的更多。
可以先粗暴分成两类:
- 业务日志:记录关键流程,比如用户下单、任务开始、任务结束
- 错误日志:记录出错点、参数、上下文
如果一条日志既不能帮助你理解业务,也不能帮助你排查问题,那它多半只是噪音。
启动配置打印一下,但别把秘密全抖出来
服务启动时把关键信息打印出来很有帮助,比如端口、运行模式、依赖地址。但要注意,密码、token、私钥这类东西别直接打全。
cfg := LoadConfig()
log.Printf("service start on :%s", cfg.Port)很多线上事故不是代码崩了,而是配置配错了。启动时愿意多说两句,排查起来真的能省很多事。
配置文件也可以有,但别弄得太复杂
有些项目会用 JSON、YAML、TOML 来装配置,这当然没问题。但如果项目还很小,环境变量已经能满足,就没必要为了“看起来正规”先引入一堆配置系统。
工程化不是比谁目录多、库多,而是让程序更容易理解和维护。
小结
这一章先形成这些习惯:
- 配置优先外置,不要写死在代码里。
- 环境变量是最简单实用的配置手段之一。
- 日志要有信息量,不要只是情绪输出。
- 启动时把关键配置说清楚,但别把敏感信息裸奔出来。
下一章我们回头再把 error 讲深一点。前面是会用,后面要开始学会怎么用得像样。