This commit is contained in:
insanity 2017-10-24 16:09:17 +09:00
parent 2e31ae10eb
commit 806f406ee0
11 changed files with 311 additions and 163 deletions

View File

@ -2,6 +2,7 @@ package crawler
import ( import (
"bytes" "bytes"
"encoding/json"
"git.loafle.net/overflow/ssh_crawler/ssh" "git.loafle.net/overflow/ssh_crawler/ssh"
"git.loafle.net/overflow/ssh_crawler/stat" "git.loafle.net/overflow/ssh_crawler/stat"
) )
@ -29,33 +30,43 @@ func (c *Crawler) connectSSH(ip, port, user, pw string) error {
return nil return nil
} }
func (c *Crawler) CPUStat(ch chan interface{}) { func (c *Crawler) CPUStat(ch chan interface{}, keys []string) {
go func() { go func() {
cpu := &stat.CPUStat{} cpu := &stat.CPUStat{}
b, err := c.sshCli.RunCommand(cpu.Command()) b, err := c.sshCli.RunCommand(cpu.Command())
if err != nil { if err != nil {
ch <- err ch <- err
} }
res, err := cpu.Parse(bytes.NewReader(b)) res, err := cpu.Read(bytes.NewReader(b), keys)
if err != nil { if err != nil {
ch <- err ch <- err
} }
ch <- res jsonData, err := json.Marshal(res)
if err != nil {
ch <- err
}
ch <- string(jsonData)
close(ch)
}() }()
} }
func (c *Crawler) MemStat(ch chan interface{}) { func (c *Crawler) MemStat(ch chan interface{}, keys []string) {
go func() { go func() {
mem := &stat.MemStat{} mem := &stat.MemStat{}
b, err := c.sshCli.RunCommand(mem.Command()) b, err := c.sshCli.RunCommand(mem.Command())
if err != nil { if err != nil {
ch <- err ch <- err
} }
res, err := mem.Parse(bytes.NewReader(b)) res, err := mem.Read(bytes.NewReader(b), keys)
if err != nil { if err != nil {
ch <- err ch <- err
} }
ch <- res jsonData, err := json.Marshal(res)
if err != nil {
ch <- err
}
ch <- string(jsonData)
close(ch)
}() }()
} }
@ -73,6 +84,7 @@ func (c *Crawler) DiskIOStat(ch chan interface{}) {
ch <- err ch <- err
} }
ch <- res ch <- res
close(ch)
}() }()
} }
@ -88,6 +100,7 @@ func (c *Crawler) DiskFreeStat(ch chan interface{}) {
ch <- err ch <- err
} }
ch <- res ch <- res
close(ch)
}() }()
} }

101
main.go
View File

