synapsecns/sanguine

View on GitHub
core/dockerutil/docker.go

Summary

Maintainability
A
35 mins
Test Coverage
package dockerutil

import (
    "context"
    "fmt"
    "github.com/ipfs/go-log"
    "github.com/ory/dockertest/v3/docker"
    "github.com/synapsecns/sanguine/core/processlog"
    "io"
)

var logger = log.Logger("dockertest")

// TailContainerLogs tails the logs of a container and outputs them to a processlog file.
func TailContainerLogs(opts ...Option) error {
    stdoutReader, stdoutWriter := io.Pipe()
    stderrReader, stderrWriter := io.Pipe()

    logOpts := &logOptions{
        logOptions: docker.LogsOptions{
            Stderr:       true,
            Stdout:       true,
            Timestamps:   false,
            RawTerminal:  false,
            Since:        0,
            ErrorStream:  stderrWriter,
            OutputStream: stdoutWriter,
        },
    }

    for _, opt := range opts {
        if err := opt(logOpts); err != nil {
            return optionError{err}
        }
    }
    if err := ValidateOptions(opts...); err != nil {
        return optionError{err}
    }

    // TODO: rest of the options go here
    logInfo, err := processlog.StartLogs(buildProcessLogOpts(logOpts.ctx, stdoutReader, stderrReader, logOpts.processOptions)...)
    if err != nil {
        return fmt.Errorf("failed to get container logs: %w", err)
    }

    if logOpts.callback != nil {
        logOpts.callback(logOpts.ctx, logInfo)
    }

    closeChan := make(chan struct{})
    go func() {
        <-logOpts.ctx.Done()
        close(closeChan)
    }()

    errChan := make(chan error, 1)
    go func() {
        errChan <- logOpts.pool.Client.Logs(logOpts.logOptions)
    }()

    select {
    case <-closeChan:
        return fmt.Errorf("context canceled: %w", logOpts.ctx.Err())
    case err := <-errChan:
        return fmt.Errorf("failed to tail container logs: %w", err)
    }
}

// buildProcessLogOpts builds the processlog options for the given stdout and stderr readers.
// StdOut/StdErr will always override the set readers and emit a warning.
func buildProcessLogOpts(ctx context.Context, stdoutReader, stderrReader io.ReadCloser, opts []processlog.StdStreamLogArgsOption) (out []processlog.StdStreamLogArgsOption) {
    out = append(out, processlog.WithCtx(ctx))
    out = append(out, opts...)

    if processlog.HasReader(processlog.StdOut, opts...) {
        logger.Warn("overriding stdout reader, should not be set")
    }

    if processlog.HasReader(processlog.StdErr, opts...) {
        logger.Warn("overriding stderr reader, should not be set")
    }

    out = append(out, processlog.WithStdOut(stdoutReader))
    out = append(out, processlog.WithStdErr(stderrReader))
    return out
}