People don't seem to know how to properly do print-debugging, so here's a simple guide:

1. A log of "aaaaaa" or "got here" isn't as helpful as you think when ALL OF THEM ARE THE FUCKING SAME. You put a descriptive label or copy verbatim the conditional statement. This saves time matching statements, allows one to watch multiple branches at once, and allows others to understand and help faster when dragged in to help.
2. When trying to see where code fucks up, before each line, paste said line into a proper print statement for your language. If there's, say, a function call or some shit, have it output something like "functionCall(varA=<varA contents>,varB=<varB contents);" Most normal lines should be like this too, but it's especially helpful for calls and comparisons.
If need be, add return values after if they're not shown in another print statement later.
This allows for a trail of execution AND the line that fucks up will be the last in the log, making finding it easier when dealing with hangs and such.
3. Putting something unique like "DEBUG: " or something in front of all statements ensures you can just search for them to ensure you're not rolling one out to production. It also separates debug output from normal output at a glance, making digging through logs faster.

  • 6
    My goto:

    - line: 123
    - file: xyz.cls
    - output:
    that thing you are checking.

    It's always been effective tracking down exactly what i'm looking for and in large log files make filtering super easy.
  • 1
    Absolutely agreed @Parzi.

    The thing is this is done in kernel development mostly as we dont have exactly perfect debugging enviroment and well you need to learn how to debug there otherwise shit wont work
  • 2
    @C0D4 particularly handy when the language has __LINE__/etc equivalents, or has enough metaprogramming abilities to do it in-language.

    Though I have frequently just built a "collect a stack trace, parse, use file+line+method" helper, when I don't have a sophisticated debugger. Slow, but not as slow as recompiling.
  • 2
    ... or use a proper debugger 🤔

    Not gonna sit on my high horse here, I know it sometimes can be difficult to set up.

    I use guids in those debug statements. Makes it easy to see where it came from.
  • 2
    Extra fun for segfaults: printf to stderr or set stdout to unbuffered. Otherwise, you sometimes won't see the output even if the segfault happens afterwards because it's buffered and the program is already terminated before the buffer is flushed to output.
  • 1
    Personally I use a method that takes a indicator parameter and a string of texts.


    public String log(int n, String t) {
    switch (n) {
    case 1:
    return "[*] "+t;
    case 2:
    return "[+] "+t;
    case 3:
    return "[-] "+t;
  • 1
    Mm people who cannot work with gdb/windbg make me sick 😤
  • 1
    @Pyjong some of us use langs where that's not helpful.
  • 1
    @C0D4 A similar concept, yeah... that might work better for multi-file setups with massive logs.
  • 2
    @Pyjong I would gladly, but Go has no even remotely acceptable debugger. E.g. Delve just lets you view raw memory until it inevitably disconnects after a few seconds.

    Sometimes still better than printf, so I'm glad it exists, but it has made like zero progress in two years. I'm not optimistic.
  • 1
    @groxx thats a shame. Why polute code with printfs if you can get the same and much more by setting a breakpoint.
  • 2
    @Pyjong Because a breakpoint stops execution, which may suck. Execution in the debugger may be slower, which also may be an issue. Though of course everything after the first printf also has a different timing.

    Also, the printf debugger is a good preparation for systems that don't have any debugger at all, and these are a preparation for when you don't even have access to the real program execution because it's totally elsewhere.
  • 2
    @Pyjong totally agree. Coming from Python and Java (even though Android breaks some of the advanced stuff like hot code swapping), Go has been an incredible disappointment in a fairly large number of tools. Good debuggers are enormous productivity tools, and logs are just conditional breakpoints... but Delve breaks so often, it is frequently faster to recompile, run, and get it back into that state again.
  • 2
    @Fast-Nop breakpoint stops execution may suck? Cmon 🙂 set it when you need it or make it conditional. Done.
    But yeah I would rather use kernel prints than use gdb remotely with serial. That takes ages.
    No debugger at all mmm.. I understand, although Id say every processor has a debug instruction, so there is a way to make it work. Ermm yeah all in all I'd add an extra " except for remote machine debugging" to my claim.
  • 2
    @groxx exactly, builds and debugger are the first two things that must work. I hate when my colleagues play their guessing games. I'm not saying its a cure for everything but it is a cure for almost everything that runs on cpu and should be used in the first place.
  • 2
    @Pyjong Sometimes, I don't want the execution to actually stop, just get some debug output. Especially when it's about external inputs that arrive in real time, like in a protocol stack.

    About the only time when I fire up GDB at all is when I have really strange segfaults because some pointer bug has garbled over some unrelated variable, and that's exceptionally rare. And then it's GDB right from the CLI.

    I developed for systems where the only "debugger" was abusing either some LED or some free IO pin for attaching an oscilloscope. No other debugger available.
  • 2
    @Pyjong In contrast to that, I think a dev shouldn't depend on a debugger. It should be a "nice to have" tool, not more. The primary method of debugging should be reading and understanding the code.
  • 2
    @Fast-Nop yup debugger doesnt come for free, thats true. But it is not that hard to get breakpoints and memory/register dumps work. Not that I use any public ones but there are debug commands interpreters for embedded on github after all. I think its better to send debugger commands instead of traces in the long run. So the question is: is the run long enough to take the effort?
    Anyway, I'm more upset about people who have the debugger at their disposal, but dont use it.

    I agree on the code reading skills but i think they are more ofa prerequisite. Without that debugger hardly helps.
Add Comment