【译】调试使用Go1.12开发部署的程序

2019-04-26 14:45:37

源地址:https://blog.golang.org/debugging-what-you-deploy

1. 介绍

Go 1.11和Go 1.12在允许开发人员调试对已部署至生成环境的二进制可执行程序方面取得了重大进展。
由于Go编译器在生成更快的二进制文件方面变得越来越积极,我们在可调试性方面已失去了优势。在Go 1.10中,用户在编译时完全禁用编译优化,才能在使用Delve等交互式工具中获得良好的调试体验。但是用户不应该为了可调试性而降低程序性能,尤其是在生产环境中。如果在生产环境了出现了问题,且需要在生产环境进行debug调试,我们不应该采用未经调优的二进制文件直接放到生产环境中。
对于Go 1.11和1.12,我们专注于提升对已经编译优化后的二进制文件的debug体验(Go编译器的默认设置),改进包括:

  • 更准确的入参(value)检测,特别是function的入参;
  • 更精确的识别语句边界,以便一步一步调试时不那么跳跃,断点能更多的落在调试人员期望的地方;
  • Delve调用Go函数的初步支持(goroutines以及垃圾回收机制使得它比C和C++更复杂)

2. 使用Delve调试优化代码

Delve是基于x86的,支持Linux和MacOS。Delve对Go的goroutines结合比较好,也支持Go的其他功能,能有比较好的调试体验。Delve也是GolandVs CodeVim的官方调试引擎。
Delve通常会使用-gcflags "all=-N -l"来重建它正在调试的代码,这会禁用内联和大多数优化。要使用Delve调试优化代码,需要首先构建优化二进制文件,然后使用dlv exec your_program对它进行调试。或者如果您有崩溃的core文件,则可以使用它进行检查dlv core your_program your_core。使用1.12和最新的Delve版本能检查许多变量,即使在优化的二进制文件中也是如此。

3. 改进value检查

调试使用Go 1.10生成的优化二级制文件时,变量值通常完全不可用。但是,从Go 1.11开始,即使在优化的二进制文件中也可以检查变量,除非它们已被彻底优化。在Go 1.11中,编译器开始发送DWARF定位列表,因此调试器可以在近处寄存器时跟踪变量,并重建分散在不同寄存器和堆栈槽中的复杂对象。

4. 改进单步模式

下面显示了在1.10调试器中单步执行的一个简单函数示例,其中缺陷(跳过和重复的行)用红色箭头突出显示。
debugging-what-you-deploy
这样的缺陷使得在单步执行程序并干扰击中断点时很容易忘记您的位置。
Go 1.11和1.12 能记录语句的边界信息,并通过优化和内联更好的跟踪源行号。因此,在Go 1.12中,逐步执行此代码会在每一行停止,并按照你期望的顺序执行操作。

5. 函数调用

Delve中的函数调用目前仍在持续开发中,下面只是一个简单的示例:

(dlv)call fib(6)
> main.main()。/ hello.go:15(PC:0x49d648)
Values returned:
    ~r1:8

6. 未来方向

Go 1.12是为优化二进制文件提供更好调试体验的一步,我们计划进一步改进它。
可调试性和性能之间存在基本的权衡,因此我们将重点放在优先级最高的调试缺陷上,并努力收集自动化指标以监控我们的进度并发现和回归。
我们专注于为调试器生成有关可变位置的正确信息,因此如果可以打印变量,则可以正确打印。我们还在考虑更多地使变量值可用,特别是在比如call sites(不知该怎么翻译)等关键点,尽管在许多情况下改进这一点需要减慢程序执行速度。最后,我们正在努力改进单步调试:我们专注于单步调试的panic,单步调试的顺序,并且通常尽可能地遵循源顺序。

7. 关于macOS支持的说明

Go 1.11开始压缩调试信息以减少二进制大小。这是Delve原生支持的,但LLDB和GDB都不支持macOS上的压缩调试信息。如果您使用的是LLDB或GDB,则有两种解决方法:使用-ldflags=-compressdwarf=false或使用splitdwarf(go get golang.org/x/tools/cmd/splitdwarf)解压缩现有二进制文件中的调试信息。

Golang之服务配置自动初始化

背景 今天分享一个利用reflect在实际项目中比较省时、代码简洁且高效的方法-服务配置自动初始化的方法。 我们在起一个Web项目时,常常都是直接使用开源的一些框架或组建,然后在我们自己的项目中要使用之前按照该框架或组建提供的帮助文档一个一个进行相应的初始化配置。也许我们只引用其中一两个,这样写都还能忍受,可是如果这个服务会引用更多的呢? 效果 代码简洁化 接入第三方库就如搭积木一样,模块化,随取随用 可维护性高 干货 下面,我们就来利用reflect实现该功能。 思路 磨刀不误砍柴工,我们先整理好一个简单思路,然后再尝试实现它,这样就简单了。 从远端配置服务或本地获取到我们需要初始化的配置 解析配置中的数据 判断配置中元素是否有实现我们指定方法,如果有就执行它,没有就跳过 没错,用语言描述就这么三句话,就这么简单。 获取配置 服务要启动,获取配置要么从远端配置服务拉取,要么从本地读取,就以常见的json格式作为我们本次举例的配置格式吧。 { "ginx": { "listen_port": 8080 }, "conn_timeout":2 } 既然是json化的配置,

谷歌浏览器模拟手机浏览器

构建初始化环境 下载谷歌浏览器,地址:https://www.google.com/chrome/#_ga=2.207613393.314015719.1537268086-901043581.1537268086 不能下载?点击这里 构建基本环境 浏览地址先输入网址 如神马搜索:https://yz.m.sm.cn/s?q=红岩&from=wy836274&by=submit&snum=4 UA更换 Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11s Build/