Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stream Docker container logs via the Go SDK

I'm writing a tool for some game server software in Go called sampctl and the primary function is to spin up a Docker container for a server instance and then capture the logs coming out of the container, clean them up a bit and send them to a location of the users choice such as Elasticsearch or an administration panel for later analysis.

I've got everything else working, the only thing I can't seem to get to work is streaming logs. I can get logs if the application in the container crashes but I want to stream the logs in realtime.

I've tried using a scanner with the ContainerLogs returned ReadCloser but that just hung at the terminal.

https://github.com/Southclaws/sampctl/blob/9c76b4dd1b3dbb9e18927da10028d5beeb94f728/run_container.go#L64-L67

Does ContainerLogs even support streaming? Or will I need to figure out another solution...

Apologies if this is more of a Go question than a Docker question, I wasn't too sure whether or not to post here or on GoLangBridge...

like image 205
Southclaws Avatar asked Dec 11 '22 09:12

Southclaws


2 Answers

Have you read the docs? The stream has metadata embedded, so you can't quite just pipe it to the console.

I have the following code in a monitoring application:

    i, err := cli.ContainerLogs(context.Background(), cid, types.ContainerLogsOptions{
        ShowStderr: true,
        ShowStdout: true,
        Timestamps: false,
        Follow:     true,
        Tail:       "40",
    })
    if err != nil {
        log.Fatal(err)
    }
    hdr := make([]byte, 8)
    for {
        _, err := i.Read(hdr)
        if err != nil {
            log.Fatal(err)
        }
        var w io.Writer
        switch hdr[0] {
        case 1:
            w = os.Stdout
        default:
            w = os.Stderr
        }
        count := binary.BigEndian.Uint32(hdr[4:])
        dat := make([]byte, count)
        _, err = i.Read(dat)
        fmt.Fprint(w, string(dat))
    }

It streams as long as I keep it running. There is also this helper package to do most of that for you, but in my case I need to handle the messages individually like this for other reasons.

like image 123
captncraig Avatar answered Jan 05 '23 15:01

captncraig


Okay, I managed to resolve this and I'm not sure why captncraig's answer didn't work which I'm still curious about but hey, here's my solution:

I had to set some other options in my ContainerCreate call:

        Tty:          true,
        AttachStdout: true,
        AttachStderr: true,

Then the scanner.Scan() method worked perfectly!

Here is the updated code: https://github.com/Southclaws/sampctl/blob/1ad7971d817031bd5a5b3acfad3bf2ea69232c98/run_container.go#L56-L70

like image 44
Southclaws Avatar answered Jan 05 '23 16:01

Southclaws