Skip to content

Commit

Permalink
allow configuring docker log args from within lazydocker
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseduffield committed Nov 26, 2022
1 parent 553b985 commit 78d0ab6
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 26 deletions.
24 changes: 20 additions & 4 deletions pkg/gui/arrangement.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map
infoSectionSize = 1
}

mainBox := &boxlayout.Box{
Direction: boxlayout.ROW,
Weight: mainSectionWeight,
Children: []*boxlayout.Box{
{
Window: "main",
Weight: 1,
},
},
}

showMainInfoView := true
if showMainInfoView {
mainBox.Children = utils.Append(mainBox.Children, &boxlayout.Box{
Window: "mainInfo",
Size: 3,
})
}

root := &boxlayout.Box{
Direction: boxlayout.ROW,
Children: []*boxlayout.Box{
Expand All @@ -47,10 +66,7 @@ func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map
Weight: sideSectionWeight,
ConditionalChildren: gui.sidePanelChildren,
},
{
Window: "main",
Weight: mainSectionWeight,
},
mainBox,
},
},
{
Expand Down
11 changes: 9 additions & 2 deletions pkg/gui/confirmation_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,21 @@ func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, i
height/2 + panelHeight/2
}

func (gui *Gui) createPromptPanel(title string, handleConfirm func(*gocui.Gui, *gocui.View) error) error {
func (gui *Gui) Prompt(title string, handleConfirm func(string) error) error {
gui.Views.Confirmation.ClearTextArea()

wrappedHandleConfirm := func(g *gocui.Gui, v *gocui.View) error {
input := gui.trimmedContent(v)
return handleConfirm(input)
}

gui.onNewPopupPanel()
err := gui.prepareConfirmationPanel(title, "", false)
if err != nil {
return err
}
gui.Views.Confirmation.Editable = true
return gui.setKeyBindings(gui.g, handleConfirm, nil)
return gui.setKeyBindings(gui.g, wrappedHandleConfirm, nil)
}

func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) error {
Expand Down
14 changes: 7 additions & 7 deletions pkg/gui/container_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (gui *Gui) renderContainerLogsToMain(container *commands.Container) tasks.T
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,
Wrap: gui.State.LogConfig.Wrap,
Autoscroll: true,
})
}
Expand All @@ -37,7 +37,7 @@ func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, ctx

mainView := gui.Views.Main

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

Expand Down Expand Up @@ -85,7 +85,7 @@ func (gui *Gui) renderLogsToStdout(container *commands.Container) {
}
}()

if err := gui.writeContainerLogs(container, ctx, os.Stdout); err != nil {
if err := gui.writeContainerLogs(container, ctx, os.Stdout, gui.State.LogConfig); err != nil {
gui.Log.Error(err)
return
}
Expand All @@ -104,13 +104,13 @@ func (gui *Gui) promptToReturn() {
}
}

func (gui *Gui) writeContainerLogs(container *commands.Container, ctx context.Context, writer io.Writer) error {
func (gui *Gui) writeContainerLogs(container *commands.Container, ctx context.Context, writer io.Writer, logConfig LogConfig) 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,
Tail: gui.Config.UserConfig.Logs.Tail,
Timestamps: logConfig.Timestamps,
Since: logConfig.Since,
Tail: logConfig.Tail,
Follow: true,
})
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/gui/containers_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,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.logArgsKey()
},
},
ListPanel: panels.ListPanel[*commands.Container]{
Expand Down Expand Up @@ -239,7 +239,7 @@ func (gui *Gui) renderContainerTop(container *commands.Container) tasks.TaskFunc
},
Duration: time.Second,
Before: func(ctx context.Context) { gui.clearMainView() },
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
Wrap: gui.State.LogConfig.Wrap,
Autoscroll: false,
})
}
Expand Down
23 changes: 19 additions & 4 deletions pkg/gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ type guiState struct {
// Maintains the state of manual filtering i.e. typing in a substring
// to filter on in the current panel.
Filter filterState

LogConfig LogConfig
}

