All checks were successful
continuous-integration/drone/push Build is passing
See #478
105 lines
2.1 KiB
Go
105 lines
2.1 KiB
Go
package logs
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"sync"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
containerTypes "github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/filters"
|
|
dockerClient "github.com/docker/docker/client"
|
|
)
|
|
|
|
type TailOpts struct {
|
|
AppName string
|
|
Services []string
|
|
StdErr bool
|
|
Since string
|
|
Buffer *[]string
|
|
ToBuffer bool
|
|
Filters filters.Args
|
|
}
|
|
|
|
// TailLogs gathers logs for the given app with optional service names to be
|
|
// filtered on. These logs can be printed to os.Stdout or gathered to a buffer.
|
|
func TailLogs(
|
|
cl *dockerClient.Client,
|
|
opts TailOpts,
|
|
) error {
|
|
sigIntCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigIntCh, os.Interrupt)
|
|
defer signal.Stop(sigIntCh)
|
|
|
|
services, err := cl.ServiceList(
|
|
context.Background(),
|
|
types.ServiceListOptions{Filters: opts.Filters},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
errCh := make(chan error)
|
|
waitCh := make(chan struct{})
|
|
|
|
go func() {
|
|
var wg sync.WaitGroup
|
|
for _, service := range services {
|
|
wg.Add(1)
|
|
go func(serviceID string) {
|
|
tail := "50"
|
|
if opts.ToBuffer {
|
|
// NOTE(d1): more logs from before deployment when analysing via file
|
|
tail = "150"
|
|
}
|
|
|
|
logs, err := cl.ServiceLogs(context.Background(), serviceID, containerTypes.LogsOptions{
|
|
ShowStderr: true,
|
|
ShowStdout: !opts.StdErr,
|
|
Since: opts.Since,
|
|
Until: "",
|
|
Timestamps: true,
|
|
Follow: true,
|
|
Tail: tail,
|
|
Details: false,
|
|
})
|
|
|
|
if err == nil {
|
|
defer logs.Close()
|
|
if opts.ToBuffer {
|
|
buf := bufio.NewScanner(logs)
|
|
for buf.Scan() {
|
|
line := fmt.Sprintf("%s: %s", service.Spec.Name, buf.Text())
|
|
*opts.Buffer = append(*opts.Buffer, line)
|
|
}
|
|
logs.Close()
|
|
return
|
|
}
|
|
|
|
if _, err = io.Copy(os.Stdout, logs); err != nil && err != io.EOF {
|
|
errCh <- fmt.Errorf("tailLogs: unable to copy buffer: %s", err)
|
|
}
|
|
}
|
|
}(service.ID)
|
|
}
|
|
|
|
wg.Wait()
|
|
close(waitCh)
|
|
}()
|
|
|
|
select {
|
|
case <-waitCh:
|
|
return nil
|
|
case <-sigIntCh:
|
|
return nil
|
|
case err := <-errCh:
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|