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)
 | |
| 		}
 | |
| 	},
 | |
| }
 |