diff --git a/config/columns.go b/config/columns.go index fb539d8..6f564fa 100644 --- a/config/columns.go +++ b/config/columns.go @@ -71,6 +71,11 @@ var defaultColumns = []Column{ Label: "Container PID Count", Enabled: true, }, + Column{ + Name: "uptime", + Label: "Running uptime duration", + Enabled: true, + }, } type Column struct { diff --git a/config/param.go b/config/param.go index 281cc6c..f936b22 100644 --- a/config/param.go +++ b/config/param.go @@ -14,7 +14,7 @@ var defaultParams = []*Param{ }, &Param{ Key: "columns", - Val: "status,name,id,cpu,mem,net,io,pids", + Val: "status,name,id,cpu,mem,net,io,pids,uptime", Label: "Enabled Columns", }, } diff --git a/connector/docker.go b/connector/docker.go index 1b76424..06ec699 100644 --- a/connector/docker.go +++ b/connector/docker.go @@ -2,9 +2,11 @@ package connector import ( "fmt" - "github.com/op/go-logging" "strings" "sync" + "time" + + "github.com/op/go-logging" "github.com/bcicen/ctop/connector/collector" "github.com/bcicen/ctop/connector/manager" @@ -174,6 +176,7 @@ func (cm *Docker) refresh(c *container.Container) { c.SetMeta("IPs", ipsFormat(insp.NetworkSettings.Networks)) c.SetMeta("ports", portsFormat(insp.NetworkSettings.Ports)) c.SetMeta("created", insp.Created.Format("Mon Jan 2 15:04:05 2006")) + c.SetMeta("uptime", calcUptime(insp)) c.SetMeta("health", insp.State.Health.Status) c.SetMeta("[ENV-VAR]", strings.Join(insp.Config.Env, ";")) c.SetState(insp.State.Status) @@ -192,6 +195,15 @@ func (cm *Docker) inspect(id string) (insp *api.Container, found bool, failed bo return c, true, false } +func calcUptime(insp *api.Container) string { + endTime := insp.State.FinishedAt + if endTime.IsZero() { + endTime = time.Now() + } + uptime := endTime.Sub(insp.State.StartedAt) + return uptime.Truncate(time.Second).String() +} + // Mark all container IDs for refresh func (cm *Docker) refreshAll() { opts := api.ListContainersOptions{All: true} diff --git a/container/sort.go b/container/sort.go index 65b6c2b..2d91910 100644 --- a/container/sort.go +++ b/container/sort.go @@ -79,6 +79,15 @@ var Sorters = map[string]sortMethod{ } return stateMap[c1state] > stateMap[c2state] }, + "uptime": func(c1, c2 *Container) bool { + // Use secondary sort method if equal values + c1Uptime := c1.GetMeta("uptime") + c2Uptime := c2.GetMeta("uptime") + if c1Uptime == c2Uptime { + return nameSorter(c1, c2) + } + return c1Uptime > c2Uptime + }, } func SortFields() (fields []string) { diff --git a/cwidgets/compact/column.go b/cwidgets/compact/column.go index 7558dd9..eeb16af 100644 --- a/cwidgets/compact/column.go +++ b/cwidgets/compact/column.go @@ -22,6 +22,7 @@ var ( "net": NewNetCol, "io": NewIOCol, "pids": NewPIDCol, + "uptime": NewUptimeCol, } ) diff --git a/cwidgets/compact/text.go b/cwidgets/compact/text.go index 5b3432b..1346d01 100644 --- a/cwidgets/compact/text.go +++ b/cwidgets/compact/text.go @@ -89,6 +89,18 @@ func (w *PIDCol) SetMetrics(m models.Metrics) { w.setText(fmt.Sprintf("%d", m.Pids)) } +type UptimeCol struct { + *TextCol +} + +func NewUptimeCol() CompactCol { + return &UptimeCol{NewTextCol("UPTIME")} +} + +func (w *UptimeCol) SetMeta(m models.Meta) { + w.Text = m.Get("uptime") +} + type TextCol struct { *ui.Par header string diff --git a/cwidgets/single/info.go b/cwidgets/single/info.go index 98e51ab..559f823 100644 --- a/cwidgets/single/info.go +++ b/cwidgets/single/info.go @@ -6,7 +6,7 @@ import ( ui "github.com/gizak/termui" ) -var displayInfo = []string{"id", "name", "image", "ports", "IPs", "state", "created", "health"} +var displayInfo = []string{"id", "name", "image", "ports", "IPs", "state", "created", "uptime", "health"} type Info struct { *ui.Table