#debugging a Go function

1 messages · Page 1 of 1 (latest)

fierce idol
#

Hi Alex, if you're debugging your own logic, then placing a breakpoint somewhere in your wrapper function should work. Could you share a bit more about your debugging scenario and where it fell apart?

reef agate
#

@keen fox - I'd also be interested in what you are trying to accomplish from a code standpoint and what your "wrapper" is doing. I'm just learning all this myself. 🙂

keen fox
#

Hey @fierce idol — this is more or less the 'ideal scenario' if you ask me from where I get the best debugging experience —Yes, it's quite opinionated, but I'd think that I'm not far from the average 'nicer' experience when using IDE(s) such as Goland (Jetbrains) or others.

I use mostly Goland for crafting Go code 😄 , so I'm used to just place a breaking point in —let's stay the main function, and that's it. In the case of my current functions (see this https://github.com/Excoriate/daggerverse/blob/main/gitlab-cicd-vars/dagger/main.go#L63-L63 very simple Dagger module that I've published that fetches GitLab CI/CD vars) you'll see that if I want to reach that function during the normal dagger call --token:MY_GITLAB_SECRET get --path=some/project/ingitlab --var-name="myvar" flow, I can't, unless —and here correct me if I'm wrong— I use a wrapper function with a main entrypoint, that calls my individual functions exposed as dagger functions.

In the old 'classic' way, since the dagger client was mostly embedded into whatever application we wrote that interacted with Dagger (E.g.: a CLI), it was easy to place a breaking point in any part of the code flow, and from there reach any Dagger internal function/package that was required to either troubleshoot something, or understand more deeper how to use the Dagger Go SDK package.

Perhaps I'm demanding too much 🥲 — However, I'd love to learn from your experience in debugging dagger functions from the IDE-integration perspective.

Hey @reef agate — since I've developed very 'atomic' and granular functions, for now has been mostly Dagger CLI execution —let's stay a dagger call <> from the terminal and from there just tracking down logs in the functions called.

GitHub

A collection of Dagger modules powered by Dagger. Contribute to Excoriate/daggerverse development by creating an account on GitHub.

keen fox
#

Hey @fierce idol , @reef agate , no pressure in get your thoughts here 😄 , but it'd be awesome to understand if there are more effective manners to debug/troubleshoot effectively dagger functions/modules

reef agate
#

@keen fox - Unfortunately, I'm the last person who can give advice. I'm learning Go and Dagger at the same time. 🙂

keen fox
#

Hey! no worries at all. Just curious. When you have a tiny module (or a function in my case, like the one that I've mentioned above), following some logs it's more than enough. For more complex functions or modules calling another one, I'm Interested in checking whether just wrapping the functions with another one is a more effective approach, or there's a better one.

fierce idol
#

@keen fox I think I was overconfident when I said it should "just work". Since Dagger Functions are server code, run by the dagger engine, you can't just aim a traditional debugger at it.

We may need to add hooks to the engine for good debugger integration. I don't know what those hooks would be, or how they would be designed

#

Maybe @winter vector @fierce jetty @peak citrus @upper aurora have thoughts?

winter vector
#

There's possibly something we can do with language-specific remote debugging capabilities + host-to-container networking, would need to look into it way more deeply though, there are so many moving parts

fierce jetty
#

HLB has debugger support, through the equivalent of LSP but for debuggers. Been a long time so don’t remember details but that’s some prior art

keen fox
# fierce idol <@474225391599353866> I think I was overconfident when I said it should "just wo...

Good point. However, in the Dagger 'Classic' scenario (pre-functions/modules), I'd say that the debugging experience was close to 'ideal', and if I understand correctly your point about 'server-side code', in the old approach still the code was executed and directed by the Dagger engine, however, when we were developing code on top, placing a breakpoint into the —let's say— main() function was good enough to track down any bug until the SDK layer. I think until that layer, the debug experience is still quite good in the classic approach. In the new functions/modules approach, I can't get the same experience.

I think it'd be great to have the ability to reach the SDK and eventually the engine whilst debugging — currently, and correct me if I'm wrong, the engine is only managed by the CLI when we call our functions (dagger call <myfunction>). Perhaps that's why there's no dag.Connect() equivalent as it was with the dagger.Connect() function when we were able to manage the engine connectivity by ourselves 🤔 .

keen fox
#

If it helps to express what I'm trying to explain a bit better, let's stay I have this function in one of my modules

// Base sets the base image and version, and creates the base container.
func (g *Goreleaser) Base(image, version string) *Goreleaser {
    if image == "" {
        image = goReleaserDefaultImage
    }

    if version == "" {
        version = goReleaserDefaultVersion
    }

    slog.Info(fmt.Sprintf("Creating a new GoReleaser module with image %s", image))

    //c := dag.Container().From(image).
    //    WithMountedDirectory(mntPrefix, g.Src).
    //    WithExec([]string{"go", "install", fmt.Sprintf("github.com/goreleaser/goreleaser@%s", goreleaserVersion)})

    c := dag.Container().From(image).
        WithEnvVariable("TINI_SUBREAPER", "true").
        WithMountedDirectory(mntPrefix, g.Src)

    g.Ctr = c

    fmt.Printf("Entries: %v", entries)

    return g
}

And, I'd like to inspect the g.Src (which is a directory) and its entries, which was very useful in the classic approach to inspect what files I'm mounting. I"d do what I did in the classic approach, add entries, and inspect or debug by placing a breaking point in that particular line, something like:

entries, err := g.Src.Entries(context.Background())
    if err != nil {
        fmt.Printf("Error getting entries: %v", err)
    }

That isn't possible in the function's world. Or, at least I can't emulate the same experience —if there's a way to achieve this— and have a reliable breaking point inspecting what's being passed to the SDK's functions and so on. 🤔

upper aurora
#

Potentially we could provide a new Runtime field that would return a Service for a debugger? For example, for go, I know we could create a delve service, which is how some buildkit stuff works for debugging.

keen fox
#

hey @upper aurora , could you please elaborate a bit more on that idea? — if you can guide me where that's implemented in the actual engine's code, the better 🤔 . I'm curious.

upper aurora
#

my idea would be that we would potentially have RuntimeDebug or similar as a method there? This would return a Service as well as a Container which would have a DAP server running on it