From d4fb85bdbd80b2ef38ab4a3dbbf2da21659f5166 Mon Sep 17 00:00:00 2001 From: Allen Zhong Date: Tue, 22 May 2018 19:59:52 +0800 Subject: [PATCH] Split collector output (#7) * collector: move ntp from sysinfo to tidb-insight * save output of `collector` to seperate file base on content sections --- collector/collector.go | 2 + collector/ntp.go | 85 ++++++++++++++++++++++++++++++++++++++++++ insight.py | 10 +++-- 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 collector/ntp.go diff --git a/collector/collector.go b/collector/collector.go index 72ef3a3..e3dbdeb 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -38,6 +38,7 @@ type Meta struct { type Metrics struct { Meta Meta `json:"meta"` SysInfo sysinfo.SysInfo `json:"sysinfo"` + NTP TimeStat `json:"ntp"` Partitions []BlockDev `json:"partitions"` ProcStats []ProcessStat `json:"proc_stats"` } @@ -57,6 +58,7 @@ func main() { func (metric *Metrics) getMetrics() { metric.Meta.getMeta() metric.SysInfo.GetSysInfo() + metric.NTP.getNTPInfo() metric.Partitions = GetPartitionStats() metric.ProcStats = GetProcStats() } diff --git a/collector/ntp.go b/collector/ntp.go new file mode 100644 index 0000000..6da7860 --- /dev/null +++ b/collector/ntp.go @@ -0,0 +1,85 @@ +// Copyright © 2018 PingCAP Inc. +// +// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +// +// Use ntpq to get basic info of NTPd on the system + +package main + +import ( + "bytes" + "log" + "os/exec" + "strconv" + "strings" +) + +type TimeStat struct { + Ver string `json:"version,omitempty"` + Sync string `json:"sync,omitempty"` + Stratum int `json:"stratum,omitempty"` + Offset float64 `json:"offset,omitempty"` + Jitter float64 `json:"jitter,omitempty"` + Status string `json:"status,omitempty"` +} + +func (ts *TimeStat) getNTPInfo() { + syncd, err := exec.LookPath("ntpq") + if err != nil { + ts.Ver = err.Error() + return + } + + cmd := exec.Command(syncd, "-c rv", "127.0.0.1") + var out bytes.Buffer + cmd.Stdout = &out + err = cmd.Run() + if err != nil { + log.Fatal(err) + } + + // set default sync status to none + ts.Sync = "none" + + output := strings.FieldsFunc(out.String(), multi_split) + for _, kv := range output { + tmp := strings.Split(strings.TrimSpace(kv), "=") + switch { + case tmp[0] == "version": + ts.Ver = strings.Trim(tmp[1], "\"") + case tmp[0] == "stratum": + ts.Stratum, err = strconv.Atoi(tmp[1]) + if err != nil { + log.Fatal(err) + } + case tmp[0] == "offset": + ts.Offset, err = strconv.ParseFloat(tmp[1], 64) + if err != nil { + log.Fatal(err) + } + case tmp[0] == "sys_jitter": + ts.Jitter, err = strconv.ParseFloat(tmp[1], 64) + if err != nil { + log.Fatal(err) + } + case strings.Contains(tmp[0], "sync"): + ts.Sync = tmp[0] + case len(tmp) > 2 && strings.Contains(tmp[1], "status"): + // sample line of tmp: ["associd", "0 status", "0618 leap_none"] + ts.Status = strings.Split(tmp[2], " ")[0] + default: + continue + } + } +} + +func multi_split(r rune) bool { + switch r { + case ',': + return true + case '\n': + return true + default: + return false + } +} diff --git a/insight.py b/insight.py index e66484c..b0971e9 100755 --- a/insight.py +++ b/insight.py @@ -62,12 +62,13 @@ def format_proc_info(self, keyname=None): # collect data with `collector` and store it to disk def collector(self): - # TODO: check existance of output dir # TODO: warn on non-empty output dir # call `collector` and store data to output dir base_dir = os.path.join(util.pwd(), "../") collector_exec = os.path.join(base_dir, "bin/collector") + collector_outdir = fileutils.create_dir( + os.path.join(self.full_outdir, "collector")) stdout, stderr = util.run_cmd(collector_exec) if stderr: @@ -77,8 +78,11 @@ def collector(self): except json.JSONDecodeError: # TODO: unified output: "Error collecting system info.\n%s" % stderr return - fileutils.write_file(os.path.join(self.full_outdir, "collector.json"), - json.dumps(self.collector_data, indent=2)) + + # save various info to seperate .json files + for k, v in self.collector_data.items(): + fileutils.write_file(os.path.join(collector_outdir, "%s.json" % k), + json.dumps(v, indent=2)) def run_perf(self, args): if not args.perf: