forked from toolshed/abra
		
	
		
			
				
	
	
		
			125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package app
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"coopcloud.tech/abra/cli/internal"
 | 
						|
	"coopcloud.tech/abra/pkg/client"
 | 
						|
	"coopcloud.tech/abra/pkg/config"
 | 
						|
	"github.com/docker/docker/api/types"
 | 
						|
	"github.com/docker/docker/api/types/filters"
 | 
						|
	dockerClient "github.com/docker/docker/client"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
	"github.com/urfave/cli/v2"
 | 
						|
)
 | 
						|
 | 
						|
// stackLogs lists logs for all stack services
 | 
						|
func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) {
 | 
						|
	filters := filters.NewArgs()
 | 
						|
	filters.Add("name", stackName)
 | 
						|
	serviceOpts := types.ServiceListOptions{Filters: filters}
 | 
						|
	services, err := client.ServiceList(c.Context, serviceOpts)
 | 
						|
	if err != nil {
 | 
						|
		logrus.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	var wg sync.WaitGroup
 | 
						|
	for _, service := range services {
 | 
						|
		wg.Add(1)
 | 
						|
		go func(s string) {
 | 
						|
			logOpts := types.ContainerLogsOptions{
 | 
						|
				Details:    true,
 | 
						|
				Follow:     true,
 | 
						|
				ShowStderr: true,
 | 
						|
				ShowStdout: true,
 | 
						|
				Tail:       "20",
 | 
						|
				Timestamps: true,
 | 
						|
			}
 | 
						|
			logs, err := client.ServiceLogs(c.Context, s, logOpts)
 | 
						|
			if err != nil {
 | 
						|
				logrus.Fatal(err)
 | 
						|
			}
 | 
						|
			// defer after err check as any err returns a nil io.ReadCloser
 | 
						|
			defer logs.Close()
 | 
						|
 | 
						|
			_, err = io.Copy(os.Stdout, logs)
 | 
						|
			if err != nil && err != io.EOF {
 | 
						|
				logrus.Fatal(err)
 | 
						|
			}
 | 
						|
		}(service.ID)
 | 
						|
	}
 | 
						|
	wg.Wait()
 | 
						|
	os.Exit(0)
 | 
						|
}
 | 
						|
 | 
						|
var appLogsCommand = &cli.Command{
 | 
						|
	Name:      "logs",
 | 
						|
	Aliases:   []string{"l"},
 | 
						|
	ArgsUsage: "[<service>]",
 | 
						|
	Usage:     "Tail app logs",
 | 
						|
	Action: func(c *cli.Context) error {
 | 
						|
		app := internal.ValidateApp(c)
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		serviceName := c.Args().Get(1)
 | 
						|
		if serviceName == "" {
 | 
						|
			logrus.Debug("tailing logs for all app services")
 | 
						|
			stackLogs(c, app.StackName(), cl)
 | 
						|
		}
 | 
						|
		logrus.Debugf("tailing logs for '%s'", serviceName)
 | 
						|
 | 
						|
		service := fmt.Sprintf("%s_%s", app.StackName(), serviceName)
 | 
						|
		filters := filters.NewArgs()
 | 
						|
		filters.Add("name", service)
 | 
						|
		serviceOpts := types.ServiceListOptions{Filters: filters}
 | 
						|
		services, err := cl.ServiceList(c.Context, serviceOpts)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
		if len(services) != 1 {
 | 
						|
			logrus.Fatalf("expected 1 service but got %v", len(services))
 | 
						|
		}
 | 
						|
 | 
						|
		logOpts := types.ContainerLogsOptions{
 | 
						|
			Details:    true,
 | 
						|
			Follow:     true,
 | 
						|
			ShowStderr: true,
 | 
						|
			ShowStdout: true,
 | 
						|
			Tail:       "20",
 | 
						|
			Timestamps: true,
 | 
						|
		}
 | 
						|
		logs, err := cl.ServiceLogs(c.Context, services[0].ID, logOpts)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
		// defer after err check as any err returns a nil io.ReadCloser
 | 
						|
		defer logs.Close()
 | 
						|
 | 
						|
		_, err = io.Copy(os.Stdout, logs)
 | 
						|
		if err != nil && err != io.EOF {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	},
 | 
						|
	BashComplete: func(c *cli.Context) {
 | 
						|
		appNames, err := config.GetAppNames()
 | 
						|
		if err != nil {
 | 
						|
			logrus.Warn(err)
 | 
						|
		}
 | 
						|
		if c.NArg() > 0 {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		for _, a := range appNames {
 | 
						|
			fmt.Println(a)
 | 
						|
		}
 | 
						|
	},
 | 
						|
}
 |