|
package main |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"os" |
|
"os/exec" |
|
"regexp" |
|
"strconv" |
|
"strings" |
|
"sync" |
|
"time" |
|
|
|
"github.com/google/uuid" |
|
) |
|
|
|
func main() { |
|
data, err := json.MarshalIndent(NewEvent(), "", " ") |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
fmt.Println(string(data)) |
|
} |
|
|
|
func NewEvent() *Event { |
|
return &Event{ |
|
ID: uuid.New().String(), |
|
Timestamp: time.Now(), |
|
EventHost: getEventHost(), |
|
EventRuntime: getEventRuntime(), |
|
} |
|
} |
|
|
|
type Event struct { |
|
ID string `json:"id"` |
|
Timestamp time.Time `json:"timestamp"` |
|
EventHost |
|
EventRuntime |
|
} |
|
|
|
type EventHost struct { |
|
Platform string `json:"platform"` |
|
ProcessorCount int `json:"processor_count,omitempty"` |
|
MemoryTotal string `json:"memory_total,omitempty"` |
|
User string `json:"user"` |
|
} |
|
|
|
var ( |
|
hostEvent EventHost |
|
hostEventOnce sync.Once |
|
|
|
processorsRegex = regexp.MustCompile(`^(\d+) processors are physically available.`) |
|
memoryFreeRegex = regexp.MustCompile(`^System-wide memory free percentage:\s+(\d+)%`) |
|
batteryLevelRegex = regexp.MustCompile(`^ -InternalBattery-0.+?(\d+)%`) |
|
powerSourceRegex = regexp.MustCompile(`Now drawing from '(.+)'`) |
|
) |
|
|
|
func getEventHost() EventHost { |
|
hostEventOnce.Do(func() { |
|
platformBytes, err := exec.Command("sysctl", "-n", "machdep.cpu.brand_string").Output() |
|
if err != nil { |
|
platformBytes = []byte("unknown") |
|
} |
|
|
|
ev := EventHost{ |
|
Platform: strings.TrimSpace(string(platformBytes)), |
|
User: os.Getenv("USER"), |
|
} |
|
|
|
hostinfo, _ := exec.Command("hostinfo").Output() |
|
for _, line := range strings.Split(string(hostinfo), "\n") { |
|
if processorsRegex.MatchString(line) { |
|
countString := processorsRegex.FindStringSubmatch(line)[1] |
|
count, _ := strconv.ParseInt(countString, 10, 64) |
|
|
|
ev.ProcessorCount = int(count) |
|
} else if strings.HasPrefix(line, "Primary memory available: ") { |
|
ev.MemoryTotal = strings.SplitN(line, ": ", 2)[1] |
|
} |
|
} |
|
|
|
hostEvent = ev |
|
}) |
|
|
|
return hostEvent |
|
} |
|
|
|
type EventRuntime struct { |
|
PowerSource string `json:"power_source,omitempty"` |
|
BatteryLevel string `json:"battery_level,omitempty"` |
|
MemoryFree string `json:"memory_free,omitempty"` |
|
DockerStatus string `json:"docker_status,omitempty"` |
|
DockerCPU int `json:"docker_cpu,omitempty"` |
|
DockerMemoryTotal int `json:"docker_memory_total,omitempty"` |
|
DockerVersion string `json:"docker_version,omitempty"` |
|
} |
|
|
|
func getEventRuntime() (ev EventRuntime) { |
|
memoryPressure, _ := exec.Command("memory_pressure").Output() |
|
for _, line := range strings.Split(string(memoryPressure), "\n") { |
|
if memoryFreeRegex.MatchString(line) { |
|
ev.MemoryFree = memoryFreeRegex.FindStringSubmatch(line)[1] |
|
} |
|
} |
|
|
|
// Default assume that docker is disabled. |
|
ev.DockerStatus = "disabled" |
|
var dockerInfo struct { |
|
NCPU int `json:"NCPU"` |
|
MemTotal int `json:"MemTotal"` |
|
ServerVersion string `json:"ServerVersion"` |
|
} |
|
dockerInfoOutput, _ := exec.Command("docker", "info", "--format=json").Output() |
|
_ = json.Unmarshal(dockerInfoOutput, &dockerInfo) |
|
if dockerInfo.ServerVersion != "" { |
|
ev.DockerStatus = "running" |
|
ev.DockerCPU = dockerInfo.NCPU |
|
ev.DockerMemoryTotal = dockerInfo.MemTotal |
|
ev.DockerVersion = dockerInfo.ServerVersion |
|
} |
|
|
|
pmset, _ := exec.Command("pmset", "-g", "batt").Output() |
|
ev.PowerSource = "UNKNOWN" |
|
for _, line := range strings.Split(string(pmset), "\n") { |
|
if powerSourceRegex.MatchString(line) { |
|
ev.PowerSource = powerSourceRegex.FindStringSubmatch(line)[1] |
|
} else if batteryLevelRegex.MatchString(line) { |
|
ev.BatteryLevel = batteryLevelRegex.FindStringSubmatch(line)[1] |
|
} |
|
} |
|
|
|
return |
|
} |