├── .gitignore ├── build.sh ├── files ├── uistart.go └── utils.go ├── go.mod ├── go.sum ├── img └── Screenshot.png ├── netproc.go └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | netproc -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | GO111MODULE=on go build 5 | 6 | -------------------------------------------------------------------------------- /files/uistart.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | ui "github.com/gizak/termui" 5 | ) 6 | 7 | func UIStart(filename string) { 8 | ui.Clear() 9 | 10 | netInfoMap := getInfoMapMap(filename) 11 | 12 | parsMap := make(map[string]*ui.Par, len(netInfoMap)) 13 | for k, v := range netInfoMap { 14 | parse, lines := getPar(v) 15 | par := ui.NewPar(parse) 16 | par.Height = lines + 2 17 | par.BorderLabel = k 18 | 19 | parsMap[k] = par 20 | } 21 | 22 | // build layout 23 | parTime := ui.NewPar(getTime()) 24 | parTime.Height = 1 25 | parTime.Border = false 26 | ui.Body.AddRows( 27 | ui.NewRow( 28 | ui.NewCol(12, 0, parTime))) 29 | 30 | for _, par := range parsMap { 31 | ui.Body.AddRows( 32 | ui.NewRow( 33 | ui.NewCol(12, 0, par))) 34 | } 35 | 36 | // calculate layout 37 | ui.Body.Align() 38 | ui.Render(ui.Body) 39 | 40 | ui.Handle("/timer/1s", func(e ui.Event) { 41 | netInfoMap := getInfoMapMap(filename) 42 | ui.Clear() 43 | 44 | parTime.Text = getTime() 45 | for k, v := range netInfoMap { 46 | parse, lines := getPar(v) 47 | 48 | parsMap[k].Text = parse 49 | parsMap[k].Height = lines + 2 50 | } 51 | 52 | ui.Render(ui.Body) 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /files/utils.go: -------------------------------------------------------------------------------- 1 | package files 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | "os" 7 | "bufio" 8 | "log" 9 | "strings" 10 | "os/exec" 11 | "strconv" 12 | ) 13 | 14 | type netInfo struct { 15 | count int 16 | key string 17 | } 18 | 19 | func getTerminalSize() (high, length int) { 20 | cmd := exec.Command("stty", "size") 21 | cmd.Stdin = os.Stdin 22 | out, err := cmd.Output() 23 | if err != nil { 24 | high = 40 25 | length = 80 26 | } else { 27 | fmt.Sscanf(string(out), "%d %d", &high, &length) 28 | } 29 | return high, length 30 | } 31 | 32 | func getPar(netInfo []netInfo) (string, int){ 33 | var _parser string 34 | _, width := getTerminalSize() 35 | width -=6 36 | fmtStringLen := 0 37 | total := 0 38 | lines := 1 39 | 40 | for _, v := range netInfo { 41 | fmtString := fmt.Sprintf("%25s: %-10d", v.key, v.count) 42 | fmtStringLen = len(fmtString) 43 | total += fmtStringLen 44 | if total > width { 45 | _parser += "\r\n" 46 | lines += 1 47 | total = fmtStringLen 48 | } 49 | _parser += fmtString 50 | } 51 | return _parser, lines 52 | } 53 | 54 | func getTime() string { 55 | var _parser string 56 | 57 | t := time.Now() 58 | header := t.Format("2006-01-02 15:04:05") 59 | 60 | _, width := getTerminalSize() 61 | width -=6 62 | 63 | headerFmt := fmt.Sprintf("[%%%ds\r\n](fg-yellow)", (width + len(header))/2) 64 | _parser = fmt.Sprintf(headerFmt, header) 65 | 66 | return _parser 67 | } 68 | 69 | func isKey(text string) bool { 70 | ret := false 71 | _, err := strconv.Atoi(text) 72 | if err != nil { 73 | ret = true 74 | } 75 | return ret 76 | } 77 | 78 | func procText(texts string, infoArray []netInfo) []netInfo { 79 | textArray := strings.Split(strings.TrimSpace(texts), " ") 80 | if infoArray == nil { 81 | infoArray = make([]netInfo, len(textArray)) 82 | } 83 | if isKey(textArray[0]) { 84 | for i := 0; i < len(textArray); i++ { 85 | infoArray[i].key = textArray[i] 86 | } 87 | } else { 88 | for i := 0; i < len(textArray); i++ { 89 | infoArray[i].count, _ = strconv.Atoi(textArray[i]) 90 | } 91 | } 92 | 93 | return infoArray 94 | } 95 | 96 | func getInfoMapMap(file_path string) (map[string][]netInfo){ 97 | file, err := os.Open(file_path) 98 | if err != nil { 99 | log.Fatal(err) 100 | } 101 | defer file.Close() 102 | 103 | netInfoMap := make(map[string][]netInfo, 64) 104 | 105 | scanner := bufio.NewScanner(file) 106 | for scanner.Scan() { 107 | subString := scanner.Text() 108 | segTexts := strings.Split(subString, ":") 109 | 110 | seg := segTexts[0] 111 | texts := segTexts[1] 112 | 113 | netInfoMap[seg] = procText(texts, netInfoMap[seg]) 114 | } 115 | 116 | if err := scanner.Err(); err != nil { 117 | log.Fatal(err) 118 | } 119 | return netInfoMap 120 | } 121 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/silenceshell/netproc 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.1 // indirect 7 | github.com/gizak/termui v2.3.0+incompatible 8 | github.com/maruel/panicparse v1.6.1 // indirect 9 | github.com/mattn/go-runewidth v0.0.13 // indirect 10 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 11 | github.com/nsf/termbox-go v1.1.1 // indirect 12 | github.com/spf13/pflag v1.0.5 13 | github.com/stretchr/testify v1.7.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/gizak/termui v2.3.0+incompatible h1:S8wJoNumYfc/rR5UezUM4HsPEo3RJh0LKdiuDWQpjqw= 5 | github.com/gizak/termui v2.3.0+incompatible/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= 6 | github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= 7 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 8 | github.com/maruel/panicparse v1.6.1 h1:803MjBzGcUgE1vYgg3UMNq3G1oyYeKkMu3t6hBS97x0= 9 | github.com/maruel/panicparse v1.6.1/go.mod h1:uoxI4w9gJL6XahaYPMq/z9uadrdr1SyHuQwV2q80Mm0= 10 | github.com/maruel/panicparse/v2 v2.1.1/go.mod h1:AeTWdCE4lcq8OKsLb6cHSj1RWHVSnV9HBCk7sKLF4Jg= 11 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 12 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 13 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 14 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 15 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 16 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 17 | github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= 18 | github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 19 | github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= 20 | github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= 21 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 22 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 23 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 24 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 25 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 26 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 27 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 28 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 29 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 30 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 31 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 32 | golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 33 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 34 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 35 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 36 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 37 | -------------------------------------------------------------------------------- /img/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silenceshell/netproc/b3aac484dcb8286ec4baf26bc38c39048d4c1cca/img/Screenshot.png -------------------------------------------------------------------------------- /netproc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/silenceshell/netproc/files" 6 | flag "github.com/spf13/pflag" 7 | ui "github.com/gizak/termui" 8 | ) 9 | 10 | func main() { 11 | var f *string = flag.String("file", "", "specify the file you want to watch") 12 | 13 | flag.Parse() 14 | 15 | filename := *f 16 | if filename == "" { 17 | fmt.Println("Usage: netproc --file [snmp, netstat]") 18 | return 19 | } 20 | filename = "/proc/net/" + filename 21 | 22 | err2 := ui.Init() 23 | if err2 != nil { 24 | panic(err2) 25 | } 26 | defer ui.Close() 27 | 28 | ui.Handle("/sys/kbd/q", func(ui.Event) { 29 | ui.StopLoop() 30 | }) 31 | 32 | files.UIStart(filename) 33 | 34 | ui.Loop() 35 | } 36 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | Tools for better formatter for `/proc/net/`. Currently support snmp and netstat. 3 | 4 | ```bash 5 | go run netproc.go --file snmp 6 | go run netproc.go --file netstat 7 | ``` 8 | 9 | or 10 | 11 | ```bash 12 | go build netproc.go 13 | ./netproc --file snmp 14 | ./netproc --file netstat 15 | ``` 16 | 17 | press `q` to exit. 18 | 19 | netproc runs like this: 20 | 21 | ![Screenshot](img/Screenshot.png) 22 | --------------------------------------------------------------------------------