@ -3,11 +3,9 @@ package main
import ( import (
"fmt" "fmt"
"git.loafle.net/overflow/ssh_crawler/crawler" "git.loafle.net/overflow/ssh_crawler/crawler"
"runtime"
) )
func main() { func main() {
runtime.GOMAXPROCS(4)
const ip = "192.168.1.15" const ip = "192.168.1.15"
const port = "22" const port = "22"
@ -19,45 +17,70 @@ func main() {
fmt.Println(err) fmt.Println(err)
} }
//CPU //사용자가 cpu.usage.total을 선택했을 때의 수집항목들 (..출력 항목도 포함시켜서 계산결과 리턴해야하나?)
cpukeys := []string{
"cpu.usage.sum",
"cpu.usage.user",
"cpu.usage.system",
"cpu.usage.nice",
"cpu.usage.idle",
"cpu.usage.iowait",
"cpu.usage.irq",
"cpu.usage.softirq",
"cpu.usage.steal",
"cpu.usage.guest",
"cpu.usage.guestNice",
}
cpuCh := make(chan interface{}) cpuCh := make(chan interface{})
cr.CPUStat(cpuCh) cr.CPUStat(cpuCh, cpukeys)
fmt.Println(<-cpuCh) fmt.Println(<-cpuCh)
close(cpuCh)
//Memory //Memory
memCh := make(chan interface{}) memkeys := []string {
cr.MemStat(memCh) "mem.usage.total",
fmt.Println(<-memCh) "mem.usage.free",
close(memCh) "mem.usage.available",
"mem.usage.buffers",
//Disk IO "mem.usage.cached",
diskioCh := make(chan interface{}) "mem.swap.usage.total",
cr.DiskIOStat(diskioCh) "mem.swap.usage.free",
fmt.Println(<-diskioCh) "mem.swap.usage.cached",
close(diskioCh) }
memCh := make(chan interface{})
//Disk Free cr.MemStat(memCh, memkeys)
diskFreeCh := make(chan interface{}) fmt.Println(<-memCh)
cr.DiskFreeStat(diskFreeCh)
fmt.Println(<-diskFreeCh) //memCh := make(chan interface{})
close(diskFreeCh) //cr.MemStat(memCh, keys)
//fmt.Println(<-memCh)
//Network
netCh := make(chan interface{}) ////Memory
cr.NetworkStat(netCh) //memCh := make(chan interface{})
fmt.Println(<-netCh) //cr.MemStat(memCh)
close(netCh) //fmt.Println(<-memCh)
//
//Load Avg. ////Disk IO
loadCh := make(chan interface{}) //diskioCh := make(chan interface{})
cr.LoadAvgStat(loadCh) //cr.DiskIOStat(diskioCh)
fmt.Println(<-loadCh) //fmt.Println(<-diskioCh)
close(loadCh) //
////Disk Free
//Process //diskFreeCh := make(chan interface{})
psCh := make(chan interface{}) //cr.DiskFreeStat(diskFreeCh)
cr.ProcessStat(psCh) //fmt.Println(<-diskFreeCh)
fmt.Println(<-psCh) //
close(psCh) ////Network
//netCh := make(chan interface{})
//cr.NetworkStat(netCh)
//fmt.Println(<-netCh)
//
////Load Avg.
//loadCh := make(chan interface{})
//cr.LoadAvgStat(loadCh)
//fmt.Println(<-loadCh)
//
////Process
//psCh := make(chan interface{})
//cr.ProcessStat(psCh)
//fmt.Println(<-psCh)
} }

View File

