You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lazydocker/pkg/gui/container_logs.go

133 lines
3.3 KiB
Go

package gui
import (
"context"
"fmt"
"io"
"os"
"os/signal"
"time"
dockerTypes "github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
"github.com/fatih/color"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/tasks"
"github.com/jesseduffield/lazydocker/pkg/utils"
)
func (gui *Gui) renderContainerLogsToMain(container *commands.Container) tasks.TaskFunc {
return gui.NewTickerTask(TickerTaskOpts{
Func: func(ctx context.Context, notifyStopped chan struct{}) {
gui.renderContainerLogsToMainAux(container, ctx, notifyStopped)
},
Duration: time.Millisecond * 200,
// TODO: see why this isn't working (when switching from Top tab to Logs tab in the services panel, the tops tab's content isn't removed)
Before: func(ctx context.Context) { gui.clearMainView() },
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
Autoscroll: true,
})
}
func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, ctx context.Context, notifyStopped chan struct{}) {
gui.clearMainView()
defer func() {
notifyStopped <- struct{}{}
}()
mainView := gui.Views.Main
if err := gui.writeContainerLogs(container, ctx, mainView); err != nil {
gui.Log.Error(err)
}
// if we are here because the task has been stopped, we should return
// if we are here then the container must have exited, meaning we should wait until it's back again before
ticker := time.NewTicker(time.Millisecond * 100)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
result, err := container.Inspect()
if err != nil {
// if we get an error, then the container has probably been removed so we'll get out of here
gui.Log.Error(err)
return
}
if result.State.Running {
return
}
}
}
}
func (gui *Gui) renderLogsToStdout(container *commands.Container) {
stop := make(chan os.Signal, 1)
defer signal.Stop(stop)
ctx, cancel := context.WithCancel(context.Background())
go func() {
signal.Notify(stop, os.Interrupt)
<-stop
cancel()
}()
if err := gui.g.Suspend(); err != nil {
gui.Log.Error(err)
return
}
defer func() {
if err := gui.g.Resume(); err != nil {
gui.Log.Error(err)
}
}()
if err := gui.writeContainerLogs(container, ctx, os.Stdout); err != nil {
gui.Log.Error(err)
return
}
gui.promptToReturn()
}
func (gui *Gui) promptToReturn() {
if !gui.Config.UserConfig.Gui.ReturnImmediately {
fmt.Fprintf(os.Stdout, "\n\n%s", utils.ColoredString(gui.Tr.PressEnterToReturn, color.FgGreen))
// wait for enter press
if _, err := fmt.Scanln(); err != nil {
gui.Log.Error(err)
}
}
}
func (gui *Gui) writeContainerLogs(container *commands.Container, ctx context.Context, writer io.Writer) error {
readCloser, err := gui.DockerCommand.Client.ContainerLogs(ctx, container.ID, dockerTypes.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Timestamps: gui.Config.UserConfig.Logs.Timestamps,
Since: gui.Config.UserConfig.Logs.Since,
Follow: true,
})
if err != nil {
return err
}
if container.DetailsLoaded() && container.Details.Config.Tty {
_, err = io.Copy(writer, readCloser)
if err != nil {
return err
}
} else {
_, err = stdcopy.StdCopy(writer, writer, readCloser)
if err != nil {
return err
}
}
return nil
}