Compare commits

...

16 Commits

Author SHA1 Message Date
Bradley Cicenas
a2011b8bc7 v0.6.1 2017-06-29 14:02:52 +00:00
Bradley Cicenas
40fd9e935a combine image build steps 2017-06-29 14:02:52 +00:00
Bradley Cicenas
b88c143914 add offset sanity check to CompactGrid Align() 2017-07-07 15:43:03 +03:00
Bradley Cicenas
0a05007c4e skip offset updates in page scroll if no pages 2017-07-07 15:38:02 +03:00
Bradley Cicenas
c47ba3f804 add pgCount() method to GridCursor 2017-07-07 15:28:26 +03:00
Bradley Cicenas
79a3f361a7 add container log struct to models, collectors 2017-07-04 12:32:25 +00:00
Bradley Cicenas
65399a37e5 add log panel to expanded widgets 2017-06-29 14:02:52 +00:00
Bradley Cicenas
25a3fcf731 add runtimestats, stack logging to debug 2017-06-28 09:12:24 -03:00
Bradley Cicenas
17e2c2df8e add LogCollector interface, docker, mock log collectors 2017-06-27 14:18:17 -03:00
Bradley Cicenas
240345d527 add StreamLogs() to collector interface 2017-06-26 15:35:57 +00:00
Bradley Cicenas
2d284d9277 rename metrics subpackage 2017-06-26 15:35:57 +00:00
Bradley Cicenas
bfa5c5944f rename 2017-06-26 15:35:57 +00:00
Bradley Cicenas
e1051cd40f use underscore-prefixed build dir in makefile 2017-06-24 08:04:56 -03:00
Bradley Cicenas
13029cc7fe add go runtime to version output 2017-06-19 12:23:39 +00:00
Bradley Cicenas
58d9e4e194 reverse host and container port in metadata 2017-06-18 17:17:56 -03:00
Bradley Cicenas
4de7036e2f fix release url 2017-06-14 15:04:47 -03:00
22 changed files with 332 additions and 78 deletions

View File

@@ -1,3 +1,16 @@
FROM quay.io/vektorcloud/go:1.8
RUN apk add --no-cache make
COPY glide.* /go/src/github.com/bcicen/ctop/
WORKDIR /go/src/github.com/bcicen/ctop/
RUN glide install
COPY . /go/src/github.com/bcicen/ctop
RUN make build && \
mkdir -p /go/bin && \
mv -v ctop /go/bin/
FROM scratch FROM scratch
COPY ./ctop /ctop COPY --from=0 /go/bin/ctop /ctop
ENTRYPOINT ["/ctop"] ENTRYPOINT ["/ctop"]

View File

@@ -1,12 +0,0 @@
FROM quay.io/vektorcloud/go:1.8
RUN apk add --no-cache make
COPY glide.* /go/src/github.com/bcicen/ctop/
WORKDIR /go/src/github.com/bcicen/ctop/
RUN glide install
COPY . /go/src/github.com/bcicen/ctop
RUN make build && \
mkdir -p /go/bin && \
mv -v ctop /go/bin/

View File

