mirror of
https://github.com/bcicen/ctop.git
synced 2025-12-06 15:16:41 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2011b8bc7 | ||
|
|
40fd9e935a | ||
|
|
b88c143914 | ||
|
|
0a05007c4e | ||
|
|
c47ba3f804 | ||
|
|
79a3f361a7 | ||
|
|
65399a37e5 | ||
|
|
25a3fcf731 | ||
|
|
17e2c2df8e | ||
|
|
240345d527 | ||
|
|
2d284d9277 | ||
|
|
bfa5c5944f | ||
|
|
e1051cd40f | ||
|
|
13029cc7fe | ||
|
|
58d9e4e194 | ||
|
|
4de7036e2f |
15
Dockerfile
15
Dockerfile
@@ -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
|
||||
COPY ./ctop /ctop
|
||||
COPY --from=0 /go/bin/ctop /ctop
|
||||
ENTRYPOINT ["/ctop"]
|
||||
|
||||
@@ -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/
|
||||
17
Makefile
17
Makefile
@@ -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)"
|
||||
|
||||
clean:
|
||||
rm -rf build/ release/
|
||||
rm -rf _build/ _release/
|
||||
|
||||
build:
|
||||
glide install
|
||||
@@ -16,21 +16,18 @@ build-dev:
|
||||
|
||||
build-all:
|
||||
mkdir -p build
|
||||
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=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=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=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
|
||||
|
||||
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 .
|
||||
|
||||
release:
|
||||
mkdir release
|
||||
mkdir _release
|
||||
go get github.com/progrium/gh-release/...
|
||||
cp build/* release
|
||||
cp _build/* _release
|
||||
gh-release create bcicen/$(NAME) $(VERSION) \
|
||||
$(shell git rev-parse --abbrev-ref HEAD) $(VERSION)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Fetch the [latest release](https://github.com/bcicen/ctop/releases) for your pla
|
||||
#### Linux
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ brew install ctop
|
||||
```
|
||||
or
|
||||
```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
|
||||
```
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
api "github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
// Docker collector
|
||||
type Docker struct {
|
||||
metrics.Metrics
|
||||
models.Metrics
|
||||
id string
|
||||
client *api.Client
|
||||
running bool
|
||||
stream chan metrics.Metrics
|
||||
stream chan models.Metrics
|
||||
done chan bool
|
||||
lastCpu float64
|
||||
lastSysCpu float64
|
||||
@@ -19,7 +19,7 @@ type Docker struct {
|
||||
|
||||
func NewDocker(client *api.Client, id string) *Docker {
|
||||
return &Docker{
|
||||
Metrics: metrics.Metrics{},
|
||||
Metrics: models.Metrics{},
|
||||
id: id,
|
||||
client: client,
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func NewDocker(client *api.Client, id string) *Docker {
|
||||
|
||||
func (c *Docker) Start() {
|
||||
c.done = make(chan bool)
|
||||
c.stream = make(chan metrics.Metrics)
|
||||
c.stream = make(chan models.Metrics)
|
||||
stats := make(chan *api.Stats)
|
||||
|
||||
go func() {
|
||||
@@ -61,10 +61,14 @@ func (c *Docker) Running() bool {
|
||||
return c.running
|
||||
}
|
||||
|
||||
func (c *Docker) Stream() chan metrics.Metrics {
|
||||
func (c *Docker) Stream() chan models.Metrics {
|
||||
return c.stream
|
||||
}
|
||||
|
||||
func (c *Docker) Logs() LogCollector {
|
||||
return &DockerLogs{c.id, c.client, make(chan bool)}
|
||||
}
|
||||
|
||||
// Stop collector
|
||||
func (c *Docker) Stop() {
|
||||
c.done <- true
|
||||
|
||||
74
connector/collector/docker_logs.go
Normal file
74
connector/collector/docker_logs.go
Normal 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
|
||||
}
|
||||
@@ -4,10 +4,24 @@ import (
|
||||
"math"
|
||||
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/models"
|
||||
)
|
||||
|
||||
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 {
|
||||
return int(num + math.Copysign(0.5, num))
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
)
|
||||
|
||||
// Mock collector
|
||||
type Mock struct {
|
||||
metrics.Metrics
|
||||
stream chan metrics.Metrics
|
||||
models.Metrics
|
||||
stream chan models.Metrics
|
||||
done bool
|
||||
running bool
|
||||
aggression int64
|
||||
@@ -20,7 +20,7 @@ type Mock struct {
|
||||
|
||||
func NewMock(a int64) *Mock {
|
||||
c := &Mock{
|
||||
Metrics: metrics.Metrics{},
|
||||
Metrics: models.Metrics{},
|
||||
aggression: a,
|
||||
}
|
||||
c.MemLimit = 2147483648
|
||||
@@ -33,7 +33,7 @@ func (c *Mock) Running() bool {
|
||||
|
||||
func (c *Mock) Start() {
|
||||
c.done = false
|
||||
c.stream = make(chan metrics.Metrics)
|
||||
c.stream = make(chan models.Metrics)
|
||||
go c.run()
|
||||
}
|
||||
|
||||
@@ -41,10 +41,14 @@ func (c *Mock) Stop() {
|
||||
c.done = true
|
||||
}
|
||||
|
||||
func (c *Mock) Stream() chan metrics.Metrics {
|
||||
func (c *Mock) Stream() chan models.Metrics {
|
||||
return c.stream
|
||||
}
|
||||
|
||||
func (c *Mock) Logs() LogCollector {
|
||||
return &MockLogs{make(chan bool)}
|
||||
}
|
||||
|
||||
func (c *Mock) run() {
|
||||
c.running = true
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
|
||||
31
connector/collector/mock_logs.go
Normal file
31
connector/collector/mock_logs.go
Normal 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 }
|
||||
@@ -5,17 +5,17 @@ package collector
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
)
|
||||
|
||||
// Runc collector
|
||||
type Runc struct {
|
||||
metrics.Metrics
|
||||
models.Metrics
|
||||
id string
|
||||
libc libcontainer.Container
|
||||
stream chan metrics.Metrics
|
||||
stream chan models.Metrics
|
||||
done bool
|
||||
running bool
|
||||
interval int // collection interval, in seconds
|
||||
@@ -25,7 +25,7 @@ type Runc struct {
|
||||
|
||||
func NewRunc(libc libcontainer.Container) *Runc {
|
||||
c := &Runc{
|
||||
Metrics: metrics.Metrics{},
|
||||
Metrics: models.Metrics{},
|
||||
id: libc.ID(),
|
||||
libc: libc,
|
||||
interval: 1,
|
||||
@@ -39,7 +39,7 @@ func (c *Runc) Running() bool {
|
||||
|
||||
func (c *Runc) Start() {
|
||||
c.done = false
|
||||
c.stream = make(chan metrics.Metrics)
|
||||
c.stream = make(chan models.Metrics)
|
||||
go c.run()
|
||||
}
|
||||
|
||||
@@ -47,10 +47,14 @@ func (c *Runc) Stop() {
|
||||
c.done = true
|
||||
}
|
||||
|
||||
func (c *Runc) Stream() chan metrics.Metrics {
|
||||
func (c *Runc) Stream() chan models.Metrics {
|
||||
return c.stream
|
||||
}
|
||||
|
||||
func (c *Runc) Logs() LogCollector {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Runc) run() {
|
||||
c.running = true
|
||||
defer close(c.stream)
|
||||
|
||||
@@ -66,7 +66,7 @@ func portsFormat(ports map[api.Port][]api.PortBinding) string {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/connector/collector"
|
||||
"github.com/bcicen/ctop/cwidgets"
|
||||
"github.com/bcicen/ctop/cwidgets/compact"
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -13,19 +14,19 @@ var (
|
||||
|
||||
// Metrics and metadata representing a container
|
||||
type Container struct {
|
||||
metrics.Metrics
|
||||
models.Metrics
|
||||
Id string
|
||||
Meta map[string]string
|
||||
Widgets *compact.Compact
|
||||
Display bool // display this container in compact view
|
||||
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)
|
||||
return &Container{
|
||||
Metrics: metrics.NewMetrics(),
|
||||
Metrics: models.NewMetrics(),
|
||||
Id: id,
|
||||
Meta: make(map[string]string),
|
||||
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
|
||||
func (c *Container) Read(stream chan metrics.Metrics) {
|
||||
func (c *Container) Read(stream chan models.Metrics) {
|
||||
go func() {
|
||||
for metrics := range stream {
|
||||
c.Metrics = metrics
|
||||
c.updater.SetMetrics(metrics)
|
||||
}
|
||||
log.Infof("reader stopped for container: %s", c.Id)
|
||||
c.Metrics = metrics.NewMetrics()
|
||||
c.Metrics = models.NewMetrics()
|
||||
c.Widgets.Reset()
|
||||
}()
|
||||
log.Infof("reader started for container: %s", c.Id)
|
||||
20
cursor.go
20
cursor.go
@@ -142,10 +142,11 @@ func (gc *GridCursor) PgUp() {
|
||||
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()),
|
||||
float64(0)))
|
||||
}
|
||||
|
||||
active := gc.filtered[idx]
|
||||
next := gc.filtered[nextidx]
|
||||
@@ -164,11 +165,11 @@ func (gc *GridCursor) PgDown() {
|
||||
return
|
||||
}
|
||||
|
||||
var nextidx int
|
||||
nextidx = int(math.Min(float64(gc.Len()-1),
|
||||
float64(idx+cGrid.MaxRows())))
|
||||
nextidx := int(math.Min(float64(gc.Len()-1), float64(idx+cGrid.MaxRows())))
|
||||
if gc.pgCount() > 0 {
|
||||
cGrid.Offset = int(math.Min(float64(cGrid.Offset+cGrid.MaxRows()),
|
||||
float64(gc.Len()-cGrid.MaxRows())))
|
||||
}
|
||||
|
||||
active := gc.filtered[idx]
|
||||
next := gc.filtered[nextidx]
|
||||
@@ -180,3 +181,12 @@ func (gc *GridCursor) PgDown() {
|
||||
cGrid.Align()
|
||||
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
|
||||
}
|
||||
|
||||
@@ -22,9 +22,14 @@ func NewCompactGrid() *CompactGrid {
|
||||
|
||||
func (cg *CompactGrid) Align() {
|
||||
y := cg.Y
|
||||
|
||||
if cg.Offset >= len(cg.Rows) {
|
||||
cg.Offset = 0
|
||||
}
|
||||
if cg.Offset < 0 {
|
||||
cg.Offset = 0
|
||||
}
|
||||
|
||||
// update row ypos, width recursively
|
||||
for _, r := range cg.pageRows() {
|
||||
r.SetY(y)
|
||||
|
||||
@@ -2,7 +2,7 @@ package compact
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
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.SetNet(m.NetRx, m.NetTx)
|
||||
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent)
|
||||
|
||||
83
cwidgets/expanded/logs.go
Normal file
83
cwidgets/expanded/logs.go
Normal 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 }
|
||||
@@ -2,7 +2,7 @@ package expanded
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
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) 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.Net.Update(m.NetRx, m.NetTx)
|
||||
e.Mem.Update(int(m.MemUsage), int(m.MemLimit))
|
||||
|
||||
@@ -2,12 +2,12 @@ package cwidgets
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
"github.com/bcicen/ctop/models"
|
||||
)
|
||||
|
||||
var log = logging.Init()
|
||||
|
||||
type WidgetUpdater interface {
|
||||
SetMeta(string, string)
|
||||
SetMetrics(metrics.Metrics)
|
||||
SetMetrics(models.Metrics)
|
||||
}
|
||||
|
||||
19
debug.go
19
debug.go
@@ -3,11 +3,14 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/bcicen/ctop/container"
|
||||
ui "github.com/gizak/termui"
|
||||
)
|
||||
|
||||
var mstats = &runtime.MemStats{}
|
||||
|
||||
func logEvent(e ui.Event) {
|
||||
var s string
|
||||
s += fmt.Sprintf("Type=%s", quote(e.Type))
|
||||
@@ -19,6 +22,22 @@ func logEvent(e ui.Event) {
|
||||
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
|
||||
func dumpContainer(c *container.Container) {
|
||||
msg := fmt.Sprintf("logging state for container: %s\n", c.Id)
|
||||
|
||||
4
main.go
4
main.go
@@ -4,6 +4,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/bcicen/ctop/config"
|
||||
"github.com/bcicen/ctop/connector"
|
||||
@@ -18,13 +19,14 @@ import (
|
||||
var (
|
||||
build = "none"
|
||||
version = "dev-build"
|
||||
goVersion = runtime.Version()
|
||||
|
||||
log *logging.CTopLogger
|
||||
cursor *GridCursor
|
||||
cGrid *compact.CompactGrid
|
||||
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() {
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
package metrics
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Log struct {
|
||||
Timestamp time.Time
|
||||
Message string
|
||||
}
|
||||
|
||||
type Metrics struct {
|
||||
CPUUtil int
|
||||
@@ -24,10 +31,3 @@ func NewMetrics() Metrics {
|
||||
Pids: -1,
|
||||
}
|
||||
}
|
||||
|
||||
type Collector interface {
|
||||
Stream() chan Metrics
|
||||
Running() bool
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
Reference in New Issue
Block a user