mirror of
https://github.com/bcicen/ctop.git
synced 2025-12-06 23:26:45 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b28beed3ee | ||
|
|
2e51406d00 | ||
|
|
c84b52ce40 | ||
|
|
4ee8cf621a | ||
|
|
192298c045 | ||
|
|
258536740d | ||
|
|
ef69744249 | ||
|
|
07f95a04b0 | ||
|
|
b2184bbc6d | ||
|
|
96b01eb3b9 | ||
|
|
03d4869361 | ||
|
|
4b7257908f | ||
|
|
1875013a76 | ||
|
|
dab2f926b9 | ||
|
|
ddce54f991 | ||
|
|
168e8f3aae |
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM quay.io/vektorcloud/glibc:latest
|
||||||
|
|
||||||
|
RUN ctop_url=$(wget -q -O - https://api.github.com/repos/bcicen/ctop/releases/latest | grep 'browser_' | cut -d\" -f4 |grep 'linux-amd64') && \
|
||||||
|
wget -q $ctop_url -O /ctop && \
|
||||||
|
chmod +x /ctop
|
||||||
|
|
||||||
|
ENTRYPOINT ["/ctop"]
|
||||||
17
README.md
17
README.md
@@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
Top-like interface for container metrics
|
Top-like interface for container metrics
|
||||||
|
|
||||||
ctop provides a concise and condensed overview of real-time metrics for multiple containers:
|
`ctop` provides a concise and condensed overview of real-time metrics for multiple containers:
|
||||||
<p align="center"><img src="_docs/img/grid.gif" alt="ctop"/></p>
|
<p align="center"><img src="_docs/img/grid.gif" alt="ctop"/></p>
|
||||||
|
|
||||||
as well as an [expanded view][expanded_view] for inspecting a specific container.
|
as well as an [expanded view][expanded_view] for inspecting a specific container.
|
||||||
|
|
||||||
ctop currently comes with built-in support for Docker; connectors for other container and cluster systems are planned for future releases.
|
`ctop` currently comes with built-in support for Docker; connectors for other container and cluster systems are planned for future releases.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Fetch the [latest release](https://github.com/bcicen/ctop/releases) for your pla
|
|||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/bcicen/ctop/releases/download/v0.4/ctop-0.4-linux-amd64 -O ctop
|
wget https://github.com/bcicen/ctop/releases/download/v0.4.1/ctop-0.4.1-linux-amd64 -O ctop
|
||||||
sudo mv ctop /usr/local/bin/
|
sudo mv ctop /usr/local/bin/
|
||||||
sudo chmod +x /usr/local/bin/ctop
|
sudo chmod +x /usr/local/bin/ctop
|
||||||
```
|
```
|
||||||
@@ -25,14 +25,21 @@ sudo chmod +x /usr/local/bin/ctop
|
|||||||
#### OS X
|
#### OS X
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -Lo ctop https://github.com/bcicen/ctop/releases/download/v0.4/ctop-0.4-darwin-amd64
|
curl -Lo ctop https://github.com/bcicen/ctop/releases/download/v0.4.1/ctop-0.4.1-darwin-amd64
|
||||||
sudo mv ctop /usr/local/bin/
|
sudo mv ctop /usr/local/bin/
|
||||||
sudo chmod +x /usr/local/bin/ctop
|
sudo chmod +x /usr/local/bin/ctop
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or run via Docker:
|
||||||
|
```bash
|
||||||
|
docker run -ti -v /var/run/docker.sock:/var/run/docker.sock quay.io/vektorlab/ctop:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
`ctop` is also available for Arch in the [AUR](https://aur.archlinux.org/packages/ctop/)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
ctop requires no arguments and will configure itself using the `DOCKER_HOST` environment variable
|
`ctop` requires no arguments and will configure itself using the `DOCKER_HOST` environment variable
|
||||||
```bash
|
```bash
|
||||||
export DOCKER_HOST=tcp://127.0.0.1:4243
|
export DOCKER_HOST=tcp://127.0.0.1:4243
|
||||||
ctop
|
ctop
|
||||||
|
|||||||
24
circle.yml
Normal file
24
circle.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
machine:
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
override:
|
||||||
|
- docker info
|
||||||
|
- |
|
||||||
|
if [[ "$CIRCLE_BRANCH" == "master" ]]; then
|
||||||
|
docker build -t quay.io/vektorlab/ctop:latest .
|
||||||
|
else
|
||||||
|
docker build -t quay.io/vektorlab/ctop:${CIRCLE_BRANCH} .
|
||||||
|
fi
|
||||||
|
|
||||||
|
test:
|
||||||
|
override:
|
||||||
|
- docker run -t --entrypoint /bin/sh quay.io/vektorlab/ctop:latest -v
|
||||||
|
|
||||||
|
deployment:
|
||||||
|
hub:
|
||||||
|
branch: master
|
||||||
|
commands:
|
||||||
|
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS quay.io
|
||||||
|
- docker push quay.io/vektorlab/ctop:latest
|
||||||
@@ -2,11 +2,6 @@ package config
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
var params = []*Param{
|
var params = []*Param{
|
||||||
&Param{
|
|
||||||
Key: "dockerHost",
|
|
||||||
Val: getEnv("DOCKER_HOST", "unix:///var/run/docker.sock"),
|
|
||||||
Label: "Docker API URL",
|
|
||||||
},
|
|
||||||
&Param{
|
&Param{
|
||||||
Key: "filterStr",
|
Key: "filterStr",
|
||||||
Val: "",
|
Val: "",
|
||||||
|
|||||||
11
cursor.go
11
cursor.go
@@ -16,8 +16,15 @@ func NewGridCursor() *GridCursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GridCursor) Len() int { return len(gc.filtered) }
|
func (gc *GridCursor) Len() int { return len(gc.filtered) }
|
||||||
func (gc *GridCursor) Selected() *Container { return gc.filtered[gc.Idx()] }
|
|
||||||
|
func (gc *GridCursor) Selected() *Container {
|
||||||
|
idx := gc.Idx()
|
||||||
|
if idx < gc.Len() {
|
||||||
|
return gc.filtered[idx]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh containers from source
|
// Refresh containers from source
|
||||||
func (gc *GridCursor) RefreshContainers() (lenChanged bool) {
|
func (gc *GridCursor) RefreshContainers() (lenChanged bool) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func NewInfo(id string) *Info {
|
|||||||
p.Height = 4
|
p.Height = 4
|
||||||
p.Width = colWidth[0]
|
p.Width = colWidth[0]
|
||||||
p.FgColor = ui.ThemeAttr("par.text.fg")
|
p.FgColor = ui.ThemeAttr("par.text.fg")
|
||||||
p.Seperator = false
|
p.Separator = false
|
||||||
i := &Info{p, make(map[string]string)}
|
i := &Info{p, make(map[string]string)}
|
||||||
i.Set("id", id)
|
i.Set("id", id)
|
||||||
return i
|
return i
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/bcicen/ctop/config"
|
|
||||||
"github.com/bcicen/ctop/metrics"
|
"github.com/bcicen/ctop/metrics"
|
||||||
"github.com/fsouza/go-dockerclient"
|
"github.com/fsouza/go-dockerclient"
|
||||||
)
|
)
|
||||||
@@ -18,11 +18,12 @@ type DockerContainerSource struct {
|
|||||||
client *docker.Client
|
client *docker.Client
|
||||||
containers map[string]*Container
|
containers map[string]*Container
|
||||||
needsRefresh chan string // container IDs requiring refresh
|
needsRefresh chan string // container IDs requiring refresh
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerContainerSource() *DockerContainerSource {
|
func NewDockerContainerSource() *DockerContainerSource {
|
||||||
// init docker client
|
// init docker client
|
||||||
client, err := docker.NewClient(config.GetVal("dockerHost"))
|
client, err := docker.NewClientFromEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -30,6 +31,7 @@ func NewDockerContainerSource() *DockerContainerSource {
|
|||||||
client: client,
|
client: client,
|
||||||
containers: make(map[string]*Container),
|
containers: make(map[string]*Container),
|
||||||
needsRefresh: make(chan string, 60),
|
needsRefresh: make(chan string, 60),
|
||||||
|
lock: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
go cm.Loop()
|
go cm.Loop()
|
||||||
cm.refreshAll()
|
cm.refreshAll()
|
||||||
@@ -113,28 +115,36 @@ func (cm *DockerContainerSource) MustGet(id string) *Container {
|
|||||||
collector := metrics.NewDocker(cm.client, id)
|
collector := metrics.NewDocker(cm.client, id)
|
||||||
// create container
|
// create container
|
||||||
c = NewContainer(id, collector)
|
c = NewContainer(id, collector)
|
||||||
|
cm.lock.Lock()
|
||||||
cm.containers[id] = c
|
cm.containers[id] = c
|
||||||
|
cm.lock.Unlock()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a single container, by ID
|
// Get a single container, by ID
|
||||||
func (cm *DockerContainerSource) Get(id string) (*Container, bool) {
|
func (cm *DockerContainerSource) Get(id string) (*Container, bool) {
|
||||||
|
cm.lock.Lock()
|
||||||
c, ok := cm.containers[id]
|
c, ok := cm.containers[id]
|
||||||
|
cm.lock.Unlock()
|
||||||
return c, ok
|
return c, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove containers by ID
|
// Remove containers by ID
|
||||||
func (cm *DockerContainerSource) delByID(id string) {
|
func (cm *DockerContainerSource) delByID(id string) {
|
||||||
|
cm.lock.Lock()
|
||||||
delete(cm.containers, id)
|
delete(cm.containers, id)
|
||||||
|
cm.lock.Unlock()
|
||||||
log.Infof("removed dead container: %s", id)
|
log.Infof("removed dead container: %s", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return array of all containers, sorted by field
|
// Return array of all containers, sorted by field
|
||||||
func (cm *DockerContainerSource) All() (containers Containers) {
|
func (cm *DockerContainerSource) All() (containers Containers) {
|
||||||
|
cm.lock.Lock()
|
||||||
for _, c := range cm.containers {
|
for _, c := range cm.containers {
|
||||||
containers = append(containers, c)
|
containers = append(containers, c)
|
||||||
}
|
}
|
||||||
|
cm.lock.Unlock()
|
||||||
sort.Sort(containers)
|
sort.Sort(containers)
|
||||||
containers.Filter()
|
containers.Filter()
|
||||||
return containers
|
return containers
|
||||||
|
|||||||
7
grid.go
7
grid.go
@@ -28,7 +28,7 @@ func RedrawRows(clr bool) {
|
|||||||
log.Debugf("screen cleared")
|
log.Debugf("screen cleared")
|
||||||
}
|
}
|
||||||
if config.GetSwitchVal("enableHeader") {
|
if config.GetSwitchVal("enableHeader") {
|
||||||
header.Render()
|
ui.Render(header)
|
||||||
}
|
}
|
||||||
cGrid.Align()
|
cGrid.Align()
|
||||||
ui.Render(cGrid)
|
ui.Render(cGrid)
|
||||||
@@ -132,7 +132,10 @@ func Display() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if expand {
|
if expand {
|
||||||
ExpandView(cursor.Selected())
|
c := cursor.Selected()
|
||||||
|
if c != nil {
|
||||||
|
ExpandView(c)
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -23,10 +23,14 @@ func NewCTopHeader() *CTopHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTopHeader) Render() {
|
func (c *CTopHeader) Buffer() ui.Buffer {
|
||||||
|
buf := ui.NewBuffer()
|
||||||
c.Time.Text = timeStr()
|
c.Time.Text = timeStr()
|
||||||
ui.Render(c.bg)
|
buf.Merge(c.bg.Buffer())
|
||||||
ui.Render(c.Time, c.Count, c.Filter)
|
buf.Merge(c.Time.Buffer())
|
||||||
|
buf.Merge(c.Count.Buffer())
|
||||||
|
buf.Merge(c.Filter.Buffer())
|
||||||
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTopHeader) Align() {
|
func (c *CTopHeader) Align() {
|
||||||
|
|||||||
Reference in New Issue
Block a user