@ -4,29 +4,31 @@ import (
"bufio" "bufio"
"io" "io"
"strings" "strings"
"git.loafle.net/overflow/ssh_crawler/util"
) )
type CPUStat struct { type CPUStat struct {
device, Device,
user, User,
nice, Nice,
system, System,
idle, Idle,
iowait, Iowait,
irq, Irq,
softIrq, SoftIrq,
steal, // (over 2.6.11) Steal, // (over 2.6.11)
guest, // (over 2.6.24) Guest, // (over 2.6.24)
guestNice string //(over 2.6.33) GuestNice, //(over 2.6.33)
Sum float64
} }
func (cpu CPUStat) Command() string { func (cpu CPUStat) Command() string {
return "cat /proc/stat" return "cat /proc/stat"
} }
func (cpu CPUStat) Parse(r io.Reader) (*[]CPUStat, error) { func (cpu CPUStat) Read(r io.Reader, keys []string) (*map[string]string, error) {
var ( var (
CPUStats = []CPUStat{} stats = []CPUStat{}
scanner = bufio.NewScanner(r) scanner = bufio.NewScanner(r)
) )
@ -37,31 +39,79 @@ func (cpu CPUStat) Parse(r io.Reader) (*[]CPUStat, error) {
continue continue
} }
steal, guest, guestNice := "", "", "" var steal, guest, guestNice float64
if len(parts) > 8 { if len(parts) > 8 {
steal = parts[8] steal = util.StringToFloat64(parts[8])
} }
if len(parts) > 9 { if len(parts) > 9 {
guest = parts[9] guest = util.StringToFloat64(parts[9])
} }
if len(parts) > 10 { if len(parts) > 10 {
guestNice = parts[10] guestNice = util.StringToFloat64(parts[10])
} }
CPUStats = append(CPUStats, CPUStat{ stats = append(stats, CPUStat{
device: parts[0], Device: util.StringToFloat64(parts[0]),
user: parts[1], User: util.StringToFloat64(parts[1]),
nice: parts[2], Nice: util.StringToFloat64(parts[2]),
system: parts[3], System: util.StringToFloat64(parts[3]),
idle: parts[4], Idle: util.StringToFloat64(parts[4]),
iowait: parts[5], Iowait: util.StringToFloat64(parts[5]),
irq: parts[6], Irq: util.StringToFloat64(parts[6]),
softIrq: parts[7], SoftIrq: util.StringToFloat64(parts[7]),
steal: steal, Steal: steal,
guest: guest, Guest: guest,
guestNice: guestNice, GuestNice: guestNice,
}) })
} }
return &CPUStats, scanner.Err() res, err :=cpu.parse(keys, stats)
if err != nil {
return nil, err
}
return &res, scanner.Err()
}
func (cpu CPUStat) parse(keys []string, data []CPUStat) (map[string]string, error) {
resMap := make(map[string]string)
for _, key := range keys {
resMap[key] = cpu.calc(key, data[0])
}
return resMap, nil
}
func (cpu CPUStat) calc(key string, d CPUStat) string {
var value float64 = 0
sum := d.User + d.Nice + d.System + d.Idle + d.Iowait + d.Irq + d.SoftIrq + d.Steal + d.Guest + d.GuestNice
switch key {
case "cpu.usage.sum":
value = sum
case "cpu.usage.user":
value = d.User / sum * 100
case "cpu.usage.nice":
value = d.Nice / sum * 100
case "cpu.usage.system":
value = d.System / sum * 100
case "cpu.usage.idle":
value = d.Idle / sum * 100
case "cpu.usage.iowait":
value = d.Iowait / sum * 100
case "cpu.usage.irq":
value = d.Irq / sum * 100
case "cpu.usage.softirq":
value = d.SoftIrq / sum * 100
case "cpu.usage.steal":
value = d.Steal / sum * 100
case "cpu.usage.guest":
value = d.Guest / sum * 100
case "cpu.usage.gnice":
value = d.GuestNice / sum * 100
default:
}
return util.Float64ToString(value)
} }

View File

