当前位置: 首页 > news >正文

The Dangers of Fatal Logging

log.Fatal violates the Single Responsibility Principle in insidious ways. Never use it!

I want to talk about fatal logging. It’s practically always a bad idea. Let me explain…

I was recently reviewing some code written in Go, where I saw this pattern in a constructor function:

func NewConnection(url string) *Client { conn, err := service.Connect(url) if err != nil { log.Fatal( err) } return &Client{conn: conn} }

Whatever language you use, if your logging library has aFataloption, I emplore you to never use it, and for one simple, but profound reason:

It violates the Single-Responsibility Principle

Now, I don’t generally put the SOLID principles on a high pedistal. But this is one place where the SRP violation doesn’t just peak through the curtains, asking you politely to re-consider. It bursts through the seams like the Kool-aid Man screaming for attention. Oh yeah!

In Go, callinglog.Fatalin the standard library, and to my knowledge in any other logger implementation, does two things:

  1. It logs an error message with a priority ofFATAL
  2. It immediately exits the program (by calling os.Exit(1))

Do you see the SRP violation?

Logging is one concern. Affecting control flow of the entire program (by exiting) is something else entirely. This function, by design, has two unrelated responsibilities.

But does it matter? If you know that callinglog.Fatalexits the program, surely you can make an informed decision, right?

If you’re writting some short, throw-away program, akin to a bash script, sure. Whatever. I often have no problem violating the SRP, or countless other rules of thumb and best practices in such a case.

But if you’re writing anything like a real application, this SRP violation creates an insideous form of tight-coupling in your program.

What if the caller of your function wants to try to recover from an error? Maybe you add an option for the user to provide a list of connection URLs, and you want to try all of them until one works.

for _, url := range config.URLs { conn = NewConnection(url) }

With our current implementation, the first failure will cause the program to crash.

“Yes, but I can edit it!” You can. But SRP. You should have only one reason to change a piece of code. We now have two: (1) we want to change the way a connection works (2) we want to decouple control flow.

Or what if you add the option to re-connect to the service after a failure after the app has already been running. Do you want a failed connection attempt to exit the program? Well… maybe. But also maybe not. That should be up to the caller of the function, not the function itself.

Only exit your program from the top of the call stack

In Go parlance, this means: Only ever callos.Exit()from yourmain()function. This precludes callinglog.Fatalfrom anywhere except possibly inmain()itself.

If you follow this simple rule, your constructors will not surprise their callers by exiting the program.

This is doubly important in any language (like Go), where exiting the program precludes any cleanup. In Go, callingos.Exitmeans that deferred functions don’t get called, and there’s no opportunity for recovery. It’s final. Do not pass Go. Do not collect $200.

This means that in many applications, callinglog.Fatalmay actually not even log your error!What?

If you’re logging to a network service, one of the last things you must do before exiting your program is flush your log buffer. If you callos.Exit, that flushing never happens.

Won’t that be a lovely debugging session? You typo your database config. Now your app won’t start…andit doesn’t send you any logs. 🤦‍♂️

What’s the alternative?

In the Go example above, the obvious alternative is to return the error to the caller.

func NewConnection(url string) (*Client, error) { conn, err := service.Connect(url) if err != nil { return nil, err } return &Client{conn: conn}, nil }

Your language may use exceptions. That’s fine. Use whatever normal error-handling capability your language/tool provides.

In Go, there’s also the option topanic, if returning an error really doesn’t make sense.panicdiffers fromos.Exitin three distinct ways:

  1. It has a different semantic meaning. It means “something unrecoverable happened”, where asos.Exitmeans “quit the program” without regard for why.
  2. Deferred functions are still called, so cleanup can be done prior to program exit.
  3. It’s recoverable.
http://www.jsqmd.com/news/704226/

相关文章:

  • 2026届最火的六大降重复率神器推荐
  • 【独家首发】MCP 2026多租户加密性能压测报告:AES-GCM-SIV vs ChaCha20-Poly1305在10万TPS下的租户上下文切换耗时对比(附可复现YAML)
  • 如何用望言OCR实现10倍速视频字幕提取?终极硬字幕识别工具完整指南
  • KISSABC官方正规购买渠道及授权服务说明 - 品牌企业推荐师(官方)
  • WASM容器化部署性能翻倍实录(2024边缘节点压测全数据公开):从287ms到19ms的5步调优链
  • 大规模数据集异常检测技术实战与优化
  • M3U8不只是个播放列表?揭秘它在短视频下载与HLS流媒体中的核心角色
  • 当 grep 遇上向量数据库:AI 工程范式的演进与缝合
  • 如何快速搭建本地AI助手:Ollama GUI完整使用指南
  • 3步重新定义老旧电视体验:MyTV-Android突破性直播解决方案实战指南
  • 掌握CREST分子构象搜索:从基础理论到实战应用
  • 2025-2026年航城壹号电话查询:看房前请核实房源信息与交易条件 - 品牌推荐
  • Docker + WASM边缘计算部署指南:5步实现毫秒级冷启动,99.99%可用性保障
  • Skillz:基于MCP协议实现AI技能跨平台复用的开源服务器
  • 别再只会调库了!手把手教你用STM32的TIM8定时器精准控制SG90舵机(附完整代码)
  • 2026届必备的六大降AI率网站推荐
  • TouchGal终极指南:打造你的专属Galgame社区平台
  • 2026届最火的十大AI辅助写作工具推荐榜单
  • 5个提升glTF 2.0导出效率的实战技巧
  • 2025-2026年画景电话查询:了解天然弱碱性矿泉水的特点与选择建议 - 品牌推荐
  • 【VS Code MCP生态搭建终极指南】:20年专家亲授从零部署到企业级插件开发的7大核心步骤
  • CPU性能优化终极指南:免费开源工具CPUDoc让你的电脑飞起来
  • 解锁微信自动化:Python脚本让你的消息处理效率提升300%
  • 2026届毕业生推荐的六大降AI率助手实测分析
  • CefFlashBrowser:终极Flash兼容解决方案 - 完整指南
  • 2025-2026年航城壹号电话查询:购房前请核实房源信息与交易流程 - 品牌推荐
  • 基于STM8的中频理疗仪解决方案(SCH+PCB设计)
  • 终极Windows安装神器:MediaCreationTool.bat全功能解析与高效使用指南
  • 无人机飞行数据分析新视角:让复杂数据变得一目了然的Web工具
  • 开源数据协作平台OpsKat:可视化工作流构建与自托管部署指南