1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
//go:build !nodocker
// +build !nodocker
package main
import (
"bufio"
"context"
"io"
"log"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"gopkg.in/alecthomas/kingpin.v2"
)
// A DockerLogSource reads log records from the given Docker
// journal.
type DockerLogSource struct {
client DockerClient
reader *bufio.Reader
containerID string
}
// A DockerClient is the client interface that client.Client
// provides. See https://pkg.go.dev/github.com/docker/docker/client
type DockerClient interface {
io.Closer
ContainerLogs(context.Context, string, container.LogsOptions) (io.ReadCloser, error)
}
// NewDockerLogSource returns a log source for reading Docker logs.
func NewDockerLogSource(ctx context.Context, c DockerClient, containerID string) (*DockerLogSource, error) {
r, err := c.ContainerLogs(ctx, containerID, container.LogsOptions{
ShowStdout: true,
ShowStderr: true,
Follow: true,
Tail: "0",
})
if err != nil {
return nil, err
}
logSrc := &DockerLogSource{
client: c,
containerID: containerID,
reader: bufio.NewReader(r),
}
return logSrc, nil
}
func (s *DockerLogSource) Close() error {
return s.client.Close()
}
func (s *DockerLogSource) Path() string {
return "docker:" + s.containerID
}
func (s *DockerLogSource) Read(ctx context.Context) (string, error) {
line, err := s.reader.ReadString('\n')
if err != nil {
return "", err
}
return strings.TrimSpace(line), nil
}
// A dockerLogSourceFactory is a factory that can create
// DockerLogSources from command line flags.
type dockerLogSourceFactory struct {
containerID string
enable bool
}
func (f *dockerLogSourceFactory) Init(app *kingpin.Application) {
app.Flag("docker.enable", "Read from Docker logs. Environment variable DOCKER_HOST can be used to change the address. See https://pkg.go.dev/github.com/docker/docker/client?tab=doc#NewEnvClient for more information.").Default("false").BoolVar(&f.enable)
app.Flag("docker.container.id", "ID/name of the Postfix Docker container.").Default("postfix").StringVar(&f.containerID)
}
func (f *dockerLogSourceFactory) New(ctx context.Context) (LogSourceCloser, error) {
if !f.enable {
return nil, nil
}
log.Println("Reading log events from Docker")
c, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
}
return NewDockerLogSource(ctx, c, f.containerID)
}
func init() {
RegisterLogSourceFactory(&dockerLogSourceFactory{})
}
|