type LogConfig struct {
Tail string
Since string
Autoscroll bool
Timestamps bool
Wrap bool
}

type filterState struct {
Expand Down Expand Up @@ -123,7 +133,13 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
},
},
ViewStack: []string{},

LogConfig: LogConfig{
Tail: config.UserConfig.Logs.Tail,
Since: config.UserConfig.Logs.Since,
Timestamps: config.UserConfig.Logs.Timestamps,
Wrap: config.UserConfig.Gui.WrapMainPanel,
Autoscroll: true,
},
ShowExitedContainers: true,
}

Expand Down Expand Up @@ -424,9 +440,8 @@ func (gui *Gui) openFile(filename string) error {
}

func (gui *Gui) handleCustomCommand(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(gui.Tr.CustomCommandTitle, func(g *gocui.Gui, v *gocui.View) error {
command := gui.trimmedContent(v)
return gui.runSubprocess(gui.OSCommand.RunCustomCommand(command))
return gui.Prompt(gui.Tr.CustomCommandTitle, func(input string) error {
return gui.runSubprocess(gui.OSCommand.RunCustomCommand(input))
})
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/gui/keybindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: wrappedHandler(gui.escapeFilterPrompt),
},
{
ViewName: "",
Key: 'i',
Modifier: gocui.ModNone,
Handler: wrappedHandler(gui.handleOpenLogMenu),
Description: "Set log args (tail, since, etc)",
},
{
ViewName: "",
Key: 'J',
Expand Down
4 changes: 4 additions & 0 deletions pkg/gui/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}

if err := gui.renderMainInfoView(); err != nil {
return err
}

// here is a good place log some stuff
// if you download humanlog and do tail -f development.log | humanlog
// this will let you see these branches as prettified json
Expand Down
102 changes: 102 additions & 0 deletions pkg/gui/main_info_view.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package gui

import (
"fmt"

"github.com/fatih/color"
"github.com/jesseduffield/lazydocker/pkg/gui/types"
)

func (gui *Gui) renderMainInfoView() error {
str := ""
keyColorSprintFn := color.New(color.FgMagenta).SprintFunc()
valueColorSprintFn := color.New(color.FgGreen).SprintFunc()

keyVal := func(key, value string) string {
return fmt.Sprintf("%s:%s ", keyColorSprintFn(key), valueColorSprintFn(value))
}
str += keyVal("Tail", blankToNil(gui.State.LogConfig.Tail))
str += keyVal("Since", blankToNil(gui.State.LogConfig.Since))
str += keyVal("Timestamps", boolToStr(gui.State.LogConfig.Timestamps))
str += keyVal("Wrap", boolToStr(gui.State.LogConfig.Wrap))
str += keyVal("Autoscroll", boolToStr(gui.Views.Main.Autoscroll))

return gui.renderString(gui.g, "mainInfo", str)
}

func boolToStr(b bool) string {
if b {
return "On"
}
return "Off"
}

func blankToNil(s string) string {
if s == "" {
return "-"
}
return s
}

func (gui *Gui) reselectSideListItem() error {
currentSidePanel, ok := gui.currentSidePanel()
if ok {
if err := currentSidePanel.HandleSelect(); err != nil {
return err
}
}
return nil
}

func (gui *Gui) handleOpenLogMenu() error {
return gui.Menu(CreateMenuOptions{
Title: "Log Options",
Items: []*types.MenuItem{
{
Label: "Set tail",
OnPress: func() error {
return gui.Prompt("Set tail value (e.g. 200). Unset with empty value", func(input string) error {
gui.State.LogConfig.Tail = input
return gui.reselectSideListItem()
})
},
},
{
Label: "Set since",
OnPress: func() error {
return gui.Prompt("Set since value (e.g. 60m). Unset with empty value", func(input string) error {
gui.State.LogConfig.Since = input
return gui.reselectSideListItem()
})
},
},
{
Label: "Toggle timestamps",
OnPress: func() error {
gui.State.LogConfig.Timestamps = !gui.State.LogConfig.Timestamps
return gui.reselectSideListItem()
},
},
{
Label: "Toggle wrap",
OnPress: func() error {
gui.State.LogConfig.Wrap = !gui.State.LogConfig.Wrap
return gui.reselectSideListItem()
},
},
{
Label: "Toggle autoscroll",
OnPress: func() error {
gui.Views.Main.Autoscroll = !gui.Views.Main.Autoscroll
// the view will refresh automatically
return nil
},
},
},
})
}

func (gui *Gui) logArgsKey() string {
// not including autoscroll because that doesn't require refetching the logs
return gui.State.LogConfig.Since + gui.State.LogConfig.Tail + boolToStr(gui.State.LogConfig.Timestamps) + boolToStr(gui.State.LogConfig.Wrap)
}
4 changes: 2 additions & 2 deletions pkg/gui/project_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
}
},
GetItemContextCacheKey: func(project *commands.Project) string {
return "projects-" + project.Name
return "projects-" + project.Name + gui.logArgsKey()
},
},

