Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_de.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: anbinden
<kbd>m</kbd>: zeige Protokolle
<kbd>E</kbd>: exec shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: führe vordefinierten benutzerdefinierten Befehl aus
<kbd>b</kbd>: view bulk commands
<kbd>w</kbd>: open in browser (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: start
<kbd>a</kbd>: anbinden
<kbd>m</kbd>: zeige Protokolle
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: zeige Neustartoptionen
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: attach
<kbd>m</kbd>: view logs
<kbd>E</kbd>: exec shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: run predefined custom command
<kbd>b</kbd>: view bulk commands
<kbd>w</kbd>: open in browser (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: start
<kbd>a</kbd>: attach
<kbd>m</kbd>: view logs
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: view restart options
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_es.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: attach
<kbd>m</kbd>: ver logs
<kbd>E</kbd>: ejecutar shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: ejecutar comando personalizado
<kbd>b</kbd>: ver comandos masivos
<kbd>w</kbd>: abrir en navegador (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: iniciar
<kbd>a</kbd>: attach
<kbd>m</kbd>: ver logs
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: levantar proyecto
<kbd>D</kbd>: dar de baja el proyecto
<kbd>R</kbd>: ver opciones de reinicio
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: attacher
<kbd>m</kbd>: voir les enregistrements
<kbd>E</kbd>: exécuter le shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: exécuter une commande prédéfinie
<kbd>b</kbd>: voir les commandes groupées
<kbd>w</kbd>: ouvrir dans le navigateur (le premier port est http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: démarrer
<kbd>a</kbd>: attacher
<kbd>m</kbd>: voir les enregistrements
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: voir les options de redémarrage
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_nl.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: verbinden
<kbd>m</kbd>: bekijk logs
<kbd>E</kbd>: exec shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: draai een vooraf bedacht aangepaste opdracht
<kbd>b</kbd>: view bulk commands
<kbd>w</kbd>: open in browser (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: start
<kbd>a</kbd>: verbinden
<kbd>m</kbd>: bekijk logs
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: bekijk herstart opties
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_pl.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: przyczep
<kbd>m</kbd>: pokaż logi
<kbd>E</kbd>: exec shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: wykonaj predefiniowaną własną komende
<kbd>b</kbd>: view bulk commands
<kbd>w</kbd>: open in browser (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: start
<kbd>a</kbd>: przyczep
<kbd>m</kbd>: pokaż logi
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: pokaż opcje restartu
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: anexar
<kbd>m</kbd>: ver logs
<kbd>E</kbd>: executar shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: executar comando personalizado predefinido
<kbd>b</kbd>: ver comandos em massa
<kbd>w</kbd>: abrir no navegador (primeira porta é http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: iniciar
<kbd>a</kbd>: anexar
<kbd>m</kbd>: ver logs
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: subir projeto
<kbd>D</kbd>: derrubar projeto
<kbd>R</kbd>: ver opções de reinício
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: bağlan/iliştir
<kbd>m</kbd>: kayıt defterini görüntüle
<kbd>E</kbd>: exec shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: önceden tanımlanmış özel komutu çalıştır
<kbd>b</kbd>: view bulk commands
<kbd>w</kbd>: open in browser (first port is http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: start
<kbd>a</kbd>: bağlan/iliştir
<kbd>m</kbd>: kayıt defterini görüntüle
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: up project
<kbd>D</kbd>: down project
<kbd>R</kbd>: yeniden başlatma seçeneklerini görüntüle
Expand Down
2 changes: 2 additions & 0 deletions docs/keybindings/Keybindings_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>a</kbd>: attach
<kbd>m</kbd>: 查看日志
<kbd>E</kbd>: 执行shell
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>c</kbd>: 运行预定义的自定义命令
<kbd>b</kbd>: 查看批量命令
<kbd>w</kbd>: 在浏览器中打开(第一个端口为http)
Expand All @@ -45,6 +46,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>S</kbd>: 启动项目
<kbd>a</kbd>: attach
<kbd>m</kbd>: 查看日志
<kbd>t</kbd>: cycle how many log lines are shown
<kbd>U</kbd>: 创建并启动容器
<kbd>D</kbd>: 停止并移除容器
<kbd>R</kbd>: 查看重启选项
Expand Down
85 changes: 83 additions & 2 deletions pkg/gui/container_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,88 @@ import (
"io"
"os"
"os/signal"
"strconv"
"strings"
"time"

"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/tasks"
"github.com/jesseduffield/lazydocker/pkg/utils"
)

// containerLogsTailPresets are the values we cycle through when the user asks to
// change how many lines of logs are displayed. An empty string means 'show all logs'.
var containerLogsTailPresets = []string{"", "50", "100", "200", "500"}

func containerLogsTailLabel(tail string) string {
if tail == "" {
return "all"
}

return tail
}

// cycleContainerLogsTail moves to the next tail preset (wrapping back to the start)
// and forces the logs tab to re-render with the new value.
func (gui *Gui) cycleContainerLogsTail(g *gocui.Gui, v *gocui.View) error {
currentIdx := 0
for i, preset := range containerLogsTailPresets {
if preset == gui.State.ContainerLogsTail {
currentIdx = i
break
}
}

gui.State.ContainerLogsTail = containerLogsTailPresets[(currentIdx+1)%len(containerLogsTailPresets)]

if v != nil && v.Name() == "services" {
return gui.Panels.Services.HandleSelect()
}

return gui.Panels.Containers.HandleSelect()
}

// tailLimitingWriter wraps a writer and re-renders it on every line so that it only
// ever displays the last maxLines lines, keeping a true sliding window rather than
// just applying `--tail` to the initial snapshot and then growing forever as new
// lines are followed in.
type tailLimitingWriter struct {
view *gocui.View
maxLines int
lines []string
partial string
}

func newTailLimitingWriter(view *gocui.View, maxLines int) *tailLimitingWriter {
return &tailLimitingWriter{view: view, maxLines: maxLines}
}

func (w *tailLimitingWriter) Write(p []byte) (int, error) {
w.partial += string(p)
split := strings.Split(w.partial, "\n")
w.partial = split[len(split)-1]
newLines := split[:len(split)-1]

if len(newLines) == 0 {
return len(p), nil
}

w.lines = append(w.lines, newLines...)
if excess := len(w.lines) - w.maxLines; excess > 0 {
w.lines = w.lines[excess:]
}

// SetContent clears and rewrites atomically, so the view never renders empty
// in between
w.view.SetContent(strings.Join(w.lines, "\n") + "\n")

return len(p), nil
}

func (gui *Gui) renderContainerLogsToMain(container *commands.Container) tasks.TaskFunc {
return gui.NewTickerTask(TickerTaskOpts{
Func: func(ctx context.Context, notifyStopped chan struct{}) {
Expand All @@ -36,8 +108,17 @@ func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, ctx
}()

mainView := gui.Views.Main
tail := gui.State.ContainerLogsTail
mainView.Subtitle = fmt.Sprintf("tail: %s (%s to cycle)", containerLogsTailLabel(tail), "t")

var writer io.Writer = mainView
if maxLines, err := strconv.Atoi(tail); err == nil && maxLines > 0 {
// keep re-truncating to the chosen number of lines as new ones stream in,
// instead of just limiting the initial snapshot and growing unbounded after that
writer = newTailLimitingWriter(mainView, maxLines)
}

if err := gui.writeContainerLogs(container, ctx, mainView); err != nil {
if err := gui.writeContainerLogs(container, ctx, writer); err != nil {
gui.Log.Error(err)
}

Expand Down Expand Up @@ -110,7 +191,7 @@ func (gui *Gui) writeContainerLogs(ctr *commands.Container, ctx context.Context,
ShowStderr: true,
Timestamps: gui.Config.UserConfig.Logs.Timestamps,
Since: gui.Config.UserConfig.Logs.Since,
Tail: gui.Config.UserConfig.Logs.Tail,
Tail: gui.State.ContainerLogsTail,
Follow: true,
})
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/containers_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
// where a container restarts but the new logs don't get read.
// Note that this might be jarring if we have a lot of logs and the container
// restarts a lot, so let's keep an eye on it.
return "containers-" + container.ID + "-" + container.Container.State
return "containers-" + container.ID + "-" + container.Container.State + "-" + gui.State.ContainerLogsTail
},
},
ListPanel: panels.ListPanel[*commands.Container]{
Expand Down
7 changes: 7 additions & 0 deletions pkg/gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ type guiState struct {
// if true, we show containers with an 'exited' status in the containers panel
ShowExitedContainers bool

// the number of lines to pass as `--tail` when reading a container's logs. Empty
// string means we show all of the logs. This starts out as whatever is configured
// in the user's config, and can be cycled through ContainerLogsTailPresets via a
// keybinding.
ContainerLogsTail string

ScreenMode WindowMaximisation

// Maintains the state of manual filtering i.e. typing in a substring
Expand Down Expand Up @@ -136,6 +142,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
ViewStack: []string{},

ShowExitedContainers: true,
ContainerLogsTail: config.UserConfig.Logs.Tail,
ScreenMode: getScreenMode(config),
}

Expand Down
14 changes: 14 additions & 0 deletions pkg/gui/keybindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleContainersExecShell,
Description: gui.Tr.ExecShell,
},
{
ViewName: "containers",
Key: 't',
Modifier: gocui.ModNone,
Handler: gui.cycleContainerLogsTail,
Description: gui.Tr.CycleContainerLogsTail,
},
{
ViewName: "containers",
Key: 'c',
Expand Down Expand Up @@ -318,6 +325,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleServiceRenderLogsToMain,
Description: gui.Tr.ViewLogs,
},
{
ViewName: "services",
Key: 't',
Modifier: gocui.ModNone,
Handler: gui.cycleContainerLogsTail,
Description: gui.Tr.CycleContainerLogsTail,
},
{
ViewName: "services",
Key: 'U',
Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/services_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
if service.Container == nil {
return "services-" + service.ID
}
return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State
return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State + "-" + gui.State.ContainerLogsTail
},
},
ListPanel: panels.ListPanel[*commands.Service]{
Expand Down
2 changes: 2 additions & 0 deletions pkg/i18n/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type TranslationSet struct {
NextContext string
Attach string
ViewLogs string
CycleContainerLogsTail string
UpProject string
DownProject string
ServicesTitle string
Expand Down Expand Up @@ -196,6 +197,7 @@ func englishSet() TranslationSet {
NextContext: "next tab",
Attach: "attach",
ViewLogs: "view logs",
CycleContainerLogsTail: "cycle how many log lines are shown",
UpProject: "up project",
DownProject: "down project",
RemoveImage: "remove image",
Expand Down