@@ -5,7 +5,7 @@ EXT_LD_FLAGS="-Wl,--allow-multiple-definition"
LD_FLAGS="-w -X main.version=$(VERSION) -X main.build=$(BUILD) -extldflags=$(EXT_LD_FLAGS)" LD_FLAGS="-w -X main.version=$(VERSION) -X main.build=$(BUILD) -extldflags=$(EXT_LD_FLAGS)"
clean: clean:
rm -rf build/ release/ rm -rf _build/ _release/
build: build:
glide install glide install
@@ -16,21 +16,18 @@ build-dev:
build-all: build-all:
mkdir -p build mkdir -p build
GOOS=darwin GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o build/ctop-$(VERSION)-darwin-amd64 GOOS=darwin GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-darwin-amd64
GOOS=linux GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o build/ctop-$(VERSION)-linux-amd64 GOOS=linux GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-amd64
GOOS=linux GOARCH=arm go build -tags release -ldflags $(LD_FLAGS) -o build/ctop-$(VERSION)-linux-arm GOOS=linux GOARCH=arm go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm
GOOS=linux GOARCH=arm64 go build -tags release -ldflags $(LD_FLAGS) -o build/ctop-$(VERSION)-linux-arm64 GOOS=linux GOARCH=arm64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm64
image: image:
docker build -t ctop_build -f Dockerfile_build .
docker create --name=ctop_built ctop_build ctop -v
docker cp ctop_built:/go/bin/ctop .
docker build -t ctop -f Dockerfile . docker build -t ctop -f Dockerfile .
release: release:
mkdir release mkdir _release
go get github.com/progrium/gh-release/... go get github.com/progrium/gh-release/...
cp build/* release cp _build/* _release
gh-release create bcicen/$(NAME) $(VERSION) \ gh-release create bcicen/$(NAME) $(VERSION) \
$(shell git rev-parse --abbrev-ref HEAD) $(VERSION) $(shell git rev-parse --abbrev-ref HEAD) $(VERSION)

View File

@@ -20,7 +20,7 @@ Fetch the [latest release](https://github.com/bcicen/ctop/releases) for your pla
#### Linux #### Linux
```bash ```bash
sudo wget https://github.com/bcicen/ctop/releases/download/v0.6/ctop-0.6-linux-amd64 -O /usr/local/bin/ctop sudo wget https://github.com/bcicen/ctop/releases/download/v0.6.0/ctop-0.6.0-linux-amd64 -O /usr/local/bin/ctop
sudo chmod +x /usr/local/bin/ctop sudo chmod +x /usr/local/bin/ctop
``` ```
@@ -31,7 +31,7 @@ brew install ctop
``` ```
or or
```bash ```bash
sudo curl -Lo /usr/local/bin/ctop https://github.com/bcicen/ctop/releases/download/v0.6/ctop-0.6-darwin-amd64 sudo curl -Lo /usr/local/bin/ctop https://github.com/bcicen/ctop/releases/download/v0.6.0/ctop-0.6.0-darwin-amd64
sudo chmod +x /usr/local/bin/ctop sudo chmod +x /usr/local/bin/ctop
``` ```

View File

@@ -1 +1 @@
0.6.0 0.6.1

View File

@@ -1,17 +1,17 @@
package collector package collector
import ( import (
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
api "github.com/fsouza/go-dockerclient" api "github.com/fsouza/go-dockerclient"
) )
// Docker collector // Docker collector
type Docker struct { type Docker struct {
metrics.Metrics models.Metrics
id string id string
client *api.Client client *api.Client
running bool running bool
stream chan metrics.Metrics stream chan models.Metrics
done chan bool done chan bool
lastCpu float64 lastCpu float64
lastSysCpu float64 lastSysCpu float64
@@ -19,7 +19,7 @@ type Docker struct {
func NewDocker(client *api.Client, id string) *Docker { func NewDocker(client *api.Client, id string) *Docker {
return &Docker{ return &Docker{
Metrics: metrics.Metrics{}, Metrics: models.Metrics{},
id: id, id: id,
client: client, client: client,
} }
@@ -27,7 +27,7 @@ func NewDocker(client *api.Client, id string) *Docker {
func (c *Docker) Start() { func (c *Docker) Start() {
c.done = make(chan bool) c.done = make(chan bool)
c.stream = make(chan metrics.Metrics) c.stream = make(chan models.Metrics)
stats := make(chan *api.Stats) stats := make(chan *api.Stats)
go func() { go func() {
@@ -61,10 +61,14 @@ func (c *Docker) Running() bool {
return c.running return c.running
} }
func (c *Docker) Stream() chan metrics.Metrics { func (c *Docker) Stream() chan models.Metrics {
return c.stream return c.stream
} }
func (c *Docker) Logs() LogCollector {
return &DockerLogs{c.id, c.client, make(chan bool)}
}
// Stop collector // Stop collector
func (c *Docker) Stop() { func (c *Docker) Stop() {
c.done <- true c.done <- true

View File

@@ -0,0 +1,74 @@
package collector
import (
"bufio"
"context"
"io"
"strings"
"time"
"github.com/bcicen/ctop/models"
api "github.com/fsouza/go-dockerclient"
)
type DockerLogs struct {
id string
client *api.Client
done chan bool
}
func (l *DockerLogs) Stream() chan models.Log {
r, w := io.Pipe()
logCh := make(chan models.Log)
ctx, cancel := context.WithCancel(context.Background())
opts := api.LogsOptions{
Context: ctx,
Container: l.id,
OutputStream: w,
ErrorStream: w,
Stdout: true,
Stderr: true,
Tail: "10",
Follow: true,
Timestamps: true,
}
// read io pipe into channel
go func() {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
parts := strings.Split(scanner.Text(), " ")
ts := l.parseTime(parts[0])
logCh <- models.Log{ts, strings.Join(parts[1:], " ")}
}
}()
// connect to container log stream
go func() {
err := l.client.Logs(opts)
if err != nil {
log.Errorf("error reading container logs: %s", err)
}
}()
go func() {
select {
case <-l.done:
cancel()
}
}()
return logCh
}
func (l *DockerLogs) Stop() { l.done <- true }
func (l *DockerLogs) parseTime(s string) time.Time {
ts, err := time.Parse("2006-01-02T15:04:05.000000000Z", s)
if err != nil {
log.Errorf("failed to parse container log: %s", err)
ts = time.Now()
}
return ts
}

View File

@@ -4,10 +4,24 @@ import (
"math" "math"
"github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/models"
) )
var log = logging.Init() var log = logging.Init()
type LogCollector interface {
Stream() chan models.Log
Stop()
}
type Collector interface {
Stream() chan models.Metrics
Logs() LogCollector
Running() bool
Start()
Stop()
}
func round(num float64) int { func round(num float64) int {
return int(num + math.Copysign(0.5, num)) return int(num + math.Copysign(0.5, num))
} }

View File

@@ -6,13 +6,13 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
) )
// Mock collector // Mock collector
type Mock struct { type Mock struct {
metrics.Metrics models.Metrics
stream chan metrics.Metrics stream chan models.Metrics
done bool done bool
running bool running bool
aggression int64 aggression int64
@@ -20,7 +20,7 @@ type Mock struct {
func NewMock(a int64) *Mock { func NewMock(a int64) *Mock {
c := &Mock{ c := &Mock{
Metrics: metrics.Metrics{}, Metrics: models.Metrics{},
aggression: a, aggression: a,
} }
c.MemLimit = 2147483648 c.MemLimit = 2147483648
@@ -33,7 +33,7 @@ func (c *Mock) Running() bool {
func (c *Mock) Start() { func (c *Mock) Start() {
c.done = false c.done = false
c.stream = make(chan metrics.Metrics) c.stream = make(chan models.Metrics)
go c.run() go c.run()
} }
@@ -41,10 +41,14 @@ func (c *Mock) Stop() {
c.done = true c.done = true
} }
func (c *Mock) Stream() chan metrics.Metrics { func (c *Mock) Stream() chan models.Metrics {
return c.stream return c.stream
} }
func (c *Mock) Logs() LogCollector {
return &MockLogs{make(chan bool)}
}
func (c *Mock) run() { func (c *Mock) run() {
c.running = true c.running = true
rand.Seed(int64(time.Now().Nanosecond())) rand.Seed(int64(time.Now().Nanosecond()))

View File

@@ -0,0 +1,31 @@
package collector
import (
"time"
"github.com/bcicen/ctop/models"
)
const mockLog = "Cura ob pro qui tibi inveni dum qua fit donec amare illic mea, regem falli contexo pro peregrinorum heremo absconditi araneae meminerim deliciosas actionibus facere modico dura sonuerunt psalmi contra rerum, tempus mala anima volebant dura quae o modis."
type MockLogs struct {
done chan bool
}
func (l *MockLogs) Stream() chan models.Log {
logCh := make(chan models.Log)
go func() {
for {
select {
case <-l.done:
break
default:
logCh <- models.Log{time.Now(), mockLog}
time.Sleep(250 * time.Millisecond)
}
}
}()
return logCh
}
func (l *MockLogs) Stop() { l.done <- true }

View File

@@ -5,17 +5,17 @@ package collector
import ( import (
"time" "time"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
"github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
) )
// Runc collector // Runc collector
type Runc struct { type Runc struct {
metrics.Metrics models.Metrics
id string id string
libc libcontainer.Container libc libcontainer.Container
stream chan metrics.Metrics stream chan models.Metrics
done bool done bool
running bool running bool
interval int // collection interval, in seconds interval int // collection interval, in seconds
@@ -25,7 +25,7 @@ type Runc struct {
func NewRunc(libc libcontainer.Container) *Runc { func NewRunc(libc libcontainer.Container) *Runc {
c := &Runc{ c := &Runc{
Metrics: metrics.Metrics{}, Metrics: models.Metrics{},
id: libc.ID(), id: libc.ID(),
libc: libc, libc: libc,
interval: 1, interval: 1,
@@ -39,7 +39,7 @@ func (c *Runc) Running() bool {
func (c *Runc) Start() { func (c *Runc) Start() {
c.done = false c.done = false
c.stream = make(chan metrics.Metrics) c.stream = make(chan models.Metrics)
go c.run() go c.run()
} }
@@ -47,10 +47,14 @@ func (c *Runc) Stop() {
c.done = true c.done = true
} }
func (c *Runc) Stream() chan metrics.Metrics { func (c *Runc) Stream() chan models.Metrics {
return c.stream return c.stream
} }
func (c *Runc) Logs() LogCollector {
return nil
}
func (c *Runc) run() { func (c *Runc) run() {
c.running = true c.running = true
defer close(c.stream) defer close(c.stream)

View File

@@ -66,7 +66,7 @@ func portsFormat(ports map[api.Port][]api.PortBinding) string {
continue continue
} }
for _, binding := range v { for _, binding := range v {
s := fmt.Sprintf("%s -> %s:%s", k, binding.HostIP, binding.HostPort) s := fmt.Sprintf("%s:%s -> %s", binding.HostIP, binding.HostPort, k)
published = append(published, s) published = append(published, s)
} }
} }

View File

@@ -1,10 +1,11 @@
package container package container
import ( import (
"github.com/bcicen/ctop/connector/collector"
"github.com/bcicen/ctop/cwidgets" "github.com/bcicen/ctop/cwidgets"
"github.com/bcicen/ctop/cwidgets/compact" "github.com/bcicen/ctop/cwidgets/compact"
"github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
) )
var ( var (
@@ -13,19 +14,19 @@ var (
// Metrics and metadata representing a container // Metrics and metadata representing a container
type Container struct { type Container struct {
metrics.Metrics models.Metrics
Id string Id string
Meta map[string]string Meta map[string]string
Widgets *compact.Compact Widgets *compact.Compact
Display bool // display this container in compact view Display bool // display this container in compact view
updater cwidgets.WidgetUpdater updater cwidgets.WidgetUpdater
collector metrics.Collector collector collector.Collector
} }
func New(id string, collector metrics.Collector) *Container { func New(id string, collector collector.Collector) *Container {
widgets := compact.NewCompact(id) widgets := compact.NewCompact(id)
return &Container{ return &Container{
Metrics: metrics.NewMetrics(), Metrics: models.NewMetrics(),
Id: id, Id: id,
Meta: make(map[string]string), Meta: make(map[string]string),
Widgets: widgets, Widgets: widgets,
@@ -66,15 +67,20 @@ func (c *Container) SetState(s string) {
} }
} }
// Return container log collector
func (c *Container) Logs() collector.LogCollector {
return c.collector.Logs()
}
// Read metric stream, updating widgets // Read metric stream, updating widgets
func (c *Container) Read(stream chan metrics.Metrics) { func (c *Container) Read(stream chan models.Metrics) {
go func() { go func() {
for metrics := range stream { for metrics := range stream {
c.Metrics = metrics c.Metrics = metrics
c.updater.SetMetrics(metrics) c.updater.SetMetrics(metrics)
} }
log.Infof("reader stopped for container: %s", c.Id) log.Infof("reader stopped for container: %s", c.Id)
c.Metrics = metrics.NewMetrics() c.Metrics = models.NewMetrics()
c.Widgets.Reset() c.Widgets.Reset()
}() }()
log.Infof("reader started for container: %s", c.Id) log.Infof("reader started for container: %s", c.Id)

View File

@@ -142,10 +142,11 @@ func (gc *GridCursor) PgUp() {
return return
} }
var nextidx int nextidx := int(math.Max(0.0, float64(idx-cGrid.MaxRows())))
nextidx = int(math.Max(0.0, float64(idx-cGrid.MaxRows()))) if gc.pgCount() > 0 {
cGrid.Offset = int(math.Max(float64(cGrid.Offset-cGrid.MaxRows()), cGrid.Offset = int(math.Max(float64(cGrid.Offset-cGrid.MaxRows()),
float64(0))) float64(0)))
}
active := gc.filtered[idx] active := gc.filtered[idx]
next := gc.filtered[nextidx] next := gc.filtered[nextidx]
@@ -164,11 +165,11 @@ func (gc *GridCursor) PgDown() {
return return
} }
var nextidx int nextidx := int(math.Min(float64(gc.Len()-1), float64(idx+cGrid.MaxRows())))
nextidx = int(math.Min(float64(gc.Len()-1), if gc.pgCount() > 0 {
float64(idx+cGrid.MaxRows())))
cGrid.Offset = int(math.Min(float64(cGrid.Offset+cGrid.MaxRows()), cGrid.Offset = int(math.Min(float64(cGrid.Offset+cGrid.MaxRows()),
float64(gc.Len()-cGrid.MaxRows()))) float64(gc.Len()-cGrid.MaxRows())))
}
active := gc.filtered[idx] active := gc.filtered[idx]
next := gc.filtered[nextidx] next := gc.filtered[nextidx]
@@ -180,3 +181,12 @@ func (gc *GridCursor) PgDown() {
cGrid.Align() cGrid.Align()
ui.Render(cGrid) ui.Render(cGrid)
} }
// number of pages at current row count and term height
func (gc *GridCursor) pgCount() int {
pages := gc.Len() / cGrid.MaxRows()
if gc.Len()%cGrid.MaxRows() > 0 {
pages++
}
return pages
}

View File

@@ -22,9 +22,14 @@ func NewCompactGrid() *CompactGrid {
func (cg *CompactGrid) Align() { func (cg *CompactGrid) Align() {
y := cg.Y y := cg.Y
if cg.Offset >= len(cg.Rows) { if cg.Offset >= len(cg.Rows) {
cg.Offset = 0 cg.Offset = 0
} }
if cg.Offset < 0 {
cg.Offset = 0
}
// update row ypos, width recursively // update row ypos, width recursively
for _, r := range cg.pageRows() { for _, r := range cg.pageRows() {
r.SetY(y) r.SetY(y)

View File

@@ -2,7 +2,7 @@ package compact
import ( import (
"github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
@@ -59,7 +59,7 @@ func (row *Compact) SetMeta(k, v string) {
} }
} }
func (row *Compact) SetMetrics(m metrics.Metrics) { func (row *Compact) SetMetrics(m models.Metrics) {
row.SetCPU(m.CPUUtil) row.SetCPU(m.CPUUtil)
row.SetNet(m.NetRx, m.NetTx) row.SetNet(m.NetRx, m.NetTx)
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent) row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent)

83
cwidgets/expanded/logs.go Normal file
View File

@@ -0,0 +1,83 @@
package expanded
import (
"time"
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui"
)
type LogLines struct {
ts []time.Time
data []string
}
func NewLogLines(max int) *LogLines {
ll := &LogLines{
ts: make([]time.Time, max),
data: make([]string, max),
}
return ll
}
func (ll *LogLines) tail(n int) []string {
lines := make([]string, n)
for i := 0; i < n; i++ {
lines = append(lines, ll.data[len(ll.data)-i])
}
return lines
}
func (ll *LogLines) getLines(start, end int) []string {
if end < 0 {
return ll.data[start:]
}
return ll.data[start:end]
}
func (ll *LogLines) add(l models.Log) {
if len(ll.data) == cap(ll.data) {
ll.data = append(ll.data[:0], ll.data[1:]...)
ll.ts = append(ll.ts[:0], ll.ts[1:]...)
}
ll.ts = append(ll.ts, l.Timestamp)
ll.data = append(ll.data, l.Message)
log.Debugf("recorded log line: %v", l)
}
type Logs struct {
*ui.List
lines *LogLines
}
func NewLogs(stream chan models.Log) *Logs {
p := ui.NewList()
p.Y = ui.TermHeight() / 2
p.X = 0
p.Height = ui.TermHeight() - p.Y
p.Width = ui.TermWidth()
//p.Overflow = "wrap"
p.ItemFgColor = ui.ThemeAttr("par.text.fg")
i := &Logs{p, NewLogLines(4098)}
go func() {
for line := range stream {
i.lines.add(line)
ui.Render(i)
}
}()
return i
}
func (w *Logs) Align() {
w.X = colWidth[0]
w.List.Align()
}
func (w *Logs) Buffer() ui.Buffer {
maxLines := w.Height - 2
offset := len(w.lines.data) - maxLines
w.Items = w.lines.getLines(offset, -1)
return w.List.Buffer()
}
// number of rows a line will occupy at current panel width
func (w *Logs) lineHeight(s string) int { return (len(s) / w.InnerWidth()) + 1 }

View File

@@ -2,7 +2,7 @@ package expanded
import ( import (
"github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
@@ -55,7 +55,7 @@ func (e *Expanded) Down() {
func (e *Expanded) SetWidth(w int) { e.Width = w } func (e *Expanded) SetWidth(w int) { e.Width = w }
func (e *Expanded) SetMeta(k, v string) { e.Info.Set(k, v) } func (e *Expanded) SetMeta(k, v string) { e.Info.Set(k, v) }
func (e *Expanded) SetMetrics(m metrics.Metrics) { func (e *Expanded) SetMetrics(m models.Metrics) {
e.Cpu.Update(m.CPUUtil) e.Cpu.Update(m.CPUUtil)
e.Net.Update(m.NetRx, m.NetTx) e.Net.Update(m.NetRx, m.NetTx)
e.Mem.Update(int(m.MemUsage), int(m.MemLimit)) e.Mem.Update(int(m.MemUsage), int(m.MemLimit))

View File

@@ -2,12 +2,12 @@ package cwidgets
import ( import (
"github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/metrics" "github.com/bcicen/ctop/models"
) )
var log = logging.Init() var log = logging.Init()
type WidgetUpdater interface { type WidgetUpdater interface {
SetMeta(string, string) SetMeta(string, string)
SetMetrics(metrics.Metrics) SetMetrics(models.Metrics)
} }

View File

@@ -3,11 +3,14 @@ package main
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"runtime"
"github.com/bcicen/ctop/container" "github.com/bcicen/ctop/container"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
var mstats = &runtime.MemStats{}
func logEvent(e ui.Event) { func logEvent(e ui.Event) {
var s string var s string
s += fmt.Sprintf("Type=%s", quote(e.Type)) s += fmt.Sprintf("Type=%s", quote(e.Type))
@@ -19,6 +22,22 @@ func logEvent(e ui.Event) {
log.Debugf("new event: %s", s) log.Debugf("new event: %s", s)
} }
func runtimeStats() {
var msg string
msg += fmt.Sprintf("cgo calls=%v", runtime.NumCgoCall())
msg += fmt.Sprintf(" routines=%v", runtime.NumGoroutine())
runtime.ReadMemStats(mstats)
msg += fmt.Sprintf(" numgc=%v", mstats.NumGC)
msg += fmt.Sprintf(" alloc=%v", mstats.Alloc)
log.Debugf("runtime: %v", msg)
}
func runtimeStack() {
buf := make([]byte, 32768)
buf = buf[:runtime.Stack(buf, true)]
log.Infof(fmt.Sprintf("stack:\n%v", string(buf)))
}
// log container, metrics, and widget state // log container, metrics, and widget state
func dumpContainer(c *container.Container) { func dumpContainer(c *container.Container) {
msg := fmt.Sprintf("logging state for container: %s\n", c.Id) msg := fmt.Sprintf("logging state for container: %s\n", c.Id)

View File

@@ -4,6 +4,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"runtime"
"github.com/bcicen/ctop/config" "github.com/bcicen/ctop/config"
"github.com/bcicen/ctop/connector" "github.com/bcicen/ctop/connector"
@@ -18,13 +19,14 @@ import (
var ( var (
build = "none" build = "none"
version = "dev-build" version = "dev-build"
goVersion = runtime.Version()
log *logging.CTopLogger log *logging.CTopLogger
cursor *GridCursor cursor *GridCursor
cGrid *compact.CompactGrid cGrid *compact.CompactGrid
header *widgets.CTopHeader header *widgets.CTopHeader
versionStr = fmt.Sprintf("ctop version %v, build %v", version, build) versionStr = fmt.Sprintf("ctop version %v, build %v %v", version, build, goVersion)
) )
func main() { func main() {

View File

@@ -1,4 +1,11 @@
package metrics package models
import "time"
type Log struct {
Timestamp time.Time
Message string
}
type Metrics struct { type Metrics struct {
CPUUtil int CPUUtil int
@@ -24,10 +31,3 @@ func NewMetrics() Metrics {
Pids: -1, Pids: -1,
} }
} }
type Collector interface {
Stream() chan Metrics
Running() bool
Start()
Stop()
}