@ -7,12 +7,12 @@ import (
) )
type DiskFreeStat struct { type DiskFreeStat struct {
filesystem, Filesystem,
size, Size,
used, Used,
available, Available,
usePerc, UsePerc,
mountedOn string MountedOn string
} }
func (diskFree DiskFreeStat) Command() string { func (diskFree DiskFreeStat) Command() string {
@ -28,12 +28,12 @@ func (diskio DiskFreeStat) Parse(r io.Reader) (*[]DiskFreeStat, error) {
for scanner.Scan() { for scanner.Scan() {
parts := strings.Fields(scanner.Text()) parts := strings.Fields(scanner.Text())
stats = append(stats, DiskFreeStat{ stats = append(stats, DiskFreeStat{
filesystem: parts[0], Filesystem: parts[0],
size: parts[1], Size: parts[1],
used: parts[2], Used: parts[2],
available: parts[3], Available: parts[3],
usePerc: removePercUnit(parts[4]), UsePerc: removePercUnit(parts[4]),
mountedOn: parts[5], MountedOn: parts[5],
}) })
} }

View File

@ -8,18 +8,18 @@ import (
) )
type DiskIOStat struct { type DiskIOStat struct {
device, Device,
readCompleted, ReadCompleted,
readMerged, ReadMerged,
sectorRead, SectorRead,
timeSpentReading, TimeSpentReading,
writesCompleted, WritesCompleted,
writesMerged, WritesMerged,
sectorsWritten, SectorsWritten,
timeSpentWriting, TimeSpentWriting,
ioInProg, IoInProg,
timeSpentIO, TimeSpentIO,
weightedTimeSpentIO string WeightedTimeSpentIO string
} }
func (diskio DiskIOStat) Command() string { func (diskio DiskIOStat) Command() string {
@ -42,18 +42,18 @@ func (diskio DiskIOStat) Parse(r io.Reader) (*[]DiskIOStat, error) {
continue continue
} }
stats = append(stats, DiskIOStat{ stats = append(stats, DiskIOStat{
device: deviceName, Device: deviceName,
readCompleted: parts[3], ReadCompleted: parts[3],
readMerged: parts[4], ReadMerged: parts[4],
sectorRead: parts[5], SectorRead: parts[5],
timeSpentReading: parts[6], TimeSpentReading: parts[6],
writesCompleted: parts[7], WritesCompleted: parts[7],
writesMerged: parts[8], WritesMerged: parts[8],
sectorsWritten: parts[9], SectorsWritten: parts[9],
timeSpentWriting: parts[10], TimeSpentWriting: parts[10],
ioInProg: parts[11], IoInProg: parts[11],
timeSpentIO: parts[12], TimeSpentIO: parts[12],
weightedTimeSpentIO: parts[13], WeightedTimeSpentIO: parts[13],
}) })
} }

View File

@ -7,9 +7,9 @@ import (
) )
type LoadAvg struct { type LoadAvg struct {
min1, Min1,
min5, Min5,
min15 string Min15 string
} }
func (loadavg LoadAvg) Command() string { func (loadavg LoadAvg) Command() string {
@ -25,9 +25,9 @@ func (loadavg LoadAvg) Parse(r io.Reader) (*LoadAvg, error) {
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
parts := strings.Fields(line) parts := strings.Fields(line)
load.min1 = parts[0] load.Min1 = parts[0]
load.min5 = parts[1] load.Min5 = parts[1]
load.min15 = parts[2] load.Min15 = parts[2]
} }
return &load, scanner.Err() return &load, scanner.Err()
} }

View File

@ -13,9 +13,9 @@ func (mem MemStat) Command() string {
return "cat /proc/meminfo" return "cat /proc/meminfo"
} }
func (mem MemStat) Parse(r io.Reader) (*map[string]string, error) { func (mem MemStat) Read(r io.Reader, keys []string) (*map[string]string, error) {
var ( var (
memInfo = map[string]string{} stats = map[string]string{}
scanner = bufio.NewScanner(r) scanner = bufio.NewScanner(r)
) )
@ -23,8 +23,43 @@ func (mem MemStat) Parse(r io.Reader) (*map[string]string, error) {
line := scanner.Text() line := scanner.Text()
parts := strings.Fields(line) parts := strings.Fields(line)
key := parts[0][:len(parts[0])-1] key := parts[0][:len(parts[0])-1]
memInfo[key] = parts[1]
stats[key] = parts[1]
} }
return &memInfo, scanner.Err() res, err := mem.parse(keys, stats)
if err != nil {
return nil, err
}
return &res, scanner.Err()
}
func (mem MemStat) parse(keys []string, data map[string]string) (map[string]string, error) {
resMap := make(map[string]string)
for _, key := range keys {
switch key {
case "mem.usage.total":
resMap[key] = data["MemTotal"]
case "mem.usage.free":
resMap[key] = data["MemFree"]
case "mem.usage.available":
resMap[key] = data["MemAvailable"]
case "mem.usage.buffers":
resMap[key] = data["Buffers"]
case "mem.usage.cached":
resMap[key] = data["Cached"]
case "mem.swap.usage.total":
resMap[key] = data["SwapTotal"]
case "mem.swap.usage.free":
resMap[key] = data["SwapFree"]
case "mem.swap.usage.cached":
resMap[key] = data["SwapCached"]
default:
}
}
return resMap, nil
} }

