97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
|
// +build !nodocker
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"context"
|
||
|
"io"
|
||
|
"log"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/alecthomas/kingpin"
|
||
|
"github.com/docker/docker/api/types"
|
||
|
"github.com/docker/docker/client"
|
||
|
)
|
||
|
|
||
|
// A DockerLogSource reads log records from the given Docker
|
||
|
// journal.
|
||
|
type DockerLogSource struct {
|
||
|
client DockerClient
|
||
|
containerID string
|
||
|
reader *bufio.Reader
|
||
|
}
|
||
|
|
||
|
// 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, types.ContainerLogsOptions) (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, types.ContainerLogsOptions{
|
||
|
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 {
|
||
|
enable bool
|
||
|
containerID string
|
||
|
}
|
||
|
|
||
|
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.NewEnvClient()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return NewDockerLogSource(ctx, c, f.containerID)
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
RegisterLogSourceFactory(&dockerLogSourceFactory{})
|
||
|
}
|