watchdog-go #2
|
@ -13,6 +13,6 @@ tasks:
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
cmds:
|
cmds:
|
||||||
- protoc -I ../unos-proto/src/main/proto --go_out=. ../unos-proto/src/main/proto/watchdog/push_metrics.proto --go_opt=module=$prefix --go-grpc_out=.
|
- protoc -I ../unos-proto/src/main/proto --go_out=. ../unos-proto/src/main/proto/watchdog/push_metrics.proto --go_opt=module=git.usbharu.dev/usbharu/unos --go-grpc_opt=module=git.usbharu.dev/usbharu/unos --go-grpc_out=.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/stretchr/testify v1.9.0 // indirect
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||||
|
|
|
@ -3,6 +3,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
@ -11,10 +13,14 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
|
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
|
||||||
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
|
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
|
@ -39,6 +45,7 @@ golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
|
|
@ -1,95 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"git.usbharu.dev/usbharu/unos/watchdog-go/watchdog"
|
||||||
"fmt"
|
|
||||||
"git.usbharu.dev/usbharu/unos/watchdog-go/git.usbharu.dev/usbharu/unos/watchdog"
|
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
"gopkg.in/ini.v1"
|
|
||||||
"log"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Url string
|
|
||||||
ClientName string
|
|
||||||
ClientDomain string
|
|
||||||
}
|
|
||||||
|
|
||||||
var regex = regexp.MustCompile(`[^a-zA-Z0-9-_]`)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("start gRPC Client.")
|
watchdog.Run()
|
||||||
|
|
||||||
load, err := ini.Load("config.ini")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
config := Config{
|
|
||||||
Url: load.Section("Parent").Key("url").String(),
|
|
||||||
ClientName: load.Section("Watch").Key("name").MustString("Watch Dog Go"),
|
|
||||||
ClientDomain: load.Section("Watch").Key("domain").MustString("watchdog.internal"),
|
|
||||||
}
|
|
||||||
|
|
||||||
dial, err := grpc.Dial(config.Url, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics := make(chan watchdog.Metric)
|
|
||||||
|
|
||||||
client := watchdog.NewPushMetricsServiceClient(dial)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
metricArray := getMetrics(config)
|
|
||||||
for _, metric := range metricArray {
|
|
||||||
metrics <- metric
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Minute)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for metric := range metrics {
|
|
||||||
_, err := client.Push(context.Background(), &metric)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMetrics(config Config) []watchdog.Metric {
|
|
||||||
v, _ := mem.VirtualMemory()
|
|
||||||
|
|
||||||
return []watchdog.Metric{usedMemory(*v, config)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func usedMemory(stat mem.VirtualMemoryStat, config Config) watchdog.Metric {
|
|
||||||
name := config.ClientName + " Used Memory"
|
|
||||||
usedMemory := fmt.Sprintf("%g", stat.UsedPercent)
|
|
||||||
|
|
||||||
log.Printf("Mem: %s%%\n", usedMemory)
|
|
||||||
|
|
||||||
return watchdog.Metric{
|
|
||||||
Name: name,
|
|
||||||
ObjectId: toId(name),
|
|
||||||
Domain: config.ClientDomain,
|
|
||||||
Status: watchdog.Status_OK,
|
|
||||||
Value: usedMemory,
|
|
||||||
Timestamp: timestamppb.Now(),
|
|
||||||
Message: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toId(value string) string {
|
|
||||||
return regex.ReplaceAllString(strings.ReplaceAll(value, " ", "-"), "")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Url string
|
||||||
|
ClientName string
|
||||||
|
ClientDomain string
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UsedCPU struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUsedCpu(config Config) MetricsCollector {
|
||||||
|
return &UsedCPU{
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsedCPU) Collect() (*Metric, error) {
|
||||||
|
coreCounts, err := cpu.Counts(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
threadCounts, err := cpu.Counts(true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name := u.config.ClientName + " Used CPU"
|
||||||
|
percent, err := cpu.Percent(100+time.Millisecond, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
usedCpu := fmt.Sprintf("%g", percent[0])
|
||||||
|
|
||||||
|
cpuCore := fmt.Sprintf("%d Core %d Thread", coreCounts, threadCounts)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: u.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: usedCpu,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: cpuCore,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsedCPU) Timer() time.Duration {
|
||||||
|
return 1 * time.Minute
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UsedDisk struct {
|
||||||
|
config Config
|
||||||
|
partitionStat disk.PartitionStat
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUsedDisk(config Config, stat disk.PartitionStat) MetricsCollector {
|
||||||
|
return &UsedDisk{
|
||||||
|
config: config,
|
||||||
|
partitionStat: stat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsedDisk) Collect() (*Metric, error) {
|
||||||
|
usage, err := disk.Usage(u.partitionStat.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := u.config.ClientName + " Used Disk " + u.partitionStat.Device
|
||||||
|
usedDisk := fmt.Sprintf("%g", usage.UsedPercent)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: u.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: usedDisk,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsedDisk) Timer() time.Duration {
|
||||||
|
return 1 * time.Hour
|
||||||
|
}
|
||||||
|
|
||||||
|
type TotalDisk struct {
|
||||||
|
Config
|
||||||
|
disk.PartitionStat
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTotalDisk(config Config, stat disk.PartitionStat) MetricsCollector {
|
||||||
|
return &TotalDisk{
|
||||||
|
Config: config,
|
||||||
|
PartitionStat: stat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalDisk) Collect() (*Metric, error) {
|
||||||
|
usage, err := disk.Usage(t.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := t.ClientName + " Total Disk " + t.Device
|
||||||
|
|
||||||
|
totalDisk := fmt.Sprintf("%d", usage.Total)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: t.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: totalDisk,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalDisk) Timer() time.Duration {
|
||||||
|
return 24 * time.Hour
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UsedMemory struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUsedMemory(config Config) MetricsCollector {
|
||||||
|
return &UsedMemory{
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m UsedMemory) Collect() (*Metric, error) {
|
||||||
|
memory, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name := m.config.ClientName + " Used Memory"
|
||||||
|
usedMemory := fmt.Sprintf("%g", memory.UsedPercent)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: m.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: usedMemory,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m UsedMemory) Timer() time.Duration {
|
||||||
|
return 1 * time.Minute
|
||||||
|
}
|
||||||
|
|
||||||
|
type UsedSwap struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUsedSwap(config Config) MetricsCollector {
|
||||||
|
return &UsedSwap{
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m UsedSwap) Collect() (*Metric, error) {
|
||||||
|
memory, err := mem.SwapMemory()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name := m.config.ClientName + " Used Swap"
|
||||||
|
usedMemory := fmt.Sprintf("%g", memory.UsedPercent)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: m.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: usedMemory,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m UsedSwap) Timer() time.Duration {
|
||||||
|
return 1 * time.Minute
|
||||||
|
}
|
||||||
|
|
||||||
|
type TotalMemory struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTotalMemory(config Config) MetricsCollector {
|
||||||
|
return &TotalMemory{config: config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalMemory) Collect() (*Metric, error) {
|
||||||
|
memory, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
name := t.config.ClientName + " Total Mem"
|
||||||
|
totalMemory := fmt.Sprintf("%d", memory.Total)
|
||||||
|
|
||||||
|
log.Printf("Total Mem: %s%%\n", totalMemory)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: t.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: totalMemory,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalMemory) Timer() time.Duration {
|
||||||
|
return 24 * time.Hour
|
||||||
|
}
|
||||||
|
|
||||||
|
type TotalSwap struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTotalSwap(config Config) MetricsCollector {
|
||||||
|
return &TotalSwap{config: config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalSwap) Collect() (*Metric, error) {
|
||||||
|
memory, err := mem.SwapMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
name := t.config.ClientName + " Total Swap"
|
||||||
|
totalMemory := fmt.Sprintf("%d", memory.Total)
|
||||||
|
|
||||||
|
return &Metric{
|
||||||
|
Name: name,
|
||||||
|
ObjectId: toId(name),
|
||||||
|
Domain: t.config.ClientDomain,
|
||||||
|
Status: Status_OK,
|
||||||
|
Value: totalMemory,
|
||||||
|
Timestamp: timestamppb.Now(),
|
||||||
|
Message: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TotalSwap) Timer() time.Duration {
|
||||||
|
return 24 * time.Hour
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type MetricsCollector interface {
|
||||||
|
Collect() (*Metric, error)
|
||||||
|
Timer() time.Duration
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package watchdog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regex = regexp.MustCompile(`[^a-zA-Z0-9-_]`)
|
||||||
|
|
||||||
|
func Run() {
|
||||||
|
|
||||||
|
fmt.Println("start gRPC Client.")
|
||||||
|
|
||||||
|
config := buildConfig()
|
||||||
|
|
||||||
|
dial, err := grpc.Dial(config.Url, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := NewPushMetricsServiceClient(dial)
|
||||||
|
|
||||||
|
collectors := []MetricsCollector{
|
||||||
|
NewUsedMemory(config),
|
||||||
|
NewUsedSwap(config),
|
||||||
|
NewTotalMemory(config),
|
||||||
|
NewTotalSwap(config),
|
||||||
|
NewUsedCpu(config),
|
||||||
|
}
|
||||||
|
|
||||||
|
collectors = append(collectors, diskCollector(config)...)
|
||||||
|
|
||||||
|
collectorMap := map[time.Duration][]MetricsCollector{}
|
||||||
|
|
||||||
|
for _, collector := range collectors {
|
||||||
|
timer := collector.Timer()
|
||||||
|
|
||||||
|
metricsCollectors, ok := collectorMap[timer]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
collectorMap[timer] = append(metricsCollectors, collector)
|
||||||
|
} else {
|
||||||
|
collectorMap[timer] = []MetricsCollector{collector}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics := make(chan Metric)
|
||||||
|
|
||||||
|
for duration, metricsCollectors := range collectorMap {
|
||||||
|
|
||||||
|
duration := duration
|
||||||
|
metricsCollectors := metricsCollectors
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
|
||||||
|
for _, collector := range metricsCollectors {
|
||||||
|
|
||||||
|
collect, err := collector.Collect()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("%s: %s message: %s", collect.Name, collect.Value, collect.Message)
|
||||||
|
metrics <- *collect
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(duration)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for metric := range metrics {
|
||||||
|
_, err := client.Push(context.Background(), &metric)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toId(value string) string {
|
||||||
|
return regex.ReplaceAllString(strings.ReplaceAll(value, " ", "-"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildConfig() Config {
|
||||||
|
load, err := ini.Load("config.ini")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostinfo, err := host.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Config{
|
||||||
|
Url: load.Section("Parent").Key("url").String(),
|
||||||
|
ClientName: load.Section("Watch").Key("name").MustString(hostinfo.Hostname),
|
||||||
|
ClientDomain: load.Section("Watch").Key("domain").MustString(hostinfo.Hostname),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diskCollector(config Config) []MetricsCollector {
|
||||||
|
partitions, err := disk.Partitions(true)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return []MetricsCollector{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var collectors []MetricsCollector
|
||||||
|
for _, partition := range partitions {
|
||||||
|
collectors = append(collectors, NewUsedDisk(config, partition))
|
||||||
|
collectors = append(collectors, NewTotalDisk(config, partition))
|
||||||
|
}
|
||||||
|
return collectors
|
||||||
|
}
|
Loading…
Reference in New Issue