Live data from Hacker News

Show HN: Dlg – Zero-cost printf-style debugging for Go

github.com

1–10 of 42 posts

Show HN: Dlg – Zero-cost printf-style debugging for Go

#1
Hey HN,

I tend to use printf-style debugging as my primary troubleshooting method and only resort to gdb as a last resort.

While I like its ease of use printf debugging isn't without its annoyances, namely removing the print statements once you're done.

I used to use trace-level logging from proper logging libraries but adding trace calls in every corner quickly gets out of control and results in an overwhelming amount of output.

To scratch my own itch I created dlg - a minimal debugging library that disappears completely from production builds. Its API exposes just a single function, Printf [1].

dlg is optimized for performance in debug builds and, most importantly, when compiled without the dlg build tag, all calls are eliminated by the Go linker as if dlg was never imported.

For debug builds it adds optional stack trace generation configurable via environment variables or linker flags.

GitHub: https://github.com/vvvvv/dlg

Any feedback is much appreciated.

[1]: Actually two functions - there's also SetOutput.

Show HN: Dlg – Zero-cost printf-style debugging for Go
github.com

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#4

> printf debugging isn't without its annoyances, namely removing the print statements once you're done. Use something like stacked git[1], and then it's just one "stg pop" and poof, they're gone. [1] https://stacked-git.github.io/

I’ve been doing this (manually) for about 10+ years.

I rarely use branches, my local work area is about 50-100 commits on top of master.

I pick/reorder/edit with “git rebase -i”

I’ll prefix the commit summary with a word that helps me keep straight debug changes from ones that will go toward a MR.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#5
In extreme processing needs, I suppose the elimination of a check that would happen with a level logger is a solid trade off.

My favored approach is a context aware level logger with structured logs going to an aggregator like Splunk.

Because it is context aware, custom filtering logic is available in a middleware.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#7

In extreme processing needs, I suppose the elimination of a check that would happen with a level logger is a solid trade off. My favored approach is a context aware level logger with structured logs going to an aggregator like Splunk. Because it is context aware, custom filtering logic is available in a middleware.

See the standard library "slog" package: https://pkg.go.dev/log/slog

Which is a relatively recent addition to the Go standard library, based on the collective experience with logging over the years. Compare with the original log standard library: https://pkg.go.dev/log and you can see the changes in even just the time since Go was developed in logging best practices.

Slog, once you understand the interfaces involved in stuff, has performed most every trick I could desire, up to and including things like subloggers with their own priorities for outputs that override the global settings.

I'd like to see some slog integration in this package, though I say that without a design in mind. As it stands, this is exactly what it says on the tin; debugging-only output that you fully intend to just disappear out of the production binary.

The trick it uses is a fairly straightforward use of Go's tag-based compilation features, which I do not mean as a criticism, but to point out that any Go programmer who likes the looks of this but wants to adapt it to their own task will find it easy to simply take the technique directly and adapt it in not very many lines of code.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#8
How does the dead code elimination work when using args to Printf? If static strings are fed into an empty function, I can imagine it does nothing. However, this I have less of a firm grip upon

  dlg.Printf("the thing.Something is %+v", thing.Something())
since surely golang will still call Something, and still call Printf

And don't misunderstand me: it's a grave pet peeve of mine to do action inside the args to Printf but I can tell you it's a very common [anti-]pattern so I'd presume your users will want a story for how that interacts with the "disappears completely" claim

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#9
post #8

How does the dead code elimination work when using args to Printf? If static strings are fed into an empty function, I can imagine it does nothing. However, this I have less of a firm grip upon dlg.Printf("the thing.Something is %+v", thing.Something()) since surely golang will still call Something, and still call Printf And don't misunderstand me: it's a grave pet peeve of mine to do action inside the args to Printf…

It's easy to show that you're right and that code isn't dead so it can't be eliminated:

    package main
    
    import (
     "fmt"
    
     "github.com/vvvvv/dlg"
    )
    
    func risky() error {
     _, err := fmt.Printf("unexpected error\n")
     return err
    }
    
    func main() {
     dlg.Printf("something failed: %s", risky())
     risky()
    }
prints "unexpected error" twice
Post reply on HN