synapsecns/sanguine

View on GitHub
core/processlog/options.go

Summary

Maintainability
A
35 mins
Test Coverage
package processlog

import (
    "bytes"
    "context"
    "errors"
    "io"
    "os"
    "time"
)

// PrintFunc is the function used to print data to the desired logger.
type PrintFunc func([]byte)

// stdStreamLogArgs define log inputs.
type stdStreamLogArgs struct {
    // StdOut is the standard out stream to split from
    StdOut io.ReadCloser
    // StdErr is the stderr stream to split from
    StdErr io.ReadCloser
    // PrintFunc is how the print function is returned
    PrintFunc PrintFunc
    // LogDir is the directory to log to
    LogDir string
    // LogFileName is the log file name prefix
    LogFileName string
    // LogFrequency is how often to write to the lgos
    LogFrequency time.Duration
    // Accumulator to accumulate logs to.
    Accumulator *bytes.Buffer
    // Ctx is the context. Note: cancellations may lead to errors in your Wait() function
    // nolint: containedctx
    Ctx context.Context
}

var (
    errCtxNil          = errors.New("context cannot be nil")
    errStdOutMustBeSet = errors.New("StdOut must be set")
    //nolint: errName
    errStdErrMustBeSet = errors.New("StdErr must be set")
    errLogDirRequired  = errors.New("log directory must be set")
)

// Validate validates the stdStreamLogArgs struct.
func (s *stdStreamLogArgs) Validate() error {
    if s.Ctx == nil {
        return errCtxNil
    }

    if s.StdOut == nil {
        return errStdOutMustBeSet
    }

    if s.StdErr == nil {
        return errStdErrMustBeSet
    }

    if s.LogDir == "" {
        return errLogDirRequired
    }

    return nil
}

// StdStreamLogArgsOption is a function that modifies a stdStreamLogArgs struct field.
type StdStreamLogArgsOption func(*stdStreamLogArgs)

// WithStdOut returns a function that modifies the StdOut field of a stdStreamLogArgs struct.
func WithStdOut(stdOut io.ReadCloser) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.StdOut = stdOut
    }
}

// WithStdErr returns a function that modifies the StdErr field of a stdStreamLogArgs struct.
func WithStdErr(stdErr io.ReadCloser) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.StdErr = stdErr
    }
}

// WithReader returns a function that modifies the StdOut or StdErr field of a stdStreamLogArgs struct.
func WithReader(readerType ReaderType, reader io.ReadCloser) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        switch readerType {
        case StdOut:
            WithStdOut(reader)(args)
        case StdErr:
            WithStdErr(reader)(args)
        }
    }
}

// WithPrintFunc returns a function that modifies the PrintFunc field of a stdStreamLogArgs struct.
func WithPrintFunc(printFunc PrintFunc) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.PrintFunc = printFunc
    }
}

// WithLogDir returns a function that modifies the LogDir field of a stdStreamLogArgs struct.
func WithLogDir(logDir string) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.LogDir = logDir
    }
}

// WithLogFileName returns a function that modifies the LogFileName field of a stdStreamLogArgs struct.
func WithLogFileName(logFileName string) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.LogFileName = logFileName
    }
}

// WithLogFrequency returns a function that modifies the LogFrequency field of a stdStreamLogArgs struct.
func WithLogFrequency(logFrequency time.Duration) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.LogFrequency = logFrequency
    }
}

// WithAccumulator returns a function that modifies the Accumulator field of a stdStreamLogArgs struct.
func WithAccumulator(accumulator *bytes.Buffer) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.Accumulator = accumulator
    }
}

// WithCtx returns a function that modifies the Ctx field of a stdStreamLogArgs struct.
func WithCtx(ctx context.Context) StdStreamLogArgsOption {
    return func(args *stdStreamLogArgs) {
        args.Ctx = ctx
    }
}

// ReaderType is the type of reader (stdout or stderr).
//
//go:generate go run golang.org/x/tools/cmd/stringer -type=ReaderType -linecomment
type ReaderType uint8

const (
    // StdOut is the stdout reader type.
    StdOut ReaderType = iota // stdout
    // StdErr is the stderr reader type.
    StdErr ReaderType = iota // stderr
)

// HasReader returns true if the given reader type is set.
func HasReader(readerType ReaderType, opts ...StdStreamLogArgsOption) bool {
    args := makeRawArgs(opts)

    switch readerType {
    case StdOut:
        if args.StdOut != nil {
            return true
        }
    case StdErr:
        if args.StdErr != nil {
            return true
        }
    }
    return false
}

// makeArgs creates a new stdStreamLogArgs struct with the given options applied.
// It takes in a variadic list of StdStreamLogArgsOption functions and applies each of them to the new struct instance.
// It returns the modified struct instance.
func makeArgs(opts []StdStreamLogArgsOption) (_ *stdStreamLogArgs, err error) {
    args := makeRawArgs(opts)
    if err := args.Validate(); err != nil {
        return nil, err
    }
    return args, nil
}

// makeRawArgs creates a new stdStreamLogArgs struct with the given options applied.
// it performs no validation.
func makeRawArgs(opts []StdStreamLogArgsOption) *stdStreamLogArgs {
    args := &stdStreamLogArgs{}
    args.LogFileName = "test"
    args.LogFrequency = time.Second
    // not a problem unless it's missing from user too, we'll validate at the end
    args.LogDir, _ = os.MkdirTemp("/tmp/logs", "")
    _ = os.MkdirAll("/tmp/logs", os.ModePerm)

    args.LogFileName = "log"
    args.PrintFunc = func(s []byte) {
        // do nothing
    }

    for _, opt := range opts {
        opt(args)
    }

    return args
}