Expand Down Expand Up @@ -115,7 +115,7 @@ func (gui *Gui) creditsStr() string {
func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
return gui.NewTask(TaskOpts{
Autoscroll: true,
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
Wrap: gui.State.LogConfig.Wrap,
Func: func(ctx context.Context) {
gui.clearMainView()

Expand Down
9 changes: 6 additions & 3 deletions pkg/gui/services_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
}
},
GetItemContextCacheKey: func(service *commands.Service) string {
key := "services-" + service.ID + "-" + gui.logArgsKey()

if service.Container == nil {
return "services-" + service.ID
return key
}
return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State

return key + service.Container.ID + "-" + service.Container.Container.State
},
},
ListPanel: panels.ListPanel[*commands.Service]{
Expand Down Expand Up @@ -117,7 +120,7 @@ func (gui *Gui) renderServiceTop(service *commands.Service) tasks.TaskFunc {
},
Duration: time.Second,
Before: func(ctx context.Context) { gui.clearMainView() },
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
Wrap: gui.State.LogConfig.Wrap,
Autoscroll: false,
})
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/tasks_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (gui *Gui) NewSimpleRenderStringTask(getContent func() string) tasks.TaskFu
return gui.NewRenderStringTask(RenderStringTaskOpts{
GetStrContent: getContent,
Autoscroll: false,
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
Wrap: gui.State.LogConfig.Wrap,
})
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/view_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {

func (gui *Gui) resetMainView() {
gui.State.Panels.Main.ObjectKey = ""
gui.Views.Main.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
gui.Views.Main.Wrap = gui.State.LogConfig.Wrap
}

// if the cursor down past the last item, move it to the last line
Expand Down
4 changes: 4 additions & 0 deletions pkg/gui/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ type Views struct {
// main panel
Main *gocui.View

// shows information about what's being rendered in the main panel (e.g. `docker logs` tail arg)
MainInfo *gocui.View

// bottom line
Options *gocui.View
Information *gocui.View
Expand Down Expand Up @@ -72,6 +75,7 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
{viewPtr: &gui.Views.Volumes, name: "volumes", autoPosition: true},

{viewPtr: &gui.Views.Main, name: "main", autoPosition: true},
{viewPtr: &gui.Views.MainInfo, name: "mainInfo", autoPosition: true},

// bottom line
{viewPtr: &gui.Views.Options, name: "options", autoPosition: true},
Expand Down
8 changes: 8 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,11 @@ func IsValidHexValue(v string) bool {
func OpensMenuStyle(str string) string {
return ColoredString(fmt.Sprintf("%s...", str), color.FgMagenta)
}

func Prepend[T any](slice []T, item T) []T {
return append([]T{item}, slice...)
}

func Append[T any](slice []T, item T) []T {
return append(slice, item)
}

0 comments on commit 78d0ab6

Please sign in to comment.