From ab6192f071b41aaa2bf9b4bda3aadeb5432f751e Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:11:30 +0200 Subject: [PATCH 1/9] :heavy_plus_sign: add gopsutil dependencies --- go.mod | 6 +++++- go.sum | 21 ++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 0577d7e..b69eb2f 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,13 @@ module github.com/boxmetrics/boxmetrics-agent go 1.12 require ( - github.com/BurntSushi/toml v0.3.1 // indirect + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/fsnotify/fsnotify v1.4.7 + github.com/go-ole/go-ole v1.2.4 // indirect + github.com/google/go-cmp v0.2.0 github.com/gorilla/websocket v1.4.0 + github.com/shirou/gopsutil v2.18.12+incompatible + github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/sirupsen/logrus v1.4.2 github.com/spf13/viper v1.4.0 ) diff --git a/go.sum b/go.sum index d23c0dc..dd6c647 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -11,7 +13,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -25,6 +26,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -34,6 +37,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -49,8 +53,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -74,9 +80,11 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -89,8 +97,6 @@ github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -98,7 +104,6 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -106,7 +111,6 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -123,8 +127,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -141,6 +143,7 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= From 10cd27faac46a4216458de73d2b76ec486a5885b Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:06:05 +0200 Subject: [PATCH 2/9] :sparkles: add errors pkg --- internal/pkg/errors/errors.go | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 internal/pkg/errors/errors.go diff --git a/internal/pkg/errors/errors.go b/internal/pkg/errors/errors.go new file mode 100644 index 0000000..b2ba9c6 --- /dev/null +++ b/internal/pkg/errors/errors.go @@ -0,0 +1,49 @@ +// Package errors implements functions to manipulate errors. +package errors + +import ( + "encoding/json" +) + +// New returns an error that formats as the given text. +func New(text string) error { + return &errorString{text} +} + +// Convert error to a new error with marshall support +func Convert(e error) error { + if e != nil { + return &errorString{e.Error()} + } + + return e +} + +// errorString is a trivial implementation of error. +type errorString struct { + s string +} + +func (e *errorString) Error() string { + return e.s +} + +func (e *errorString) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + e.s = s + + return nil +} + +// MarshalJSON return JSON +func (e errorString) MarshalJSON() ([]byte, error) { + var s string + + s = e.s + + return json.Marshal(s) +} From bbf3a7dc4fc54aec46542f557903ac8e4f7340af Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:02:05 +0200 Subject: [PATCH 3/9] :sparkles: add agent pkg --- internal/pkg/agent/action.go | 91 ++++++++ internal/pkg/{boxagent => agent}/config.go | 9 +- internal/pkg/{boxagent => agent}/logger.go | 8 +- internal/pkg/agent/socket.go | 245 +++++++++++++++++++++ 4 files changed, 345 insertions(+), 8 deletions(-) create mode 100644 internal/pkg/agent/action.go rename internal/pkg/{boxagent => agent}/config.go (86%) rename internal/pkg/{boxagent => agent}/logger.go (99%) create mode 100644 internal/pkg/agent/socket.go diff --git a/internal/pkg/agent/action.go b/internal/pkg/agent/action.go new file mode 100644 index 0000000..6d5aedd --- /dev/null +++ b/internal/pkg/agent/action.go @@ -0,0 +1,91 @@ +package agent + +import ( + "os/exec" + + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/info" +) + +func dispatchEvent(e event) (interface{}, error) { + switch e.Type { + case Info: + Log.Debug("info") + return dispatchInfo(e) + case Script: + return dispatchScript(e) + case Command: + return dispatchCommand(e) + default: + return nil, errors.New("Event not support") + } +} + +func dispatchInfo(e event) (interface{}, error) { + switch e.Value { + case "memory": + return info.Memory(e.Format) + case "cpu": + Log.Debug("cpu") + return info.CPU(e.Format) + case "cpuinfo": + Log.Debug("cpuinfo") + return info.CPUinfo() + case "disks": + Log.Debug("disks") + return info.Disks(e.Format) + case "containers": + Log.Debug("containers") + return info.Containers(e.Format) + case "containersid": + Log.Debug("containersid") + return info.ContainersID() + case "host": + Log.Debug("host") + return info.Host(e.Format) + case "users": + Log.Debug("users") + return info.Users() + case "network": + Log.Debug("network") + return info.Network(e.Format) + case "connections": + Log.Debug("connections") + return info.Connections() + case "processes": + Log.Debug("processes") + return info.Processes(e.Format) + case "process": + Log.Debug("process") + return info.Process(e.Options.Pid, e.Format) + case "general": + Log.Debug("general") + return info.General(e.Format) + default: + return nil, errors.New("Info not support") + } +} + +func dispatchScript(e event) (interface{}, error) { + switch e.Value { + case "user": + return "launch user creation script", nil + default: + return nil, errors.New("Script not support") + } +} + +func dispatchCommand(e event) (interface{}, error) { + cmd := exec.Command(e.Value) + cmd.Args = append(cmd.Args, e.Options.Args...) + cmd.Env = e.Options.Env + cmd.Dir = e.Options.Dir + + r, err := cmd.CombinedOutput() + + if err != nil { + return nil, errors.Convert(err) + } + + return string(r), nil +} diff --git a/internal/pkg/boxagent/config.go b/internal/pkg/agent/config.go similarity index 86% rename from internal/pkg/boxagent/config.go rename to internal/pkg/agent/config.go index af95564..45aa850 100644 --- a/internal/pkg/boxagent/config.go +++ b/internal/pkg/agent/config.go @@ -1,4 +1,4 @@ -package boxagent +package agent import ( "github.com/fsnotify/fsnotify" @@ -37,10 +37,11 @@ func InitConfig() { func setDefault() { consoleLog := Logger{Type: "console", Format: "text", Level: "debug"} Config.SetDefault("loggers", []Logger{consoleLog}) - Config.SetDefault("protocol", "https") + Config.SetDefault("protocol", "http") Config.SetDefault("host", "localhost") - Config.SetDefault("http_port", 8080) - Config.SetDefault("https_port", 9090) + Config.SetDefault("http_port", 4455) + Config.SetDefault("https_port", 5544) Config.SetDefault("ssl_crt", "certificates/server.crt") Config.SetDefault("ssl_key", "certificates/server.key") + Config.SetDefault("jwt_auth", false) } diff --git a/internal/pkg/boxagent/logger.go b/internal/pkg/agent/logger.go similarity index 99% rename from internal/pkg/boxagent/logger.go rename to internal/pkg/agent/logger.go index cedcb30..acc976e 100644 --- a/internal/pkg/boxagent/logger.go +++ b/internal/pkg/agent/logger.go @@ -1,11 +1,11 @@ -package boxagent +package agent import ( - "io" - "os" + "errors" "fmt" + "io" "log" - "errors" + "os" "github.com/sirupsen/logrus" ) diff --git a/internal/pkg/agent/socket.go b/internal/pkg/agent/socket.go new file mode 100644 index 0000000..efcf513 --- /dev/null +++ b/internal/pkg/agent/socket.go @@ -0,0 +1,245 @@ +package agent + +import ( + "encoding/json" + "net/http" + "os" + "strconv" + "strings" + "time" + + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/google/go-cmp/cmp" + "github.com/gorilla/websocket" + "github.com/sirupsen/logrus" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +// EventCode type +type EventCode int + +const ( + _ EventCode = iota + // Info event + Info + // Script event + Script + // Command event + Command +) + +// UnmarshalJSON parse JSON +func (ec *EventCode) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + switch strings.ToLower(s) { + default: + return errors.New("EventCode not support") + case "info": + *ec = Info + case "script": + *ec = Script + case "command": + *ec = Command + } + + return nil +} + +// MarshalJSON return JSON +func (ec EventCode) MarshalJSON() ([]byte, error) { + var s string + switch ec { + default: + s = "" + case Info: + s = "info" + case Script: + s = "script" + case Command: + s = "command" + } + + return json.Marshal(s) +} + +type options struct { + Args []string `json:"args"` + Env []string `json:"env"` + Dir string `json:"pwd"` + Pid int32 `json:"pid"` +} + +type event struct { + Type EventCode `json:"type"` + Value string `json:"value"` + Options options `json:"options"` + Format bool `json:"format"` +} + +func (e *event) validate() error { + + Log.WithField("event", e).Debug("event receive") + if cmp.Equal(e, new(event)) { + return errors.New("Empty event") + } + + if !Config.GetBool("jwt_auth") { + return nil + } + // TODO: Ajouter authentifaction par token + return nil +} + +func (e event) String() string { + s, _ := json.Marshal(e) + return string(s) +} + +// Status type +type Status struct { + Code int `json:"code"` + Message string `json:"message"` +} + +// SuccessStatus return on success +var SuccessStatus = Status{200, "Request succeed"} + +// ErrorStatus return on success +var ErrorStatus = Status{400, "Request failed"} + +type response struct { + Event event `json:"event"` + Data interface{} `json:"data"` + StartDate time.Time `json:"startDate"` + EndDate time.Time `json:"endDate"` + Duration string `json:"duration"` + Status Status `json:"status"` + Error error `json:"error"` +} + +func (r response) String() string { + s, _ := json.Marshal(r) + return string(s) +} + +func (r response) HasError() bool { + return r.Error != nil +} + +func (r *response) SetStatus(s Status) { + r.Status = s +} + +func (r *response) SetError(err error) { + r.Error = err + r.SetStatus(ErrorStatus) +} + +func (r *response) SetData(d interface{}) { + r.Data = d + r.SetStatus(SuccessStatus) +} + +func newResponse(e event) *response { + date := time.Now() + + res := response{e, nil, date, time.Time{}, "", Status{}, nil} + + return &res +} + +// CreateServer create websocket server +func CreateServer() { + http.HandleFunc("/ws/v1", func(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) // error ignored for sake of simplicity + + if err != nil { + Log.WithField("error", err).Error("websocket error") + } + + for { + e := event{Format: true} + + err := conn.ReadJSON(&e) + + r := newResponse(e) + + if err != nil { + Log.WithField("error", err).Error("cannot read json message") + r.SetError(errors.Convert(err)) + } else { + err := e.validate() + + if err != nil { + Log.WithField("error", err).Error("invalid event") + r.SetError(err) + } else { + // Log message + logfields := logrus.Fields{"remote": conn.RemoteAddr(), "event": e} + Log.WithFields(logfields).Info("receive") + + // Dispatch action and return response + data, err := dispatchEvent(e) + + r.EndDate = time.Now() + r.Duration = r.EndDate.Sub(r.StartDate).String() + + if err != nil { + Log.WithField("error", err).Error("cannot dispatch request") + r.SetError(err) + } else { + Log.Debug(data) + r.SetData(data) + } + } + } + + Log.WithField("response", r).Debug("response before send to client") + + // Write response to client + if err = conn.WriteJSON(r); err != nil { + return + } + } + }) + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "web/websocket.html") + }) + + var httpErr error + protocol := Config.GetString("protocol") + host := Config.GetString("host") + port := Config.GetInt(strings.Join([]string{protocol, "_port"}, "")) + addr := strings.Join([]string{host, ":", strconv.Itoa(port)}, "") + url := strings.Join([]string{protocol, "://", addr}, "") + + logfields := logrus.Fields{"host": host, "port": port, "url": url} + Log.WithFields(logfields).Info("server started") + + if protocol == "https" { + crt := Config.GetString("ssl_crt") + key := Config.GetString("ssl_key") + if _, err := os.Stat(crt); err != nil { + Log.WithField("error", err).Fatal("could not find certificate file") + } + if _, err := os.Stat(key); err != nil { + Log.WithField("error", err).Fatal("could not find key file") + } + httpErr = http.ListenAndServeTLS(addr, crt, key, nil) + + } else { + httpErr = http.ListenAndServe(addr, nil) + } + + if httpErr != nil { + Log.WithField("error", httpErr).Fatal("listener fatal error") + } +} From 5fe7bf5a488823058601c9686b7fa8a8ac3ca7b0 Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:02:22 +0200 Subject: [PATCH 4/9] :sparkles: add info pkg --- internal/pkg/info/common.go | 267 +++++++++++++++ internal/pkg/info/container.go | 320 +++++++++++++++++ internal/pkg/info/cpu.go | 274 +++++++++++++++ internal/pkg/info/disk.go | 253 ++++++++++++++ internal/pkg/info/general.go | 32 ++ internal/pkg/info/host.go | 176 ++++++++++ internal/pkg/info/memory.go | 76 ++++ internal/pkg/info/network.go | 282 +++++++++++++++ internal/pkg/info/process.go | 610 +++++++++++++++++++++++++++++++++ 9 files changed, 2290 insertions(+) create mode 100644 internal/pkg/info/common.go create mode 100644 internal/pkg/info/container.go create mode 100644 internal/pkg/info/cpu.go create mode 100644 internal/pkg/info/disk.go create mode 100644 internal/pkg/info/general.go create mode 100644 internal/pkg/info/host.go create mode 100644 internal/pkg/info/memory.go create mode 100644 internal/pkg/info/network.go create mode 100644 internal/pkg/info/process.go diff --git a/internal/pkg/info/common.go b/internal/pkg/info/common.go new file mode 100644 index 0000000..8a5dce0 --- /dev/null +++ b/internal/pkg/info/common.go @@ -0,0 +1,267 @@ +package info + +import ( + // "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "strconv" + "time" +) + +type info interface { + String() string + Text() string + Format() string +} + +type byte float64 + +func (b byte) String() string { + return strconv.FormatFloat(float64(b), 'f', 2, 64) +} + +func (b byte) Text() string { + s := b.String() + + return s + "B" +} + +func (b byte) Format() string { + switch { + case b >= pb: + v := b / pb + return v.String() + "PB" + case b >= tb: + v := b / tb + return v.String() + "TB" + case b >= gb: + v := b / gb + return v.String() + "GB" + case b >= mb: + v := b / mb + return v.String() + "MB" + case b >= kb: + v := b / kb + return v.String() + "KB" + } + return b.Text() +} + +type byteSpeed float64 + +func (bs byteSpeed) String() string { + return strconv.FormatFloat(float64(bs), 'f', 2, 64) +} + +func (bs byteSpeed) Text() string { + s := byte(bs).Text() + + return s + "/S" +} + +func (bs byteSpeed) Format() string { + b := byte(bs) + switch { + case b >= pb: + v := b / pb + return v.Format() + "/S" + case b >= tb: + v := b / tb + return v.Format() + "/S" + case b >= gb: + v := b / gb + return v.Format() + "/S" + case b >= mb: + v := b / mb + return v.Format() + "/S" + case b >= kb: + v := b / kb + return v.Format() + "/S" + } + return bs.Text() +} + +type percent float64 + +func (p percent) String() string { + return strconv.FormatFloat(float64(p), 'f', 2, 64) +} + +func (p percent) Text() string { + s := p.String() + + return s + "%" +} + +func (p percent) Format() string { + return p.Text() +} + +type frequency float64 + +func (f frequency) String() string { + return strconv.FormatFloat(float64(f), 'f', 2, 64) +} + +func (f frequency) Text() string { + s := f.String() + + return s + " MHz" +} + +func (f frequency) Format() string { + return f.Text() +} + +type jiffy float64 + +func (j jiffy) String() string { + return strconv.FormatFloat(float64(j), 'f', 4, 64) +} + +func (j jiffy) Text() string { + s := j.String() + + return s + " jiffies" +} + +func (j jiffy) Format() string { + s := strconv.FormatFloat(float64(j/100), 'f', 4, 64) + "s" + + d, _ := time.ParseDuration(s) + + return d.String() +} + +type number int + +func (n number) String() string { + return strconv.Itoa(int(n)) +} + +func (n number) Text() string { + return n.String() +} + +func (n number) Format() string { + return n.Text() +} + +type systemtime int64 + +func (st systemtime) String() string { + return strconv.FormatInt(int64(st), 10) +} + +func (st systemtime) Text() string { + str := st.String() + + return str + "s" +} + +func (st systemtime) Format() string { + t := time.Unix(int64(st), 0) + + return t.String() +} + +type second float64 + +func (s second) String() string { + return strconv.FormatFloat(float64(s), 'f', 4, 64) +} + +func (s second) Text() string { + str := s.String() + + return str + "s" +} + +func (s second) Format() string { + d, _ := time.ParseDuration(s.Text()) + + return d.String() +} + +type millisecond float64 + +func (m millisecond) String() string { + return strconv.FormatFloat(float64(m), 'f', 4, 64) +} + +func (m millisecond) Text() string { + s := m.String() + + return s + "ms" +} + +func (m millisecond) Format() string { + d, _ := time.ParseDuration(m.Text()) + + return d.String() +} + +type temperature float64 + +func (t temperature) String() string { + return strconv.FormatFloat(float64(t), 'f', 2, 64) +} + +func (t temperature) Text() string { + s := t.String() + + return s + "°C" +} + +func (t temperature) Format() string { + + return t.Text() +} + +const ( + b byte = 1 << (10 * iota) + kb + mb + gb + tb + pb +) + +type numberSlice []number + +func (r numberSlice) Convert() []info { + infos := make([]info, len(r)) + for i, v := range r { + infos[i] = v + } + + return infos +} + +func newNumberSlice32(slice []int32) numberSlice { + var ns numberSlice + + for _, val := range slice { + ns = append(ns, number(val)) + } + + return ns +} + + +func convertInfoSlice(slice []info, method string) []string { + var ret []string + + for _, inf := range slice { + switch method { + case "string": + ret = append(ret, inf.String()) + case "text": + ret = append(ret, inf.Text()) + case "format": + ret = append(ret, inf.Format()) + default: + ret = append(ret, "") + } + } + + return ret +} \ No newline at end of file diff --git a/internal/pkg/info/container.go b/internal/pkg/info/container.go new file mode 100644 index 0000000..5f2a69f --- /dev/null +++ b/internal/pkg/info/container.go @@ -0,0 +1,320 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/docker" + "strconv" +) + +// ContainerStat def +type ContainerStat struct { + ContainerID string `json:"containerId"` + Name string `json:"name"` + Image string `json:"image"` + Status string `json:"status"` + Running bool `json:"running"` + CPU containerCPUStat `json:"cpu"` + Memory containerMemStat `json:"memory"` +} + +// ContainerStatFormat def +type ContainerStatFormat struct { + ContainerID string `json:"containerId"` + Name string `json:"name"` + Image string `json:"image"` + Status string `json:"status"` + Running string `json:"running"` + CPU containerCPUStatFormat `json:"cpu"` + Memory containerMemStatFormat `json:"memory"` +} + +// Text return +func (ds ContainerStat) Text() ContainerStatFormat { + cID := ds.ContainerID + n := ds.Name + i := ds.Image + s := ds.Status + r := strconv.FormatBool(ds.Running) + cp := ds.CPU.Text() + mem := ds.Memory.Text() + + return ContainerStatFormat{cID, n, i, s, r, cp, mem} +} + +// Format return +func (ds ContainerStat) Format() ContainerStatFormat { + cID := ds.ContainerID + n := ds.Name + i := ds.Image + s := ds.Status + r := strconv.FormatBool(ds.Running) + cp := ds.CPU.Format() + mem := ds.Memory.Format() + + return ContainerStatFormat{cID, n, i, s, r, cp, mem} +} + +func (ds ContainerStatFormat) String() string { + s, _ := json.Marshal(ds) + return string(s) +} + +type containerCPUStat struct { + Percent percent `json:"percent"` + Times cpuTimes `json:"times"` +} + +type containerCPUStatFormat struct { + Percent string `json:"percent"` + Times cpuTimesFormat `json:"times"` +} + +func (c containerCPUStat) Text() containerCPUStatFormat { + up := c.Percent.Text() + t := c.Times.Text() + + return containerCPUStatFormat{up, t} +} + +func (c containerCPUStat) Format() containerCPUStatFormat { + up := c.Percent.Format() + t := c.Times.Format() + + return containerCPUStatFormat{up, t} +} + +func newContainerCPUStat(per float64, time *cpu.TimesStat) containerCPUStat { + p := percent(per) + t := newCPUTimes(time) + + return containerCPUStat{p, t} +} + +type containerMemStat struct { + ContainerID string `json:"containerId"` + Cache byte `json:"cache"` + RSS number `json:"rss"` + RSSHuge number `json:"rssHuge"` + MappedFile number `json:"mappedFile"` + Pgpgin number `json:"pgpgin"` + Pgpgout number `json:"pgpgout"` + Pgfault number `json:"pgfault"` + Pgmajfault number `json:"pgmajfault"` + InactiveAnon number `json:"inactiveAnon"` + ActiveAnon number `json:"activeAnon"` + InactiveFile number `json:"inactiveFile"` + ActiveFile number `json:"activeFile"` + Unevictable byte `json:"unevictable"` + HierarchicalMemoryLimit byte `json:"hierarchicalMemoryLimit"` + TotalCache byte `json:"totalCache"` + TotalRSS number `json:"totalRss"` + TotalRSSHuge number `json:"totalRssHuge"` + TotalMappedFile number `json:"totalMappedFile"` + TotalPgpgIn number `json:"totalPgpgin"` + TotalPgpgOut number `json:"totalPgpgout"` + TotalPgFault number `json:"totalPgfault"` + TotalPgMajFault number `json:"totalPgmajfault"` + TotalInactiveAnon number `json:"totalInactiveAnon"` + TotalActiveAnon number `json:"totalActiveAnon"` + TotalInactiveFile number `json:"totalInactiveFile"` + TotalActiveFile number `json:"totalActiveFile"` + TotalUnevictable number `json:"totalUnevictable"` + MemUsage byte `json:"memUsage"` + MemMaxUsage byte `json:"memMaxUsage"` + MemLimit byte `json:"memoryLimit"` + MemFailCnt byte `json:"memoryFailcnt"` +} + +type containerMemStatFormat struct { + ContainerID string `json:"containerId"` + Cache string `json:"cache"` + RSS string `json:"rss"` + RSSHuge string `json:"rssHuge"` + MappedFile string `json:"mappedFile"` + Pgpgin string `json:"pgpgin"` + Pgpgout string `json:"pgpgout"` + Pgfault string `json:"pgfault"` + Pgmajfault string `json:"pgmajfault"` + InactiveAnon string `json:"inactiveAnon"` + ActiveAnon string `json:"activeAnon"` + InactiveFile string `json:"inactiveFile"` + ActiveFile string `json:"activeFile"` + Unevictable string `json:"unevictable"` + HierarchicalMemoryLimit string `json:"hierarchicalMemoryLimit"` + TotalCache string `json:"totalCache"` + TotalRSS string `json:"totalRss"` + TotalRSSHuge string `json:"totalRssHuge"` + TotalMappedFile string `json:"totalMappedFile"` + TotalPgpgIn string `json:"totalPgpgin"` + TotalPgpgOut string `json:"totalPgpgout"` + TotalPgFault string `json:"totalPgfault"` + TotalPgMajFault string `json:"totalPgmajfault"` + TotalInactiveAnon string `json:"totalInactiveAnon"` + TotalActiveAnon string `json:"totalActiveAnon"` + TotalInactiveFile string `json:"totalInactiveFile"` + TotalActiveFile string `json:"totalActiveFile"` + TotalUnevictable string `json:"totalUnevictable"` + MemUsage string `json:"memUsage"` + MemMaxUsage string `json:"memMaxUsage"` + MemLimit string `json:"memoryLimit"` + MemFailCnt string `json:"memoryFailcnt"` +} + +func (c containerMemStat) Text() containerMemStatFormat { + cID := c.ContainerID + cache := c.Cache.Text() + rss := c.RSS.Text() + rssH := c.RSSHuge.Text() + mf := c.MappedFile.Text() + pi := c.Pgpgin.Text() + po := c.Pgpgout.Text() + pf := c.Pgfault.Text() + pjf := c.Pgmajfault.Text() + ia := c.InactiveAnon.Text() + aa := c.ActiveAnon.Text() + ifile := c.InactiveFile.Text() + afile := c.ActiveFile.Text() + u := c.Unevictable.Text() + hml := c.HierarchicalMemoryLimit.Text() + tc := c.TotalCache.Text() + trss := c.TotalRSS.Text() + trssh := c.TotalRSSHuge.Text() + tmf := c.TotalMappedFile.Text() + tpi := c.TotalPgpgIn.Text() + tpo := c.TotalPgpgOut.Text() + tpf := c.TotalPgFault.Text() + tpfg := c.TotalPgMajFault.Text() + tia := c.TotalInactiveAnon.Text() + taa := c.TotalActiveAnon.Text() + tifile := c.TotalInactiveFile.Text() + tafile := c.TotalActiveFile.Text() + tu := c.TotalUnevictable.Text() + mu := c.MemUsage.Text() + mmu := c.MemMaxUsage.Text() + ml := c.MemLimit.Text() + mfc := c.MemFailCnt.Text() + + return containerMemStatFormat{cID, cache, rss, rssH, mf, pi, po, pf, pjf, ia, aa, ifile, afile, u, hml, tc, trss, trssh, tmf, tpi, tpo, tpf, tpfg, tia, taa, tifile, tafile, tu, mu, mmu, ml, mfc} +} + +func (c containerMemStat) Format() containerMemStatFormat { + cID := c.ContainerID + cache := c.Cache.Format() + rss := c.RSS.Format() + rssH := c.RSSHuge.Format() + mf := c.MappedFile.Format() + pi := c.Pgpgin.Format() + po := c.Pgpgout.Format() + pf := c.Pgfault.Format() + pjf := c.Pgmajfault.Format() + ia := c.InactiveAnon.Format() + aa := c.ActiveAnon.Format() + ifile := c.InactiveFile.Format() + afile := c.ActiveFile.Format() + u := c.Unevictable.Format() + hml := c.HierarchicalMemoryLimit.Format() + tc := c.TotalCache.Format() + trss := c.TotalRSS.Format() + trssh := c.TotalRSSHuge.Format() + tmf := c.TotalMappedFile.Format() + tpi := c.TotalPgpgIn.Format() + tpo := c.TotalPgpgOut.Format() + tpf := c.TotalPgFault.Format() + tpfg := c.TotalPgMajFault.Format() + tia := c.TotalInactiveAnon.Format() + taa := c.TotalActiveAnon.Format() + tifile := c.TotalInactiveFile.Format() + tafile := c.TotalActiveFile.Format() + tu := c.TotalUnevictable.Format() + mu := c.MemUsage.Format() + mmu := c.MemMaxUsage.Format() + ml := c.MemLimit.Format() + mfc := c.MemFailCnt.Format() + + return containerMemStatFormat{cID, cache, rss, rssH, mf, pi, po, pf, pjf, ia, aa, ifile, afile, u, hml, tc, trss, trssh, tmf, tpi, tpo, tpf, tpfg, tia, taa, tifile, tafile, tu, mu, mmu, ml, mfc} +} + +func newContainerMemStat(c *docker.CgroupMemStat) containerMemStat { + cID := c.ContainerID + cache := byte(c.Cache) + rss := number(c.RSS) + rssH := number(c.RSSHuge) + mf := number(c.MappedFile) + pi := number(c.Pgpgin) + po := number(c.Pgpgout) + pf := number(c.Pgfault) + pjf := number(c.Pgmajfault) + ia := number(c.InactiveAnon) + aa := number(c.ActiveAnon) + ifile := number(c.InactiveFile) + afile := number(c.ActiveFile) + u := byte(c.Unevictable) + hml := byte(c.HierarchicalMemoryLimit) + tc := byte(c.TotalCache) + trss := number(c.TotalRSS) + trssh := number(c.TotalRSSHuge) + tmf := number(c.TotalMappedFile) + tpi := number(c.TotalPgpgIn) + tpo := number(c.TotalPgpgOut) + tpf := number(c.TotalPgFault) + tpfg := number(c.TotalPgMajFault) + tia := number(c.TotalInactiveAnon) + taa := number(c.TotalActiveAnon) + tifile := number(c.TotalInactiveFile) + tafile := number(c.TotalActiveFile) + tu := number(c.TotalUnevictable) + mu := byte(c.MemUsageInBytes) + mmu := byte(c.MemMaxUsageInBytes) + ml := byte(c.MemLimitInBytes) + mfc := byte(c.MemFailCnt) + + return containerMemStat{cID, cache, rss, rssH, mf, pi, po, pf, pjf, ia, aa, ifile, afile, u, hml, tc, trss, trssh, tmf, tpi, tpo, tpf, tpfg, tia, taa, tifile, tafile, tu, mu, mmu, ml, mfc} +} + +// Containers info +func Containers(format bool) ([]ContainerStatFormat, error) { + var containers []ContainerStatFormat + + dock, err := docker.GetDockerStat() + if err != nil { + return containers, errors.Convert(err) + } + + for _, container := range dock { + cpuS, err := docker.CgroupCPUDocker(container.ContainerID) + if err != nil { + return containers, errors.Convert(err) + } + per, err := docker.CgroupCPUUsageDocker(container.ContainerID) + // per := 0.00 + if err != nil { + return containers, errors.Convert(err) + } + cpuStat := newContainerCPUStat(per, cpuS) + + cpuM, err := docker.CgroupMemDocker(container.ContainerID) + if err != nil { + return containers, errors.Convert(err) + } + cpuMem := newContainerMemStat(cpuM) + + dockerStat := ContainerStat{container.ContainerID, container.Name, container.Image, container.Status, container.Running, cpuStat, cpuMem} + + if format { + containers = append(containers, dockerStat.Format()) + } else { + containers = append(containers, dockerStat.Text()) + } + } + + return containers, nil +} + +// ContainersID return slice of container id +func ContainersID() ([]string, error) { + containers, err := docker.GetDockerIDList() + + return containers, errors.Convert(err) +} diff --git a/internal/pkg/info/cpu.go b/internal/pkg/info/cpu.go new file mode 100644 index 0000000..b3ad6ae --- /dev/null +++ b/internal/pkg/info/cpu.go @@ -0,0 +1,274 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/cpu" + "strconv" + "time" +) + +// CPUStat desc +type CPUStat struct { + Count cpuCount `json:"count"` + Info []cpuInfo `json:"info"` +} + +// CPUStatFormat desc +type CPUStatFormat struct { + Count cpuCountFormat `json:"count"` + Info []cpuInfoFormat `json:"info"` +} + +// Text CPUStat +func (cs CPUStat) Text() CPUStatFormat { + c := cs.Count.Text() + + var i []cpuInfoFormat + + for _, info := range cs.Info { + i = append(i, info.Text()) + } + + return CPUStatFormat{c, i} +} + +// Format CPUStat +func (cs CPUStat) Format() CPUStatFormat { + c := cs.Count.Format() + + var i []cpuInfoFormat + + for _, info := range cs.Info { + i = append(i, info.Format()) + } + + return CPUStatFormat{c, i} +} + +func (cs CPUStatFormat) String() string { + s, _ := json.Marshal(cs) + return string(s) +} + +type cpuCount struct { + Physical number `json:"physical"` + Logical number `json:"logical"` +} +type cpuCountFormat struct { + Physical string `json:"physical"` + Logical string `json:"logical"` +} + +func (c cpuCount) Text() cpuCountFormat { + p := c.Physical.Text() + l := c.Logical.Text() + + return cpuCountFormat{p, l} +} + +func (c cpuCount) Format() cpuCountFormat { + p := c.Physical.Format() + l := c.Logical.Format() + + return cpuCountFormat{p, l} +} + +func newCPUCount(physical int, logical int) cpuCount { + p := number(physical) + l := number(logical) + + return cpuCount{p, l} +} + +type cpuInfo struct { + ID string `json:"id"` + Percent percent `json:"percent"` + Times cpuTimes `json:"times"` +} + +func (ci cpuInfo) Text() cpuInfoFormat { + id := ci.ID + p := ci.Percent.Text() + t := ci.Times.Text() + + return cpuInfoFormat{id, p, t} +} + +func (ci cpuInfo) Format() cpuInfoFormat { + id := ci.ID + p := ci.Percent.Format() + t := ci.Times.Format() + + return cpuInfoFormat{id, p, t} +} + +type cpuInfoFormat struct { + ID string `json:"id"` + Percent string `json:"percent"` + Times cpuTimesFormat `json:"times"` +} + +type cpuTimes struct { + User jiffy `json:"user"` + System jiffy `json:"system"` + Idle jiffy `json:"idle"` + Nice jiffy `json:"nice"` + Iowait jiffy `json:"iowait"` + Irq jiffy `json:"irq"` + Softirq jiffy `json:"softirq"` + Steal jiffy `json:"steal"` + Guest jiffy `json:"guest"` + GuestNice jiffy `json:"guestNice"` + Total jiffy `json:"total"` +} + +type cpuTimesFormat struct { + User string `json:"user"` + System string `json:"system"` + Idle string `json:"idle"` + Nice string `json:"nice"` + Iowait string `json:"iowait"` + Irq string `json:"irq"` + Softirq string `json:"softirq"` + Steal string `json:"steal"` + Guest string `json:"guest"` + GuestNice string `json:"guestNice"` + Total string `json:"total"` +} + +func (ct cpuTimes) Text() cpuTimesFormat { + u := ct.User.Text() + s := ct.System.Text() + i := ct.Idle.Text() + n := ct.Nice.Text() + io := ct.Iowait.Text() + irq := ct.Irq.Text() + softirq := ct.Softirq.Text() + st := ct.Steal.Text() + g := ct.Guest.Text() + gn := ct.GuestNice.Text() + t := ct.Total.Text() + + return cpuTimesFormat{u, s, i, n, io, irq, softirq, st, g, gn, t} +} + +func (ct cpuTimes) Format() cpuTimesFormat { + u := ct.User.Format() + s := ct.System.Format() + i := ct.Idle.Format() + n := ct.Nice.Format() + io := ct.Iowait.Format() + irq := ct.Irq.Format() + softirq := ct.Softirq.Format() + st := ct.Steal.Format() + g := ct.Guest.Format() + gn := ct.GuestNice.Format() + t := ct.Total.Format() + + return cpuTimesFormat{u, s, i, n, io, irq, softirq, st, g, gn, t} +} + +func newCPUTimes(ts *cpu.TimesStat) cpuTimes { + if ts == nil { + return cpuTimes{} + } + user := jiffy(ts.User) + system := jiffy(ts.System) + idle := jiffy(ts.Idle) + nice := jiffy(ts.Nice) + iowait := jiffy(ts.Iowait) + irq := jiffy(ts.Irq) + softirq := jiffy(ts.Softirq) + steal := jiffy(ts.Steal) + guest := jiffy(ts.Guest) + guestnice := jiffy(ts.GuestNice) + total := jiffy(ts.Total()) + + return cpuTimes{user, system, idle, nice, iowait, irq, softirq, steal, guest, guestnice, total} +} + +func getCPUInfoTotal() (cpuInfo, error) { + totalCPUPercent, err := cpu.Percent(time.Second, false) + if err != nil { + return cpuInfo{}, errors.Convert(err) + } + p := percent(totalCPUPercent[0]) + + totalTimeStat, err := cpu.Times(false) + if err != nil { + return cpuInfo{}, errors.Convert(err) + } + t := newCPUTimes(&totalTimeStat[0]) + + return cpuInfo{"total", p, t}, nil +} + +func getCPUInfo() ([]cpuInfo, error) { + cpus := []cpuInfo{} + + total, err := getCPUInfoTotal() + if err != nil { + return nil, err + } + + cpus = append(cpus, total) + + allTimes, err := cpu.Times(true) + if err != nil { + return nil, errors.Convert(err) + } + + allPercent, err := cpu.Percent(time.Second, true) + if err != nil { + return nil, errors.Convert(err) + } + + for index, val := range allTimes { + id := strconv.Itoa(index) + percent := percent(allPercent[index]) + times := newCPUTimes(&val) + + info := cpuInfo{id, percent, times} + + cpus = append(cpus, info) + + } + + return cpus, nil +} + +// CPU info +func CPU(format bool) (CPUStatFormat, error) { + + physical, err := cpu.Counts(false) + if err != nil { + return CPUStatFormat{}, errors.Convert(err) + } + + logical, err := cpu.Counts(true) + if err != nil { + return CPUStatFormat{}, errors.Convert(err) + } + + infos, err := getCPUInfo() + if err != nil { + return CPUStatFormat{}, err + } + + count := newCPUCount(physical, logical) + cpuStat := CPUStat{count, infos} + + if format { + return cpuStat.Format(), nil + } + + return cpuStat.Text(), nil +} + +// CPUinfo info on cpu +func CPUinfo() ([]cpu.InfoStat, error) { + info, err := cpu.Info() + + return info, errors.Convert(err) +} diff --git a/internal/pkg/info/disk.go b/internal/pkg/info/disk.go new file mode 100644 index 0000000..c231d6d --- /dev/null +++ b/internal/pkg/info/disk.go @@ -0,0 +1,253 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/disk" +) + +// DiskStat def +type DiskStat struct { + Device string `json:"device"` + Mountpoint string `json:"mountpoint"` + Fstype string `json:"fstype"` + Opts string `json:"opts"` + Usage diskUsage `json:"usage"` + IOCounters diskCounters `json:"iocounters"` +} + +// DiskStatFormat def +type DiskStatFormat struct { + Device string `json:"device"` + Mountpoint string `json:"mountpoint"` + Fstype string `json:"fstype"` + Opts string `json:"opts"` + Usage diskUsageFormat `json:"usage"` + IOCounters diskCountersFormat `json:"iocounters"` +} + +// Text of DiskStat +func (d DiskStat) Text() DiskStatFormat { + u := d.Usage.Text() + io := d.IOCounters.Text() + + return DiskStatFormat{d.Device, d.Mountpoint, d.Fstype, d.Opts, u, io} +} + +// Format of DiskStat +func (d DiskStat) Format() DiskStatFormat { + u := d.Usage.Format() + io := d.IOCounters.Format() + + return DiskStatFormat{d.Device, d.Mountpoint, d.Fstype, d.Opts, u, io} +} + +func (d DiskStatFormat) String() string { + s, _ := json.Marshal(d) + return string(s) +} + +func newDiskStat(d disk.PartitionStat) (DiskStat, error) { + u, err := disk.Usage(d.Mountpoint) + if err != nil { + return DiskStat{}, err + } + usage := newDiskUsage(u) + + io, err := disk.IOCounters(d.Mountpoint) + if err != nil { + return DiskStat{}, err + } + iocounter := newDiskCounter(io[d.Mountpoint]) + + return DiskStat{d.Device, d.Mountpoint, d.Fstype, d.Opts, usage, iocounter}, nil +} + +type diskUsage struct { + Path string `json:"path"` + Fstype string `json:"fstype"` + Total byte `json:"total"` + Free byte `json:"free"` + Used byte `json:"used"` + UsedPercent percent `json:"usedPercent"` + InodesTotal number `json:"inodesTotal"` + InodesUsed number `json:"inodesUsed"` + InodesFree number `json:"inodesFree"` + InodesUsedPercent percent `json:"inodesUsedPercent"` +} + +type diskUsageFormat struct { + Path string `json:"path"` + Fstype string `json:"fstype"` + Total string `json:"total"` + Free string `json:"free"` + Used string `json:"used"` + UsedPercent string `json:"usedPercent"` + InodesTotal string `json:"inodesTotal"` + InodesUsed string `json:"inodesUsed"` + InodesFree string `json:"inodesFree"` + InodesUsedPercent string `json:"inodesUsedPercent"` +} + +func (d diskUsage) Text() diskUsageFormat { + p := d.Path + fs := d.Fstype + t := d.Total.Text() + f := d.Free.Text() + u := d.Used.Text() + up := d.UsedPercent.Text() + it := d.InodesTotal.Text() + iu := d.InodesUsed.Text() + inf := d.InodesFree.Text() + iup := d.InodesUsedPercent.Text() + + return diskUsageFormat{p, fs, t, f, u, up, it, iu, inf, iup} +} + +func (d diskUsage) Format() diskUsageFormat { + p := d.Path + fs := d.Fstype + t := d.Total.Format() + f := d.Free.Format() + u := d.Used.Format() + up := d.UsedPercent.Format() + it := d.InodesTotal.Format() + iu := d.InodesUsed.Format() + inf := d.InodesFree.Format() + iup := d.InodesUsedPercent.Format() + + return diskUsageFormat{p, fs, t, f, u, up, it, iu, inf, iup} +} + +func newDiskUsage(d *disk.UsageStat) diskUsage { + p := d.Path + fs := d.Fstype + t := byte(d.Total) + f := byte(d.Free) + u := byte(d.Used) + up := percent(d.UsedPercent) + it := number(d.InodesTotal) + iu := number(d.InodesUsed) + inf := number(d.InodesFree) + iup := percent(d.InodesUsedPercent) + + return diskUsage{p, fs, t, f, u, up, it, iu, inf, iup} +} + +type diskCounters struct { + ReadCount number `json:"readCount"` + MergedReadCount number `json:"mergedReadCount"` + WriteCount number `json:"writeCount"` + MergedWriteCount number `json:"mergedWriteCount"` + ReadBytes byte `json:"readBytes"` + WriteBytes byte `json:"writeBytes"` + ReadTime millisecond `json:"readTime"` + WriteTime millisecond `json:"writeTime"` + IopsInProgress number `json:"iopsInProgress"` + IoTime millisecond `json:"ioTime"` + WeightedIO number `json:"weightedIO"` + Name string `json:"name"` + Serialnumber string `json:"serialnumber"` + Label string `json:"label"` +} + +type diskCountersFormat struct { + ReadCount string `json:"readCount"` + MergedReadCount string `json:"mergedReadCount"` + WriteCount string `json:"writeCount"` + MergedWriteCount string `json:"mergedWriteCount"` + ReadBytes string `json:"readBytes"` + WriteBytes string `json:"writeBytes"` + ReadTime string `json:"readTime"` + WriteTime string `json:"writeTime"` + IopsInProgress string `json:"iopsInProgress"` + IoTime string `json:"ioTime"` + WeightedIO string `json:"weightedIO"` + Name string `json:"name"` + Serialnumber string `json:"serialnumber"` + Label string `json:"label"` +} + +func (d diskCounters) Text() diskCountersFormat { + rc := d.ReadCount.Text() + mrc := d.MergedReadCount.Text() + wc := d.WriteCount.Text() + mwc := d.MergedWriteCount.Text() + rb := d.ReadBytes.Text() + wb := d.WriteBytes.Text() + rt := d.ReadTime.Text() + wt := d.WriteTime.Text() + iip := d.IopsInProgress.Text() + it := d.IoTime.Text() + wi := d.WeightedIO.Text() + n := d.Name + sn := d.Serialnumber + l := d.Label + + return diskCountersFormat{rc, mrc, wc, mwc, rb, wb, rt, wt, iip, it, wi, n, sn, l} +} + +func (d diskCounters) Format() diskCountersFormat { + rc := d.ReadCount.Format() + mrc := d.MergedReadCount.Format() + wc := d.WriteCount.Format() + mwc := d.MergedWriteCount.Format() + rb := d.ReadBytes.Format() + wb := d.WriteBytes.Format() + rt := d.ReadTime.Format() + wt := d.WriteTime.Format() + iip := d.IopsInProgress.Format() + it := d.IoTime.Format() + wi := d.WeightedIO.Format() + n := d.Name + sn := d.Serialnumber + l := d.Label + + return diskCountersFormat{rc, mrc, wc, mwc, rb, wb, rt, wt, iip, it, wi, n, sn, l} +} + +func newDiskCounter(d disk.IOCountersStat) diskCounters { + rc := number(d.ReadCount) + mrc := number(d.MergedReadCount) + wc := number(d.WriteCount) + mwc := number(d.MergedWriteCount) + rb := byte(d.ReadBytes) + wb := byte(d.WriteBytes) + rt := millisecond(d.ReadTime) + wt := millisecond(d.WriteTime) + iip := number(d.IopsInProgress) + it := millisecond(d.IoTime) + wi := number(d.WeightedIO) + n := d.Name + sn := d.SerialNumber + l := d.Label + + return diskCounters{rc, mrc, wc, mwc, rb, wb, rt, wt, iip, it, wi, n, sn, l} +} + +// Disks info +func Disks(format bool) ([]DiskStatFormat, error) { + d, err := disk.Partitions(true) + + if err != nil { + return nil, errors.Convert(err) + } + + var diskinfo []DiskStatFormat + + for _, disk := range d { + ds, err := newDiskStat(disk) + + if err != nil { + return nil, errors.Convert(err) + } + + if format { + diskinfo = append(diskinfo, ds.Format()) + } else { + diskinfo = append(diskinfo, ds.Text()) + } + } + + return diskinfo, nil +} diff --git a/internal/pkg/info/general.go b/internal/pkg/info/general.go new file mode 100644 index 0000000..d215626 --- /dev/null +++ b/internal/pkg/info/general.go @@ -0,0 +1,32 @@ +package info + +// GeneralStatFormat def +type GeneralStatFormat struct { + CPU CPUStatFormat `json:"cpu"` + Disks []DiskStatFormat `json:"disks"` + Containers []ContainerStatFormat `json:"containers"` + Host HostStatFormat `json:"host"` + Memory MemoryStatFormat `json:"memory"` + Network NetworkStatFormat `json:"network"` + Processes []ProcessLightStatFormat `json:"processes"` +} + +// General system information +func General(format bool) (GeneralStatFormat, error) { + + cpu, _ := CPU(format) + + disk, _ := Disks(format) + + containers, _ := Containers(format) + + host, _ := Host(format) + + memory, _ := Memory(format) + + network, _ := Network(format) + + processes, _ := Processes(format) + + return GeneralStatFormat{cpu, disk, containers, host, memory, network, processes}, nil +} diff --git a/internal/pkg/info/host.go b/internal/pkg/info/host.go new file mode 100644 index 0000000..91ea203 --- /dev/null +++ b/internal/pkg/info/host.go @@ -0,0 +1,176 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/host" +) + +// HostStat def +type HostStat struct { + Hostname string `json:"hostname"` + Uptime second `json:"uptime"` + BootTime systemtime `json:"bootTime"` + Procs number `json:"procs"` + OS string `json:"os"` + Platform string `json:"platform"` + PlatformFamily string `json:"platformFamily"` + PlatformVersion string `json:"platformVersion"` + KernelVersion string `json:"kernelVersion"` + VirtualizationSystem string `json:"virtualizationSystem"` + VirtualizationRole string `json:"virtualizationRole"` + HostID string `json:"hostid"` + Sensors []sensorStat `json:"sensors"` +} + +// HostStatFormat def +type HostStatFormat struct { + Hostname string `json:"hostname"` + Uptime string `json:"uptime"` + BootTime string `json:"bootTime"` + Procs string `json:"procs"` + OS string `json:"os"` + Platform string `json:"platform"` + PlatformFamily string `json:"platformFamily"` + PlatformVersion string `json:"platformVersion"` + KernelVersion string `json:"kernelVersion"` + VirtualizationSystem string `json:"virtualizationSystem"` + VirtualizationRole string `json:"virtualizationRole"` + HostID string `json:"hostId"` + Sensors []sensorStatFormat `json:"sensors"` +} + +// Text formatting +func (hs HostStat) Text() HostStatFormat { + hn := hs.Hostname + upt := hs.Uptime.Text() + bt := hs.BootTime.Text() + procs := hs.Procs.Text() + os := hs.OS + p := hs.Platform + pf := hs.PlatformFamily + pv := hs.PlatformVersion + kv := hs.KernelVersion + vs := hs.VirtualizationSystem + vr := hs.VirtualizationRole + hID := hs.HostID + + var sensors []sensorStatFormat + + for _, sensor := range hs.Sensors { + sensors = append(sensors, sensor.Text()) + } + + return HostStatFormat{hn, upt, bt, procs, os, p, pf, pv, kv, vs, vr, hID, sensors} +} + +// Format formatting +func (hs HostStat) Format() HostStatFormat { + hn := hs.Hostname + upt := hs.Uptime.Format() + bt := hs.BootTime.Format() + procs := hs.Procs.Format() + os := hs.OS + p := hs.Platform + pf := hs.PlatformFamily + pv := hs.PlatformVersion + kv := hs.KernelVersion + vs := hs.VirtualizationSystem + vr := hs.VirtualizationRole + hID := hs.HostID + + var sensors []sensorStatFormat + + for _, sensor := range hs.Sensors { + sensors = append(sensors, sensor.Format()) + } + + return HostStatFormat{hn, upt, bt, procs, os, p, pf, pv, kv, vs, vr, hID, sensors} +} + +func (hs HostStatFormat) String() string { + s, _ := json.Marshal(hs) + return string(s) +} + +func newHostStat(info *host.InfoStat, sensors []sensorStat) HostStat { + hn := info.Hostname + upt := second(info.Uptime) + bt := systemtime(info.BootTime) + procs := number(info.Procs) + os := info.OS + p := info.Platform + pf := info.PlatformFamily + pv := info.PlatformVersion + kv := info.KernelVersion + vs := info.VirtualizationSystem + vr := info.VirtualizationRole + hID := info.HostID + + return HostStat{hn, upt, bt, procs, os, p, pf, pv, kv, vs, vr, hID, sensors} +} + +type sensorStat struct { + SensorKey string `json:"sensorKey"` + Temperature temperature `json:"sensorTemperature"` +} + +type sensorStatFormat struct { + SensorKey string `json:"sensorKey"` + Temperature string `json:"sensorTemperature"` +} + +func (ss sensorStat) Text() sensorStatFormat { + sk := ss.SensorKey + temp := ss.Temperature.Text() + + return sensorStatFormat{sk, temp} +} + +func (ss sensorStat) Format() sensorStatFormat { + sk := ss.SensorKey + temp := ss.Temperature.Format() + + return sensorStatFormat{sk, temp} +} + +func newSensorStat(ts *host.TemperatureStat) sensorStat { + sk := ts.SensorKey + temp := temperature(ts.Temperature) + + return sensorStat{sk, temp} +} + +// Host information +func Host(format bool) (HostStatFormat, error) { + var sensors []sensorStat + + sensorsTemp, err := host.SensorsTemperatures() + if err != nil { + return HostStatFormat{}, errors.Convert(err) + } + + for _, sensor := range sensorsTemp { + sensors = append(sensors, newSensorStat(&sensor)) + } + + h, err := host.Info() + if err != nil { + return HostStatFormat{}, errors.Convert(err) + } + + hostS := newHostStat(h, sensors) + + if format { + return hostS.Format(), nil + } + + return hostS.Text(), nil +} + +// Users of host +func Users() ([]host.UserStat, error) { + usr, err := host.Users() + + return usr, errors.Convert(err) +} \ No newline at end of file diff --git a/internal/pkg/info/memory.go b/internal/pkg/info/memory.go new file mode 100644 index 0000000..809fc5f --- /dev/null +++ b/internal/pkg/info/memory.go @@ -0,0 +1,76 @@ +package info + +import ( + "encoding/json" + + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/mem" +) + +// MemoryStat desc +type MemoryStat struct { + Total byte `json:"total"` + Available byte `json:"available"` + Used byte `json:"used"` + UsedPercent percent `json:"usedPercent"` + Free byte `json:"free"` +} + +// MemoryStatFormat desc +type MemoryStatFormat struct { + Total string `json:"total"` + Available string `json:"available"` + Used string `json:"used"` + Usedpercent string `json:"usedpercent"` + Free string `json:"free"` +} + +// Text MemoryStat values +func (ms MemoryStat) Text() MemoryStatFormat { + t := ms.Total.Text() + a := ms.Available.Text() + u := ms.Used.Text() + up := ms.UsedPercent.Text() + f := ms.Free.Text() + + return MemoryStatFormat{t, a, u, up, f} +} + +// Format MemoryStat values +func (ms MemoryStat) Format() MemoryStatFormat { + t := ms.Total.Format() + a := ms.Available.Format() + u := ms.Used.Format() + up := ms.UsedPercent.Format() + f := ms.Free.Format() + + return MemoryStatFormat{t, a, u, up, f} +} + +func (ms MemoryStatFormat) String() string { + s, _ := json.Marshal(ms) + return string(s) +} + +// Memory return memory info +func Memory(format bool) (MemoryStatFormat, error) { + v, err := mem.VirtualMemory() + + if err != nil { + return MemoryStatFormat{}, errors.Convert(err) + } + + total := byte(v.Total) + available := byte(v.Available) + used := byte(v.Used) + usedPer := percent(v.UsedPercent) + free := byte(v.Free) + + memInfo := MemoryStat{total, available, used, usedPer, free} + + if format { + return memInfo.Format(), nil + } + + return memInfo.Text(), nil +} diff --git a/internal/pkg/info/network.go b/internal/pkg/info/network.go new file mode 100644 index 0000000..cf4ac74 --- /dev/null +++ b/internal/pkg/info/network.go @@ -0,0 +1,282 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/net" + "time" +) + +// NetworkStat def +type NetworkStat struct { + Usage networkIOCounter `json:"usage"` + Interfaces []networkInterface `json:"interfaces"` +} + +// NetworkStatFormat def +type NetworkStatFormat struct { + Usage networkIOCounterFormat `json:"usage"` + Interfaces []networkInterfaceFormat `json:"interfaces"` +} + +// Text formatting +func (ns NetworkStat) Text() NetworkStatFormat { + u := ns.Usage.Text() + var ints []networkInterfaceFormat + + for _, i := range ns.Interfaces { + ints = append(ints, i.Text()) + } + + return NetworkStatFormat{u, ints} +} + +// Format network stat +func (ns NetworkStat) Format() NetworkStatFormat { + u := ns.Usage.Format() + var ints []networkInterfaceFormat + + for _, i := range ns.Interfaces { + ints = append(ints, i.Format()) + } + + return NetworkStatFormat{u, ints} +} + +func (ns NetworkStatFormat) String() string { + s, _ := json.Marshal(ns) + return string(s) +} + +type networkInterface struct { + MTU number `json:"mtu"` + Name string `json:"name"` + HardwareAddr string `json:"hardwareaddr"` + Flags []string `json:"flags"` + Addrs []net.InterfaceAddr `json:"addrs"` + Usage networkIOCounter `json:"usage"` +} + +type networkInterfaceFormat struct { + MTU string `json:"mtu"` + Name string `json:"name"` + HardwareAddr string `json:"hardwareaddr"` + Flags []string `json:"flags"` + Addrs []net.InterfaceAddr `json:"addrs"` + Usage networkIOCounterFormat `json:"usage"` +} + +func (ni networkInterface) Text() networkInterfaceFormat { + mtu := ni.MTU.Text() + n := ni.Name + ha := ni.HardwareAddr + flags := ni.Flags + addrs := ni.Addrs + u := ni.Usage.Text() + + return networkInterfaceFormat{mtu, n, ha, flags, addrs, u} +} + +func (ni networkInterface) Format() networkInterfaceFormat { + mtu := ni.MTU.Format() + n := ni.Name + ha := ni.HardwareAddr + flags := ni.Flags + addrs := ni.Addrs + u := ni.Usage.Format() + + return networkInterfaceFormat{mtu, n, ha, flags, addrs, u} +} + +func newNetworkInterface(nic *net.InterfaceStat, ioBefore *net.IOCountersStat, ioAfter *net.IOCountersStat) networkInterface { + mtu := number(nic.MTU) + n := nic.Name + ha := nic.HardwareAddr + flags := nic.Flags + addrs := nic.Addrs + byteSentPerSec := ioAfter.BytesSent - ioBefore.BytesSent + byteRecvPerSec := ioAfter.BytesRecv - ioBefore.BytesRecv + u := newNetworkIOCounter(ioAfter, byteSentPerSec, byteRecvPerSec) + + return networkInterface{mtu, n, ha, flags, addrs, u} +} + +type networkIOCounter struct { + Name string `json:"name"` + BytesSent byte `json:"bytesSent"` + BytesRecv byte `json:"bytesRecv"` + BytesSentPerSec byteSpeed `json:"bytesSentPerSec"` + BytesRecvPerSec byteSpeed `json:"bytesRecvPerSec"` + PacketsSent number `json:"packetsSent"` + PacketsRecv number `json:"packetsRecv"` + Errin number `json:"errin"` + Errout number `json:"errout"` + Dropin number `json:"dropin"` + Dropout number `json:"dropout"` + Fifoin number `json:"fifoin"` + Fifoout number `json:"fifoout"` +} + +type networkIOCounterFormat struct { + Name string `json:"name"` + BytesSent string `json:"bytesSent"` + BytesRecv string `json:"bytesRecv"` + BytesSentPerSec string `json:"bytesSentPerSec"` + BytesRecvPerSec string `json:"bytesRecvPerSec"` + PacketsSent string `json:"packetsSent"` + PacketsRecv string `json:"packetsRecv"` + Errin string `json:"errin"` + Errout string `json:"errout"` + Dropin string `json:"dropin"` + Dropout string `json:"dropout"` + Fifoin string `json:"fifoin"` + Fifoout string `json:"fifoout"` +} + +func (nIOC networkIOCounter) Text() networkIOCounterFormat { + n := nIOC.Name + bs := nIOC.BytesSent.Text() + br := nIOC.BytesRecv.Text() + bsps := nIOC.BytesSentPerSec.Text() + brps := nIOC.BytesRecvPerSec.Text() + ps := nIOC.PacketsSent.Text() + pr := nIOC.PacketsRecv.Text() + ei := nIOC.Errin.Text() + eo := nIOC.Errout.Text() + di := nIOC.Dropin.Text() + do := nIOC.Dropout.Text() + fi := nIOC.Fifoin.Text() + fo := nIOC.Fifoout.Text() + + return networkIOCounterFormat{n, bs, br, bsps, brps, ps, pr, ei, eo, di, do, fi, fo} +} + +func (nIOC networkIOCounter) Format() networkIOCounterFormat { + n := nIOC.Name + bs := nIOC.BytesSent.Format() + br := nIOC.BytesRecv.Format() + bsps := nIOC.BytesSentPerSec.Format() + brps := nIOC.BytesRecvPerSec.Format() + ps := nIOC.PacketsSent.Format() + pr := nIOC.PacketsRecv.Format() + ei := nIOC.Errin.Format() + eo := nIOC.Errout.Format() + di := nIOC.Dropin.Format() + do := nIOC.Dropout.Format() + fi := nIOC.Fifoin.Format() + fo := nIOC.Fifoout.Format() + + return networkIOCounterFormat{n, bs, br, bsps, brps, ps, pr, ei, eo, di, do, fi, fo} +} + +func newNetworkIOCounter(io *net.IOCountersStat, byteSentPerSec uint64, byteRecvPerSec uint64) networkIOCounter { + n := io.Name + bs := byte(io.BytesSent) + br := byte(io.BytesRecv) + bsps := byteSpeed(byteSentPerSec) + brps := byteSpeed(byteRecvPerSec) + ps := number(io.PacketsSent) + pr := number(io.PacketsRecv) + ei := number(io.Errin) + eo := number(io.Errout) + di := number(io.Dropin) + do := number(io.Dropout) + fi := number(io.Fifoin) + fo := number(io.Fifoout) + + return networkIOCounter{n, bs, br, bsps, brps, ps, pr, ei, eo, di, do, fi, fo} +} + +func buildTotalIOCounter(io chan networkIOCounter, e chan error) { + + before, err := net.IOCounters(false) + if err != nil { + io <- networkIOCounter{} + e <- err + return + } + time.Sleep(time.Second) + after, err := net.IOCounters(false) + if err != nil { + io <- networkIOCounter{} + e <- err + return + } + + bsps := after[0].BytesSent - before[0].BytesSent + brps := after[0].BytesRecv - before[0].BytesRecv + + io <- newNetworkIOCounter(&after[0], bsps, brps) + e <- nil +} + +func buildInterfaces(result chan []networkInterface, e chan error) { + + var netInts []networkInterface + + nicStat, err := net.Interfaces() + if err != nil { + result <- netInts + e <- err + return + } + + before, err := net.IOCounters(true) + if err != nil { + result <- netInts + e <- err + return + } + + time.Sleep(time.Second) + + after, err := net.IOCounters(true) + if err != nil { + result <- netInts + e <- err + return + } + + for _, nic := range nicStat { + for i := range after { + if after[i].Name == nic.Name { + + netInts = append(netInts, newNetworkInterface(&nic, &before[i], &after[i])) + } + } + } + + result <- netInts + e <- nil +} + +// Network information +func Network(format bool) (NetworkStatFormat, error) { + e := make(chan error) + io := make(chan networkIOCounter) + netInts := make(chan []networkInterface) + + go buildTotalIOCounter(io, e) + go buildInterfaces(netInts, e) + + usage := <-io + nic := <-netInts + err := <-e + if err != nil { + return NetworkStatFormat{}, errors.Convert(err) + } + + ns := NetworkStat{usage, nic} + + if format { + return ns.Format(), nil + } + return ns.Text(), nil +} + +// Connections return all active connection +func Connections() ([]net.ConnectionStat, error) { + conns, err := net.Connections("all") + + return conns, errors.Convert(err) +} diff --git a/internal/pkg/info/process.go b/internal/pkg/info/process.go new file mode 100644 index 0000000..a4c0be3 --- /dev/null +++ b/internal/pkg/info/process.go @@ -0,0 +1,610 @@ +package info + +import ( + "encoding/json" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors" + "github.com/shirou/gopsutil/net" + "github.com/shirou/gopsutil/process" + "sync" + "time" +) + +// ProcessStat def +type ProcessStat struct { + Pid number `json:"pid"` + Name string `json:"name"` + Username string `json:"username"` + Status string `json:"status"` + Uids numberSlice `json:"uids"` + Gids numberSlice `json:"gids"` + Terminal string `json:"terminal"` + Cwd string `json:"cwd"` + Exe string `json:"exe"` + CmdArgs []string `json:"cmdArgs"` + Ppid number `json:"ppid"` + Parent ProcessLightStat `json:"parent"` + Children []ProcessLightStat `json:"children"` + CPU processCPUInfo `json:"cpu"` + Memory processMemInfo `json:"memory"` + Network networkIOCounter `json:"network"` + Disk processDiskInfo `json:"disk"` + Connections []net.ConnectionStat `json:"connections"` + NumFDS number `json:"numFds"` + OpenFiles []process.OpenFilesStat `json:"openFiles"` + NumThreads number `json:"numThread"` + Threads map[number]cpuTimes `json:"threads"` + Rlimits []processLimit `json:"limits"` + IsRunning bool `json:"isRunning"` + Background bool `json:"background"` + Foreground bool `json:"foreground"` + CreateTime systemtime `json:"createTime"` +} + +// ProcessStatFormat def +type ProcessStatFormat struct { + Pid string `json:"pid"` + Name string `json:"name"` + Username string `json:"username"` + Status string `json:"status"` + Uids []string `json:"uids"` + Gids []string `json:"gids"` + Terminal string `json:"terminal"` + Cwd string `json:"cwd"` + Exe string `json:"exe"` + CmdArgs []string `json:"cmdArgs"` + Ppid string `json:"ppid"` + Parent ProcessLightStatFormat `json:"parent"` + Children []ProcessLightStatFormat `json:"children"` + CPU processCPUInfoFormat `json:"cpu"` + Memory processMemInfoFormat `json:"memory"` + Network networkIOCounterFormat `json:"network"` + Disk processDiskInfoFormat `json:"disk"` + Connections []net.ConnectionStat `json:"connections"` + NumFDS string `json:"numFds"` + OpenFiles []process.OpenFilesStat `json:"openFiles"` + NumThreads string `json:"numThread"` + Threads map[string]cpuTimesFormat `json:"threads"` + Rlimits []processLimitFormat `json:"limits"` + IsRunning bool `json:"isRunning"` + Background bool `json:"background"` + Foreground bool `json:"foreground"` + CreateTime string `json:"createTime"` +} + +// Text conversion +func (p ProcessStat) Text() ProcessStatFormat { + pid := p.Pid.Text() + name := p.Name + username := p.Username + status := p.Status + uids := convertInfoSlice(p.Uids.Convert(), "text") + gids := convertInfoSlice(p.Gids.Convert(), "text") + term := p.Terminal + cwd := p.Cwd + exe := p.Exe + cmdArgs := p.CmdArgs + ppid := p.Ppid.Text() + parent := p.Parent.Text() + var children []ProcessLightStatFormat + for _, child := range p.Children { + children = append(children, child.Text()) + } + cpu := p.CPU.Text() + mem := p.Memory.Text() + net := p.Network.Text() + disk := p.Disk.Text() + conns := p.Connections + numFds := p.NumFDS.Text() + openFile := p.OpenFiles + numThread := p.NumThreads.Text() + var threads map[string]cpuTimesFormat + for key, th := range p.Threads { + threads[key.Text()] = th.Text() + } + var rlimits []processLimitFormat + for _, limit := range p.Rlimits { + rlimits = append(rlimits, limit.Text()) + } + isR := p.IsRunning + bck := p.Background + fgr := p.Foreground + ctime := p.CreateTime.Text() + + return ProcessStatFormat{pid, name, username, status, uids, gids, term, cwd, exe, cmdArgs, ppid, parent, children, cpu, mem, net, disk, conns, numFds, openFile, numThread, threads, rlimits, isR, bck, fgr, ctime} +} + +// Format conversion +func (p ProcessStat) Format() ProcessStatFormat { + pid := p.Pid.Format() + name := p.Name + username := p.Username + status := p.Status + uids := convertInfoSlice(p.Uids.Convert(), "format") + gids := convertInfoSlice(p.Gids.Convert(), "format") + term := p.Terminal + cwd := p.Cwd + exe := p.Exe + cmdArgs := p.CmdArgs + ppid := p.Ppid.Format() + parent := p.Parent.Format() + var children []ProcessLightStatFormat + for _, child := range p.Children { + children = append(children, child.Format()) + } + cpu := p.CPU.Format() + mem := p.Memory.Format() + net := p.Network.Format() + disk := p.Disk.Format() + conns := p.Connections + numFds := p.NumFDS.Format() + openFile := p.OpenFiles + numThread := p.NumThreads.Format() + var threads map[string]cpuTimesFormat + for key, th := range p.Threads { + threads[key.Format()] = th.Format() + } + var rlimits []processLimitFormat + for _, limit := range p.Rlimits { + rlimits = append(rlimits, limit.Format()) + } + isR := p.IsRunning + bck := p.Background + fgr := p.Foreground + ctime := p.CreateTime.Format() + + return ProcessStatFormat{pid, name, username, status, uids, gids, term, cwd, exe, cmdArgs, ppid, parent, children, cpu, mem, net, disk, conns, numFds, openFile, numThread, threads, rlimits, isR, bck, fgr, ctime} +} + +func (p ProcessStatFormat) String() string { + s, _ := json.Marshal(p) + return string(s) +} + +func newProcessStat(p *process.Process) ProcessStat { + pid := number(p.Pid) + name, _ := p.Name() + username, _ := p.Username() + status, _ := p.Status() + uidsRaw, _ := p.Uids() + uids := newNumberSlice32(uidsRaw) + gidsRaw, _ := p.Gids() + gids := newNumberSlice32(gidsRaw) + term, _ := p.Terminal() + cwd, _ := p.Cwd() + exe, _ := p.Exe() + cmdArgs, _ := p.CmdlineSlice() + ppidRaw, _ := p.Ppid() + ppid := number(ppidRaw) + parentRaw, _ := p.Parent() + parent := newProcessLightStat(parentRaw) + childrenRaw, _ := p.Children() + var children []ProcessLightStat + for _, proc := range childrenRaw { + children = append(children, newProcessLightStat(proc)) + } + cpuPer, _ := p.CPUPercent() + cpuTimeRaw, _ := p.Times() + cpuTime := newCPUTimes(cpuTimeRaw) + cpu := newProcessCPUInfo(cpuPer, cpuTime) + memPer, _ := p.MemoryPercent() + memInfoRaw, _ := p.MemoryInfo() + memInfo := newProcessMemUsage(memInfoRaw) + mem := newProcessMemInfo(memPer, memInfo) + e := make(chan error) + ionet := make(chan networkIOCounter) + iodisk := make(chan processDiskInfo) + go buildProcessNetInfo(p, ionet, e) + go buildProcessDiskInfo(p, iodisk, e) + net := <-ionet + disk := <-iodisk + conns, _ := p.Connections() + numFdsRaw, _ := p.NumFDs() + numFds := number(numFdsRaw) + openFiles, _ := p.OpenFiles() + numThreadsRaw, _ := p.NumThreads() + numThreads := number(numThreadsRaw) + threadsRaw, _ := p.Threads() + var threads map[number]cpuTimes + for key, th := range threadsRaw { + threads[number(key)] = newCPUTimes(th) + } + rlimitRaw, _ := p.Rlimit() + var rlimits []processLimit + for _, lim := range rlimitRaw { + rlimits = append(rlimits, newProcessLimit(&lim)) + } + isR, _ := p.IsRunning() + bck, _ := p.Background() + fgr, _ := p.Foreground() + ctimeRaw, _ := p.CreateTime() + ctime := systemtime(ctimeRaw) + + return ProcessStat{pid, name, username, status, uids, gids, term, cwd, exe, cmdArgs, ppid, parent, children, cpu, mem, net, disk, conns, numFds, openFiles, numThreads, threads, rlimits, isR, bck, fgr, ctime} +} + +func buildProcessNetInfo(p *process.Process, io chan networkIOCounter, e chan error) { + before, err := p.NetIOCounters(false) + if err != nil { + io <- networkIOCounter{} + e <- err + return + } + time.Sleep(time.Second) + after, err := p.NetIOCounters(false) + if err != nil { + io <- networkIOCounter{} + e <- err + return + } + + bsps := after[0].BytesSent - before[0].BytesSent + brps := after[0].BytesRecv - before[0].BytesRecv + + io <- newNetworkIOCounter(&after[0], bsps, brps) + e <- nil +} + +func buildProcessDiskInfo(p *process.Process, io chan processDiskInfo, e chan error) { + before, err := p.IOCounters() + if err != nil { + io <- processDiskInfo{} + e <- err + return + } + time.Sleep(time.Second) + after, err := p.IOCounters() + if err != nil { + io <- processDiskInfo{} + e <- err + return + } + + io <- newProcessDiskInfo(before, after) + e <- nil +} + +type processCPUInfo struct { + Percent percent `json:"percent"` + Times cpuTimes `json:"times"` +} + +type processCPUInfoFormat struct { + Percent string `json:"percent"` + Times cpuTimesFormat `json:"times"` +} + +func (p processCPUInfo) Text() processCPUInfoFormat { + per := p.Percent.Text() + times := p.Times.Text() + + return processCPUInfoFormat{per, times} +} + +func (p processCPUInfo) Format() processCPUInfoFormat { + per := p.Percent.Format() + times := p.Times.Format() + + return processCPUInfoFormat{per, times} +} + +func newProcessCPUInfo(perCPU float64, times cpuTimes) processCPUInfo { + per := percent(perCPU) + + return processCPUInfo{per, times} +} + +type processMemInfo struct { + Percent percent `json:"percent"` + Usage processMemUsage `json:"usage"` +} + +type processMemInfoFormat struct { + Percent string `json:"percent"` + Usage processMemUsageFormat `json:"usage"` +} + +func (p processMemInfo) Text() processMemInfoFormat { + per := p.Percent.Text() + usage := p.Usage.Text() + + return processMemInfoFormat{per, usage} +} + +func (p processMemInfo) Format() processMemInfoFormat { + per := p.Percent.Format() + usage := p.Usage.Format() + + return processMemInfoFormat{per, usage} +} + +func newProcessMemInfo(memPer float32, usage processMemUsage) processMemInfo { + per := percent(memPer) + + return processMemInfo{per, usage} +} + +type processMemUsage struct { + RSS byte `json:"rss"` + VMS byte `json:"vms"` + Data byte `json:"data"` + Stack byte `json:"stack"` + Locked byte `json:"locked"` + Swap byte `json:"swap"` +} + +type processMemUsageFormat struct { + RSS string `json:"rss"` + VMS string `json:"vms"` + Data string `json:"data"` + Stack string `json:"stack"` + Locked string `json:"locked"` + Swap string `json:"swap"` +} + +func (p processMemUsage) Text() processMemUsageFormat { + rss := p.RSS.Text() + vms := p.VMS.Text() + data := p.Data.Text() + stack := p.Stack.Text() + locked := p.Locked.Text() + swap := p.Swap.Text() + + return processMemUsageFormat{rss, vms, data, stack, locked, swap} +} +func (p processMemUsage) Format() processMemUsageFormat { + rss := p.RSS.Format() + vms := p.VMS.Format() + data := p.Data.Format() + stack := p.Stack.Format() + locked := p.Locked.Format() + swap := p.Swap.Format() + + return processMemUsageFormat{rss, vms, data, stack, locked, swap} +} + +func newProcessMemUsage(mem *process.MemoryInfoStat) processMemUsage { + if mem == nil { + return processMemUsage{} + } + rss := byte(mem.RSS) + vms := byte(mem.VMS) + data := byte(mem.Data) + stack := byte(mem.Stack) + locked := byte(mem.Locked) + swap := byte(mem.Swap) + + return processMemUsage{rss, vms, data, stack, locked, swap} +} + +type processDiskInfo struct { + ReadCount number `json:"readCount"` + WriteCount number `json:"writeCount"` + ReadBytes byte `json:"readBytes"` + WriteBytes byte `json:"writeBytes"` + ReadBytesPerSec byteSpeed `json:"readBytesPerSec"` + WriteBytesPerSec byteSpeed `json:"writeBytesPerSec"` +} + +type processDiskInfoFormat struct { + ReadCount string `json:"readCount"` + WriteCount string `json:"writeCount"` + ReadBytes string `json:"readBytes"` + WriteBytes string `json:"writeBytes"` + ReadBytesPerSec string `json:"readBytesPerSec"` + WriteBytesPerSec string `json:"writeBytesPerSec"` +} + +func (p processDiskInfo) Text() processDiskInfoFormat { + rc := p.ReadCount.Text() + wc := p.WriteCount.Text() + rb := p.ReadBytes.Text() + wb := p.WriteBytes.Text() + rcps := p.ReadBytesPerSec.Text() + wcps := p.WriteBytesPerSec.Text() + + return processDiskInfoFormat{rc, wc, rb, wb, rcps, wcps} +} + +func (p processDiskInfo) Format() processDiskInfoFormat { + rc := p.ReadCount.Format() + wc := p.WriteCount.Format() + rb := p.ReadBytes.Format() + wb := p.WriteBytes.Format() + rcps := p.ReadBytesPerSec.Format() + wcps := p.WriteBytesPerSec.Format() + + return processDiskInfoFormat{rc, wc, rb, wb, rcps, wcps} +} + +func newProcessDiskInfo(before *process.IOCountersStat, after *process.IOCountersStat) processDiskInfo { + rc := number(after.ReadCount) + wc := number(after.WriteCount) + rb := byte(after.ReadBytes) + wb := byte(after.WriteBytes) + rcps := byteSpeed(after.ReadBytes - before.ReadBytes) + wcps := byteSpeed(after.WriteBytes - before.WriteBytes) + + return processDiskInfo{rc, wc, rb, wb, rcps, wcps} +} + +type processLimit struct { + Resource number `json:"resource"` + Soft number `json:"soft"` + Hard number `json:"hard"` + Used number `json:"used"` +} + +type processLimitFormat struct { + Resource string `json:"resource"` + Soft string `json:"soft"` + Hard string `json:"hard"` + Used string `json:"used"` +} + +func (p processLimit) Text() processLimitFormat { + r := p.Resource.Text() + s := p.Soft.Text() + h := p.Hard.Text() + u := p.Used.Text() + + return processLimitFormat{r, s, h, u} +} + +func (p processLimit) Format() processLimitFormat { + r := p.Resource.Format() + s := p.Soft.Format() + h := p.Hard.Format() + u := p.Used.Format() + + return processLimitFormat{r, s, h, u} +} + +func newProcessLimit(p *process.RlimitStat) processLimit { + r := number(p.Resource) + s := number(p.Soft) + h := number(p.Hard) + u := number(p.Used) + + return processLimit{r, s, h, u} +} + +// ProcessLightStat def +type ProcessLightStat struct { + Pid number `json:"pid"` + Name string `json:"name"` + Username string `json:"username"` + Status string `json:"status"` + Uids numberSlice `json:"uids"` + Gids numberSlice `json:"gids"` + Terminal string `json:"terminal"` + Cwd string `json:"cwd"` + Exe string `json:"exe"` + CmdArgs []string `json:"cmdArgs"` + Ppid number `json:"ppid"` + CreateTime systemtime `json:"createTime"` +} + +// ProcessLightStatFormat def +type ProcessLightStatFormat struct { + Pid string `json:"pid"` + Name string `json:"name"` + Username string `json:"username"` + Status string `json:"status"` + Uids []string `json:"uids"` + Gids []string `json:"gids"` + Terminal string `json:"terminal"` + Cwd string `json:"cwd"` + Exe string `json:"exe"` + CmdArgs []string `json:"cmdArgs"` + Ppid string `json:"ppid"` + CreateTime string `json:"createTime"` +} + +// Text conversion +func (p ProcessLightStat) Text() ProcessLightStatFormat { + pid := p.Pid.Text() + name := p.Name + username := p.Username + status := p.Status + uids := convertInfoSlice(p.Uids.Convert(), "text") + gids := convertInfoSlice(p.Gids.Convert(), "text") + terminal := p.Terminal + cwd := p.Cwd + exe := p.Exe + cmdArgs := p.CmdArgs + ppid := p.Pid.Text() + createTime := p.CreateTime.Text() + + return ProcessLightStatFormat{pid, name, username, status, uids, gids, terminal, cwd, exe, cmdArgs, ppid, createTime} +} + +// Format return +func (p ProcessLightStat) Format() ProcessLightStatFormat { + pid := p.Pid.Format() + name := p.Name + username := p.Username + status := p.Status + uids := convertInfoSlice(p.Uids.Convert(), "format") + gids := convertInfoSlice(p.Gids.Convert(), "format") + terminal := p.Terminal + cwd := p.Cwd + exe := p.Exe + cmdArgs := p.CmdArgs + ppid := p.Pid.Format() + createTime := p.CreateTime.Format() + + return ProcessLightStatFormat{pid, name, username, status, uids, gids, terminal, cwd, exe, cmdArgs, ppid, createTime} +} + +func newProcessLightStat(p *process.Process) ProcessLightStat { + if p == nil { + return ProcessLightStat{} + } + + pid := number(p.Pid) + name, _ := p.Name() + username, _ := p.Username() + status, _ := p.Status() + u, _ := p.Uids() + uids := newNumberSlice32(u) + g, _ := p.Gids() + gids := newNumberSlice32(g) + terminal, _ := p.Terminal() + cwd, _ := p.Cwd() + exe, _ := p.Exe() + cmdArgs, _ := p.CmdlineSlice() + ppidRaw, _ := p.Ppid() + ppid := number(ppidRaw) + ctime, _ := p.CreateTime() + createTime := systemtime(ctime / 1000) + + return ProcessLightStat{pid, name, username, status, uids, gids, terminal, cwd, exe, cmdArgs, ppid, createTime} +} + +// Processes return all processes informations +func Processes(format bool) ([]ProcessLightStatFormat, error) { + processes, err := process.Processes() + if err != nil { + return nil, errors.Convert(err) + } + + var wg sync.WaitGroup + var processesFormat []ProcessLightStatFormat + for _, process := range processes { + wg.Add(1) + + go buildProcessStat(&wg, process, format, &processesFormat) + } + wg.Wait() + + return processesFormat, nil +} + +// Process return stat of one process +func Process(pid int32, format bool) (ProcessStatFormat, error) { + process, err := process.NewProcess(pid) + if err != nil { + return ProcessStatFormat{}, errors.Convert(err) + } + + stat := newProcessStat(process) + + if format { + return stat.Format(), nil + } + + return stat.Text(), nil +} + +func buildProcessStat(wg *sync.WaitGroup, p *process.Process, format bool, results *[]ProcessLightStatFormat) { + defer wg.Done() + + stat := newProcessLightStat(p) + + if format { + *results = append(*results, stat.Format()) + } else { + *results = append(*results, stat.Text()) + } + +} From a5f76724adf9333669090e2563bb48709f5a263a Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:11:40 +0200 Subject: [PATCH 5/9] :package: update main.go --- main.go | 76 +++------------------------------------------------------ 1 file changed, 3 insertions(+), 73 deletions(-) diff --git a/main.go b/main.go index 86a4e90..20a03f3 100644 --- a/main.go +++ b/main.go @@ -1,81 +1,11 @@ package main import ( - "net/http" - "os" - "strconv" - "strings" - - "github.com/boxmetrics/boxmetrics-agent/internal/pkg/boxagent" - "github.com/gorilla/websocket" - "github.com/sirupsen/logrus" + "github.com/boxmetrics/boxmetrics-agent/internal/pkg/agent" ) -var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, -} - func main() { - boxagent.InitConfig() - - http.HandleFunc("/ws/v1", func(w http.ResponseWriter, r *http.Request) { - conn, err := upgrader.Upgrade(w, r, nil) // error ignored for sake of simplicity - - if err != nil { - boxagent.Log.WithField("error", err).Error("websocket error") - } - - for { - // Read message from browser - msgType, msg, err := conn.ReadMessage() - if err != nil { - return - } - - // Log message - - logfields := logrus.Fields{"remote": conn.RemoteAddr(), "text": string(msg)} - boxagent.Log.WithFields(logfields).Info("receive") - - // Write message back to browser - if err = conn.WriteMessage(msgType, msg); err != nil { - return - } - } - }) - - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, "web/websocket.html") - }) - - var httpErr error - protocol := boxagent.Config.GetString("protocol") - host := boxagent.Config.GetString("host") - port := boxagent.Config.GetInt(strings.Join([]string{protocol, "_port"}, "")) - addr := strings.Join([]string{host, ":", strconv.Itoa(port)}, "") - url := strings.Join([]string{protocol, "://", addr}, "") - - logfields := logrus.Fields{"host": host, "port": port, "url": url} - boxagent.Log.WithFields(logfields).Info("server started") - - if protocol == "https" { - crt := boxagent.Config.GetString("ssl_crt") - key := boxagent.Config.GetString("ssl_key") - if _, err := os.Stat(crt); err != nil { - boxagent.Log.WithField("error", err).Fatal("could not find certificate file") - } - if _, err := os.Stat(key); err != nil { - boxagent.Log.WithField("error", err).Fatal("could not find key file") - } - httpErr = http.ListenAndServeTLS(addr, crt, key, nil) - - } else { - httpErr = http.ListenAndServe(addr, nil) - } - - if httpErr != nil { - boxagent.Log.WithField("error", httpErr).Fatal("listener fatal error") - } + agent.InitConfig() + agent.CreateServer() } From 2eef4eca47d3b05d71e953edd1db0f778e58e860 Mon Sep 17 00:00:00 2001 From: Laurent-PANEK Date: Sun, 16 Jun 2019 14:07:10 +0200 Subject: [PATCH 6/9] :rocket: change application ports --- Dockerfile | 2 +- README.md | 2 +- web/websocket.html | 42 +++++++++++++++++++++++++----------------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 11030c7..566ae8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,5 +6,5 @@ WORKDIR /app COPY . . RUN make test RUN make build -EXPOSE 8080 9090 +EXPOSE 4455 5544 CMD ["./bin/boxmetrics-agent"] \ No newline at end of file diff --git a/README.md b/README.md index bfd44f8..840cf78 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ The project might be working with older version of Go, if you add vendor directo 3. **Open browser and start editing files!** -> Project is running at or +> Project is running at or ## 🧐 What's inside ? diff --git a/web/websocket.html b/web/websocket.html index 4f52a2a..698b1b9 100644 --- a/web/websocket.html +++ b/web/websocket.html @@ -3,23 +3,31 @@

 
\ No newline at end of file
+  socket.onmessage = function(e) {
+    output.innerHTML += "Server: " + e.data + "\n";
+    console.log(e.data);
+  };
+  function send() {
+    socket.send(input.value);
+    // input.value = "";
+  }
+

From 7c31a8300873d7edfc8269fa71c81e1dbc9e9159 Mon Sep 17 00:00:00 2001
From: Laurent-PANEK 
Date: Sun, 16 Jun 2019 13:55:46 +0200
Subject: [PATCH 7/9] :white_check_mark: add test helper commands

---
 .gitignore                          |  1 +
 Makefile                            | 11 ++++++++-
 internal/pkg/errors/errrors_test.go | 38 +++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 internal/pkg/errors/errrors_test.go

diff --git a/.gitignore b/.gitignore
index dc56e76..c988374 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
 
 # Output of the go coverage tool, specifically when used with LiteIDE
 *.out
+coverage.html
 
 # Certificate files
 *.key
diff --git a/Makefile b/Makefile
index 9beed3a..47c7433 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: run test build clean cert rootca
+.PHONY: run test coverage build clean cert rootca
 
 run:
 	@echo "Starting module"
@@ -8,6 +8,15 @@ test:
 	@echo "Running module test"
 	go test -v ./...
 
+coverage:
+	@echo "Running coverage"
+	go test -v -cover ./...
+
+coverage-html:
+	@echo "Running coverage html"
+	go test -cover -coverprofile=c.out ./...
+	go tool cover -html=c.out -o coverage.html
+
 build:
 	@echo "Building module to ./bin"
 	mkdir -p bin
diff --git a/internal/pkg/errors/errrors_test.go b/internal/pkg/errors/errrors_test.go
new file mode 100644
index 0000000..83f0935
--- /dev/null
+++ b/internal/pkg/errors/errrors_test.go
@@ -0,0 +1,38 @@
+package errors_test
+
+import (
+	e "errors"
+	"github.com/boxmetrics/boxmetrics-agent/internal/pkg/errors"
+	"testing"
+)
+func TestNewEqual(t *testing.T) {
+	// Different allocations should not be equal.
+	if errors.New("abc") == errors.New("abc") {
+		t.Errorf(`New("abc") == New("abc")`)
+	}
+	if errors.New("abc") == errors.New("xyz") {
+		t.Errorf(`New("abc") == New("xyz")`)
+	}
+
+	// Same allocation should be equal to itself (not crash).
+	err := errors.New("jkl")
+	if err != err {
+		t.Errorf(`err != err`)
+	}
+}
+func TestConvertFunction(t *testing.T) {
+	errLegacy := e.New("abc")
+	
+	errConvert := errors.Convert(errLegacy)
+	
+	if errLegacy.Error() != errConvert.Error() {
+		t.Errorf(`Convert error = %q, want %q`, errConvert.Error(), errLegacy.Error())
+	}
+}
+
+func TestErrorMethod(t *testing.T) {
+	err := errors.New("abc")
+	if err.Error() != "abc" {
+		t.Errorf(`New("abc").Error() = %q, want %q`, err.Error(), "abc")
+	}
+}
\ No newline at end of file

From 828c5b23803c2fd6b3c5f151b74963ace8f40fa3 Mon Sep 17 00:00:00 2001
From: Laurent-PANEK 
Date: Sun, 16 Jun 2019 13:56:17 +0200
Subject: [PATCH 8/9] :fire: removed unused directory

---
 deployments/.gitkeep | 0
 pkg/.gitkeep         | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 deployments/.gitkeep
 delete mode 100644 pkg/.gitkeep

diff --git a/deployments/.gitkeep b/deployments/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/pkg/.gitkeep b/pkg/.gitkeep
deleted file mode 100644
index e69de29..0000000

From 202e3648dcb9c249c1e065c790466abe7a2b8abb Mon Sep 17 00:00:00 2001
From: Laurent-PANEK 
Date: Sun, 16 Jun 2019 13:52:54 +0200
Subject: [PATCH 9/9] :pencil: add usage documentation

---
 README.md                | 167 +++++++++++++++++++++++++++++++++------
 docs/schema/container.md |  59 ++++++++++++++
 docs/schema/cpu.md       |  57 +++++++++++++
 docs/schema/disk.md      |  46 +++++++++++
 docs/schema/general.md   |  13 +++
 docs/schema/host.md      |  35 ++++++++
 docs/schema/memory.md    |  11 +++
 docs/schema/network.md   |  50 ++++++++++++
 docs/schema/process.md   | 102 ++++++++++++++++++++++++
 9 files changed, 514 insertions(+), 26 deletions(-)
 create mode 100644 docs/schema/container.md
 create mode 100644 docs/schema/cpu.md
 create mode 100644 docs/schema/disk.md
 create mode 100644 docs/schema/general.md
 create mode 100644 docs/schema/host.md
 create mode 100644 docs/schema/memory.md
 create mode 100644 docs/schema/network.md
 create mode 100644 docs/schema/process.md

diff --git a/README.md b/README.md
index 840cf78..7dd8d89 100644
--- a/README.md
+++ b/README.md
@@ -4,49 +4,165 @@
 
 ## 📦 Requirements
 
-> Only if you want to run the source code
+> Not needed if you run from a prebuilt binary
 
 This project should be working as expected with the following minimal version of:
 
 | Dependency | Version  |
-| ---------- | :------: |
-| Go         | >= v1.11 |
-
-The project might be working with older version of Go, if you add vendor directory with `go mod vendor` command _(available from Go 1.11)_. Since this repo is based on go modules dependencies, the vendor directory won't be add, it's your own choice if you want it.
+| ---------- | -------- |
+| Go         | >= v1.12 |
 
 ## 🚀 Quick start
 
+### _From prebuilt binaries :_
+
+1. **Donwload a binary from Github [release page](https://github.com/boxmetrics/boxmetrics-agent/releases)**
+
+2. **Run application**
+
+```bash
+# Made application executable
+sudo chmod +x boxmetrics-agent
+
+# Start application
+./boxmetrics-agent
+```
+
+### _From source code :_
+
 1. **Clone the git repository**
 
-   ```bash
-   # cloning git repository
-   git clone https://github.com/boxmetrics/boxmetrics-agent
+```bash
+# cloning git repository
+git clone https://github.com/boxmetrics/boxmetrics-agent
+```
 
-   cd boxmetrics-agent
-   ```
+2. **Build application**
 
-2. **Run application**
+```bash
+# go to boxmetrics-agent directory
+cd boxmetrics-agent
+# run helper command to build
+make build
+```
+
+3. **Run application**
+
+```bash
+# Made application executable
+sudo chmod +x bin/boxmetrics-agent
+
+# Start application
+./bin/boxmetrics-agent
+```
+
+## 💡 Usage
+
+### Routes
+
+| Path     | Description    |
+| -------- | -------------- |
+| `/ws/v1` | Websocket root |
+| `/`      | Test page      |
+
+### Communication
+
+Both request and response are JSON message
 
-   **Dev Version**
+#### Request
 
-   ```bash
-   # start the app
-   make run
-   ```
+| Key     | Type    | Require | Default                | Description      |
+| ------- | ------- | ------- | ---------------------- | ---------------- |
+| type    | string  | yes     | NA                     | Request type     |
+| value   | string  | yes     | NA                     | Type value       |
+| options | object  | no      | Default Options Object | Request options  |
+| format  | boolean | no      | true                   | Enable formating |
 
-   **Prod Version**
+##### Type Values
 
-   ```bash
-   # build the app
-   make build
-   # run executable
-   ./bin/boxmetrics-agent
-   ```
+| Value   | Description                                                    |
+| ------- | -------------------------------------------------------------- |
+| info    | Return `value` information type                                |
+| script  | Run `value` script                                             |
+| command | Execute `value` as command _(Use `options` to add parameters)_ |
 
-3. **Open browser and start editing files!**
+##### Info Type Values
+
+| Value        | Response                                       | Description                                                   |
+| ------------ | ---------------------------------------------- | ------------------------------------------------------------- |
+| memory       | [Schema](docs/schema/memory.md#memory)         | Return memory information                                     |
+| cpu          | [Schema](docs/schema/cpu.md#cpu)               | Return cpu usage information                                  |
+| cpuinfo      | [Schema](docs/schema/cpu.md#cpu-hardware-info) | Return cpu hardware information                               |
+| disks        | [Schema](docs/schema/disk.md#disk)             | Return disks information                                      |
+| containers   | [Schema](docs/schema/container.md#container)   | Return containers full information                            |
+| containersid | Array of string                                | Return containers ID list                                     |
+| host         | [Schema](docs/schema/host.md#host)             | Return host information                                       |
+| users        | [Schema](docs/schema/host.md#users)            | Return users list                                             |
+| network      | [Schema](docs/schema/network.md#network)       | Return network information                                    |
+| connections  | [Schema](docs/schema/network.md#connection)    | Return opened connections list                                |
+| processes    | [Schema](docs/schema/process.md#process-light) | Return processes information list                             |
+| process      | [Schema](docs/schema/process.md#process)       | Return process full information _(`options.pid` must be set)_ |
+| general      | [Schema](docs/schema/general.md)               | Return system wide informations                               |
+
+##### Script Type Values
+
+No script available yet
+
+##### Options Object
+
+| Key  | Type   | Require | Default | Description                                                                    |
+| ---- | ------ | ------- | ------- | ------------------------------------------------------------------------------ |
+| args | Array  | no      | null    | Array of arguments to pass to the command                                      |
+| env  | Array  | no      | null    | Array of environment variable to add before executing command _eg. MY_VAR=abc_ |
+| pwd  | string | no      | ""      | Location where the command run, if empty string run in the cwd of the process  |
+| pid  | number | no      | 0       | PID use to retrieve information with `process` info type                       |
+
+#### Response
+
+| Key       | Type   | Description                                                                       |
+| --------- | ------ | --------------------------------------------------------------------------------- |
+| event     | object | The event send                                                                    |
+| data      | object | The data reponse of the event. Corresponding to a specific [schema](docs/schema/) |
+| startDate | string | Start date of the response processing                                             |
+| endDate   | string | End date of the response processing                                               |
+| duration  | string | Duration of the response processing                                               |
+| status    | object | Status of the response                                                            |
+| error     | string | Error message _(`null` if no error)_                                              |
+
+##### Status object
+
+| Key     | Type   | Description    |
+| ------- | ------ | -------------- |
+| code    | number | Status code    |
+| message | string | Status message |
+
+## 💬 Contributing
+
+1. **Fork the git repository**
+
+2. **Create your feature branch**
+
+3. **Apply your changes**
+
+4. **Run application**
+
+```bash
+# run test
+make test
+# start application in dev mode
+make run
+```
+
+5. **Open browser to test your change!**
 
 > Project is running at  or 
 
+6. **Commit your changes**
+
+7. **Push it on your fork**
+
+8. **Create new pull request**
+
 ## 🧐 What's inside ?
 
 ```text
@@ -56,16 +172,15 @@ The project might be working with older version of Go, if you add vendor directo
 ├── certificates    # Project Certificates
 ├── cmd             # Main applications for this project
 ├── configs         # Configuration file templates or default configs
-├── deployments     # Deployment configurations and templates (docker-compose, kubernetes/helm)
 ├── docs            # Design and user documents
 ├── init            # System init and process manager/supervisor configs
 ├── internal
 │   ├── app         # Private application
 │   └── pkg         # Private library code
-├── pkg             # Public library code
 ├── scripts         # Scripts to perform various build, install, analysis, etc operations
 ├── test            # Additional external test apps and test data
 ├── web             # Web application specific components
+├── Dockerfile      # Docker image
 ├── go.mod          # Module dependencies
 ├── go.sum          # Ensure dependencies integrity
 ├── JenkinsFile     # Jenkins pipeline
diff --git a/docs/schema/container.md b/docs/schema/container.md
new file mode 100644
index 0000000..4b844cc
--- /dev/null
+++ b/docs/schema/container.md
@@ -0,0 +1,59 @@
+# Response Schema for Container informations
+
+## Container
+
+| Key         | Type    | Description                                                           |
+| ----------- | ------- | --------------------------------------------------------------------- |
+| containerId | string  | Container indentifier                                                 |
+| name        | string  | Container string                                                      |
+| image       | string  | Container image                                                       |
+| status      | string  | Container status                                                      |
+| running     | boolean | True when up, false otherwise                                         |
+| cpu         | object  | Container cpu usage, see [container cpu stat](#container-cpu-stat)    |
+| memory      | object  | Container memory usage, see [container mem stat](#container-mem-stat) |
+
+### Container CPU Stat
+
+| Key     | Type   | Description                             |
+| ------- | ------ | --------------------------------------- |
+| percent | string | Container CPU usage in %                |
+| times   | object | A [cpu time](./cpu.md#cpu-times) object |
+
+### Container Mem Stat
+
+| Key                     | Type   | Description                                |
+| ----------------------- | ------ | ------------------------------------------ |
+| containerId             | string | Container identifier                       |
+| cache                   | string | Cache used                                 |
+| rss                     | string | Number of rss                              |
+| rssHuge                 | string | Number of rss huge                         |
+| mappedFile              | string | Number of mapped file                      |
+| pgpgin                  | string | Number of page-ins                         |
+| pgpgout                 | string | Number of page-outs                        |
+| pgfault                 | string | Number of page faults                      |
+| pgmajfault              | string | Number of major page faults                |
+| inactiveAnon            | string | Number of inactive anonymous memory        |
+| activeAnon              | string | Number of active anonymous memory          |
+| inactiveFile            | string | Number of inactive cache memory file       |
+| activeFile              | string | Number of active cache memory file         |
+| unevictable             | string | Amount of memory that cannot be reclaimed  |
+| hierarchicalMemoryLimit | string | Maximum RAM available in the host          |
+| totalCache              | string | Total of cache                             |
+| totalRss                | string | Total of rss                               |
+| totalRssHuge            | string | Total of rss huge                          |
+| totalMappedFile         | string | Total of mapped file                       |
+| totalPgpgin             | string | Total of page-ins                          |
+| totalPgpgout            | string | Total of page-outs                         |
+| totalPgfault            | string | Total of page faults                       |
+| totalPgmajfault         | string | Total of major page faults                 |
+| totalInactiveAnon       | string | Total of inactive anonymous memory         |
+| totalActiveAnon         | string | Total of active anonymous memory           |
+| totalInactiveFile       | string | Total of inactive cache memory file        |
+| totalActiveFile         | string | Total of active cache memory file          |
+| totalUnevictable        | string | Total of unevictable memory                |
+| memUsage                | string | Amount of memory used                      |
+| memMaxUsage             | string | Amount of maximun memory usable            |
+| memoryLimit             | string | Amount of physical memory that can be used |
+| memoryFailcnt           | string | Amount of overload memory                  |
+
+More info on [docker docs](https://docs.docker.com/v17.09/engine/admin/runmetrics/#metrics-from-cgroups-memory-cpu-block-io)
diff --git a/docs/schema/cpu.md b/docs/schema/cpu.md
new file mode 100644
index 0000000..596340b
--- /dev/null
+++ b/docs/schema/cpu.md
@@ -0,0 +1,57 @@
+# Response Schema for CPU informations
+
+## CPU
+
+| Key   | Type   | Description                                      |
+| ----- | ------ | ------------------------------------------------ |
+| count | object | Number of processor. See [cpu count](#cpu-count) |
+| info  | Array  | Array of [cpu info](#cpu-info)                   |
+
+### CPU Count
+
+| Key      | Type   | Description                  |
+| -------- | ------ | ---------------------------- |
+| physical | string | Number of physical processor |
+| logical  | string | Number of logical processor  |
+
+### CPU Info
+
+| Key     | Type   | Description                      |
+| ------- | ------ | -------------------------------- |
+| id      | string | A CPU ID                         |
+| percent | string | Usage of the CPU in %            |
+| times   | object | A [cpu times](#cpu-times) object |
+
+### CPU Times
+
+| Key       | Type   | Description                            |
+| --------- | ------ | -------------------------------------- |
+| user      | string | Amounts of time of the user work       |
+| system    | string | Amounts of time of the system work     |
+| idle      | string | Amounts of time of the idle work       |
+| nide      | string | Amounts of time of the nice work       |
+| iowait    | string | Amounts of time of the iowait work     |
+| irq       | string | Amounts of time of the irq work        |
+| softirq   | string | Amounts of time of the softirq work    |
+| steal     | string | Amounts of time of the steal work      |
+| guest     | string | Amounts of time of the guest work      |
+| guestNice | string | Amounts of time of the guest nice work |
+| total     | string | Total of time for all kinds of work    |
+
+## CPU Hardware Info
+
+| Key        | Type   | Description              |
+| ---------- | ------ | ------------------------ |
+| cpu        | number | CPU Identifier           |
+| vendorId   | string | Vendor Identifier        |
+| family     | string | Family of the CPU        |
+| model      | string | Model name               |
+| stepping   | number | ???                      |
+| physicalId | string | Hardware Identifier      |
+| coreId     | string | Something about core     |
+| cores      | number | Number of cores          |
+| modelName  | string | Another model name       |
+| mhz        | number | CPU frequency            |
+| cacheSize  | number | Cache size               |
+| flags      | Array  | Flags support by the CPU |
+| microcode  | string | Microcode info           |
diff --git a/docs/schema/disk.md b/docs/schema/disk.md
new file mode 100644
index 0000000..1b8a762
--- /dev/null
+++ b/docs/schema/disk.md
@@ -0,0 +1,46 @@
+# Response Schema for Disk informations
+
+## Disk
+
+| Key        | Type   | Description                       |
+| ---------- | ------ | --------------------------------- |
+| device     | string | Disk name                         |
+| mountpoint | string | Disk mountpoint                   |
+| fstype     | string | File system type                  |
+| opts       | string | Disk options                      |
+| usage      | object | [Disk usage](#disk-usage)         |
+| iocounters | object | [Disk io counter](#disk-counters) |
+
+### Disk Usage
+
+| Key               | Type   | Description                   |
+| ----------------- | ------ | ----------------------------- |
+| path              | string | Disk path                     |
+| fstype            | string | Disk file system type         |
+| total             | string | Disk total size               |
+| free              | string | Disk free space               |
+| used              | string | Disk used space               |
+| usedPercent       | string | Percentage of disk space used |
+| inodesTotal       | string | Total number of inodes        |
+| inodesUsed        | string | Number of inodes used         |
+| inodesFree        | string | Number of inodes free         |
+| inodesUsedPercent | string | Percentage of inodes used     |
+
+### Disk Counters
+
+| Key              | Type   | Description                         |
+| ---------------- | ------ | ----------------------------------- |
+| readCount        | string | Number of read count                |
+| mergedReadCount  | string | Number of merge read count          |
+| writeCount       | string | Number of write count               |
+| mergedWriteCount | string | Number of merged write count        |
+| readBytes        | string | Number of read bytes                |
+| writeBytes       | string | Number of write bytes               |
+| readTime         | string | Total of time used to read          |
+| writeTime        | string | Total of time used to write         |
+| iopsInProgress   | string | Number of IO per second in progress |
+| ioTime           | string | Total of time used for IO           |
+| weightedIO       | string | Number of weighted IO               |
+| name             | string | Disk name                           |
+| serialnumber     | string | Disk serialnumber                   |
+| label            | string | Disk label                          |
diff --git a/docs/schema/general.md b/docs/schema/general.md
new file mode 100644
index 0000000..bc3c0e7
--- /dev/null
+++ b/docs/schema/general.md
@@ -0,0 +1,13 @@
+# Response Schema for General informations
+
+## General
+
+| Key        | Type   | Description                                                                   |
+| ---------- | ------ | ----------------------------------------------------------------------------- |
+| cpu        | object | CPU information. See [cpu](./cpu.md#cpu)                                      |
+| disks      | Array  | Array of disks information. See [disk](./disk.md#disk)                        |
+| containers | Array  | Array of container information. See [container](./container.md#container)     |
+| host       | object | Host information. See [host](./host.md#host)                                  |
+| memory     | object | Memory information. See [memory](./memory.md#memory)                          |
+| network    | object | Network information. See [network](./network.md#network)                      |
+| processes  | Array  | Array of process information. See [process light](./process.md#process-light) |
diff --git a/docs/schema/host.md b/docs/schema/host.md
new file mode 100644
index 0000000..9a3e596
--- /dev/null
+++ b/docs/schema/host.md
@@ -0,0 +1,35 @@
+# Response Schema for Host informations
+
+## Host
+
+| Key                  | Type   | Description                              |
+| -------------------- | ------ | ---------------------------------------- |
+| hostname             | string | System hostname                          |
+| uptime               | string | System uptime                            |
+| bootTime             | string | System boot date                         |
+| procs                | string | Number of processes                      |
+| os                   | string | Os type (ex: "linux")                    |
+| platform             | string | Platform name (ex: "ubuntu", "arch")     |
+| platformFamily       | string | Platform family (ex: "debian")           |
+| platformVersion      | string | Platform version (ex: "Ubuntu 13.10")    |
+| kernerlVersion       | string | Kernel version number                    |
+| virtualizationSystem | string | Virtualization system (ex: "LXC")        |
+| virtualizationRole   | string | Virtualization role (ex: "guest"/"host") |
+| hostId               | string | Host identifier                          |
+| sensors              | object | Array of [sensor stat](#sensor-stat)     |
+
+### Sensor Stat
+
+| Key         | Type   | Description        |
+| ----------- | ------ | ------------------ |
+| sensorKey   | string | Sensor identifier  |
+| temperature | string | Sensor temperature |
+
+## Users
+
+| Key      | Type   | Description               |
+| -------- | ------ | ------------------------- |
+| user     | string | User name                 |
+| terminal | string | User default terminal     |
+| host     | string | User host                 |
+| started  | int    | Number of session started |
diff --git a/docs/schema/memory.md b/docs/schema/memory.md
new file mode 100644
index 0000000..3798f25
--- /dev/null
+++ b/docs/schema/memory.md
@@ -0,0 +1,11 @@
+# Response Schema for Memory informations
+
+## Memory
+
+| Key         | Type   | Description            |
+| ----------- | ------ | ---------------------- |
+| total       | string | Total memory           |
+| available   | string | Available memory       |
+| used        | string | Used memory            |
+| usedPercent | string | Percent of used memory |
+| free        | string | Free memory            |
diff --git a/docs/schema/network.md b/docs/schema/network.md
new file mode 100644
index 0000000..6cafbb4
--- /dev/null
+++ b/docs/schema/network.md
@@ -0,0 +1,50 @@
+# Response Schema for Network informations
+
+## Network
+
+| Key        | Type   | Description                                                         |
+| ---------- | ------ | ------------------------------------------------------------------- |
+| usage      | object | Global network usage. See [network IO counter](#network-io-counter) |
+| interfaces | Array  | Array of [network interface](#network-interfaces)                   |
+
+### Network Interfaces
+
+| Key          | Type   | Description                                                    |
+| ------------ | ------ | -------------------------------------------------------------- |
+| mtu          | string | Interface MTU                                                  |
+| name         | string | Interface name                                                 |
+| hardwareaddr | string | Interface MAC address                                          |
+| flags        | array  | Interface flags                                                |
+| addrs        | array  | Interface IP addresses                                         |
+| usage        | object | Interface usage. See [network IO counter](#network-io-counter) |
+
+### Network IO Counters
+
+| Key             | Type   | Description                        |
+| --------------- | ------ | ---------------------------------- |
+| name            | string | Interface name                     |
+| bytesSent       | string | Number of bytes sent               |
+| bytesRecv       | string | Number of bytes receive            |
+| bytesSentPerSec | string | Number of bytes sent per second    |
+| bytesRecvPerSec | string | Number of bytes receive per second |
+| packetsSent     | string | Number of packets sent             |
+| packetsRecv     | string | Number of packets receive          |
+| errin           | string | Number of input error              |
+| errout          | string | Number of output error             |
+| dropin          | string | Number of intput drop              |
+| dropout         | string | Number of output drop              |
+| fifoin          | string | Number of input fifo               |
+| fifoout         | string | Number of output fifo              |
+
+## Connection
+
+| Key        | Type   | Description        |
+| ---------- | ------ | ------------------ |
+| fd         | number | File descriptor Id |
+| family     | string | Connection family  |
+| type       | string | Connection type    |
+| localaddr  | string | Local address      |
+| remoteaddr | string | Remote address     |
+| status     | string | Connection status  |
+| uids       | Array  | Connection UIDs    |
+| pid        | number | Connection PID     |
diff --git a/docs/schema/process.md b/docs/schema/process.md
new file mode 100644
index 0000000..4b41d7f
--- /dev/null
+++ b/docs/schema/process.md
@@ -0,0 +1,102 @@
+# Response Schema for Process informations
+
+## Process
+
+| Key         | Type    | Description                                                            |
+| ----------- | ------- | ---------------------------------------------------------------------- |
+| pid         | string  | Process PID                                                            |
+| name        | string  | Process name                                                           |
+| username    | string  | Process user name                                                      |
+| status      | string  | Process status                                                         |
+| uids        | Array   | Process UIDs                                                           |
+| gids        | Array   | Process GIDs                                                           |
+| terminal    | string  | Process associated terminal                                            |
+| cwd         | string  | Process current working directory                                      |
+| exe         | string  | Process executable path                                                |
+| cmdArgs     | Array   | Process command line arguments                                         |
+| ppid        | string  | Process parent PID                                                     |
+| parent      | string  | Process parent info. See [process light](#process-light)               |
+| children    | Array   | Process children. See [process light](#process-light)                  |
+| cpu         | object  | [Process cpu usage](#process-cpu-info)                                 |
+| memory      | object  | [Process memory usage](#process-memory-info)                           |
+| network     | object  | [Process network usage](./network.md#network-io-counter)               |
+| disk        | object  | [Process disk usage](#process-disk-info)                               |
+| connections | Array   | Process connections. See [network connection](./network.md#connection) |
+| numFds      | string  | Number of file descriptor                                              |
+| openFiles   | Array   | Process opened files . See [process file](#process-file)               |
+| numThread   | string  | Number of threads                                                      |
+| threads     | Array   | Process threads. See [cpu times](./cpu.md#cpu-times)                   |
+| limits      | Array   | Process limits. See [process limit](#process-limit)                    |
+| isRunning   | boolean | If process is running                                                  |
+| background  | boolean | If process is in background                                            |
+| foreground  | boolean | If process is in foreground                                            |
+| createTime  | string  | Process create time                                                    |
+
+### Process CPU Info
+
+| Key     | Type   | Description                            |
+| ------- | ------ | -------------------------------------- |
+| percent | srting | Percentage of CPU used                 |
+| times   | object | [cpu times](./cpu.md#cpu-times) object |
+
+### Process Memory Info
+
+| Key     | Type   | Description                                          |
+| ------- | ------ | ---------------------------------------------------- |
+| percent | string | Percentage of memory used                            |
+| usage   | object | [Process Memory Usage](#process-memory-usage) object |
+
+### Process Memory Usage
+
+| Key    | Type   | Description        |
+| ------ | ------ | ------------------ |
+| rss    | string | RSS memory used    |
+| vms    | string | VMS memory used    |
+| data   | string | Data memory used   |
+| stack  | string | Stack memory used  |
+| locked | string | Locked memory used |
+| swap   | string | Swap memory used   |
+
+### Process Disk Info
+
+| Key              | Type   | Description                      |
+| ---------------- | ------ | -------------------------------- |
+| readCount        | string | Number of read                   |
+| writeCount       | string | Number of write                  |
+| readBytes        | string | Number of bytes read             |
+| writeBytes       | string | Number of bytes write            |
+| readBytesPerSec  | string | Number of bytes read per second  |
+| writeBytesPerSec | string | Number of bytes write per second |
+
+### Process File
+
+| Key  | Type   | Description                |
+| ---- | ------ | -------------------------- |
+| path | string | Path of the file           |
+| fd   | number | File descriptor identifier |
+
+### Process Limit
+
+| Key      | Type   | Description   |
+| -------- | ------ | ------------- |
+| resource | string | Resource name |
+| soft     | string | Soft limit    |
+| hard     | string | Hard limit    |
+| used     | string | Resource used |
+
+## Process Light
+
+| Key        | Type   | Description                       |
+| ---------- | ------ | --------------------------------- |
+| pid        | string | Process PID                       |
+| name       | string | Process name                      |
+| username   | string | Process user name                 |
+| status     | string | Process status                    |
+| uids       | Array  | Process UIDs                      |
+| gids       | Array  | Process GIDs                      |
+| terminal   | string | Process associated terminal       |
+| cwd        | string | Process current working directory |
+| exe        | string | Process executable path           |
+| cmdArgs    | Array  | Process command line arguments    |
+| ppid       | string | Process parent PID                |
+| createTime | string | Process create time               |