View File

@ -9,23 +9,23 @@ import (
) )
type NetDevStat struct { type NetDevStat struct {
iface, Iface,
recvByte, RecvByte,
recvPacket, RecvPacket,
recvErr, RecvErr,
recvDrop, RecvDrop,
recvFifo, RecvFifo,
recvFrame, RecvFrame,
recvCompressed, RecvCompressed,
recvMulticast, RecvMulticast,
transByte, TransByte,
transPacket, TransPacket,
transErr, TransErr,
transDrop, TransDrop,
transFifo, TransFifo,
transFrame, TransFrame,
transCompressed, TransCompressed,
transMulticast string TransMulticast string
} }
func (net *NetDevStat) Command() string { func (net *NetDevStat) Command() string {
@ -56,23 +56,23 @@ func (net *NetDevStat) Parse(r io.Reader) (*[]NetDevStat, error) {
dev := parts[0][:len(parts[0])] dev := parts[0][:len(parts[0])]
netDevStats = append(netDevStats, NetDevStat{ netDevStats = append(netDevStats, NetDevStat{
iface: dev, Iface: dev,
recvByte: parts[1], RecvByte: parts[1],
recvPacket: parts[2], RecvPacket: parts[2],
recvErr: parts[3], RecvErr: parts[3],
recvDrop: parts[4], RecvDrop: parts[4],
recvFifo: parts[5], RecvFifo: parts[5],
recvFrame: parts[6], RecvFrame: parts[6],
recvCompressed: parts[7], RecvCompressed: parts[7],
recvMulticast: parts[8], RecvMulticast: parts[8],
transByte: parts[9], TransByte: parts[9],
transPacket: parts[10], TransPacket: parts[10],
transErr: parts[11], TransErr: parts[11],
transDrop: parts[12], TransDrop: parts[12],
transFifo: parts[13], TransFifo: parts[13],
transFrame: parts[14], TransFrame: parts[14],
transCompressed: parts[15], TransCompressed: parts[15],
transMulticast: parts[16], TransMulticast: parts[16],
}) })
} }
return &netDevStats, scanner.Err() return &netDevStats, scanner.Err()

View File

@ -7,12 +7,12 @@ import (
) )
type ProcessStat struct { type ProcessStat struct {
user, User,
pid, Pid,
size, Size,
pcpu, Pcpu,
pmem, Pmem,
cmd string Cmd string
} }
func (ps *ProcessStat) Command() string { func (ps *ProcessStat) Command() string {
@ -29,12 +29,12 @@ func (ps *ProcessStat) Parse(r io.Reader) (*[]ProcessStat, error) {
line := scanner.Text() line := scanner.Text()
parts := strings.Fields(line) parts := strings.Fields(line)
psStats = append(psStats, ProcessStat{ psStats = append(psStats, ProcessStat{
user: parts[0], User: parts[0],
pid: parts[1], Pid: parts[1],
size: parts[2], Size: parts[2],
pcpu: parts[3], Pcpu: parts[3],
pmem: parts[4], Pmem: parts[4],
cmd: parts[5], Cmd: parts[5],
}) })
} }
return &psStats, scanner.Err() return &psStats, scanner.Err()

1
stat/uptime.go Normal file
View File

@ -0,0 +1 @@
package stat

26
util/util.go Normal file
View File

@ -0,0 +1,26 @@
package util
import (
"fmt"
"math"
"strconv"
)
func StringToFloat64(str string) float64 {
n, _ := strconv.ParseFloat(str, 64)
return n
}
func Float64ToString(num float64) string {
return fmt.Sprintf("%v", toFixed(num, 2))
}
func round(num float64) int {
return int(num + math.Copysign(0.5, num))
}
func toFixed(num float64, precision int) float64 {
output := math.Pow(10, float64(precision))
return float64(round(num*output)) / output
}