/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ package ceph import ( "encoding/json" "math" "sort" "git.zabbix.com/ap/plugin-support/zbxerr" ) type aggDataInt struct { Min uint64 `json:"min"` Max uint64 `json:"max"` Avg float64 `json:"avg"` } // newAggDataInt calculates min, max and average values for a given slice of integers. func newAggDataInt(v []uint64) aggDataInt { if len(v) == 0 { return aggDataInt{0, 0, 0} } var total uint64 = 0 for _, value := range v { total += value } sort.Slice(v, func(i, j int) bool { return v[i] < v[j] }) return aggDataInt{ Min: v[0], Max: v[len(v)-1], Avg: float64(total) / float64(len(v)), } } type aggDataFloat struct { Min float64 `json:"min"` Max float64 `json:"max"` Avg float64 `json:"avg"` } // newAggDataFloat calculates min, max and average values for a given slice of floats. func newAggDataFloat(v []float64) aggDataFloat { if len(v) == 0 { return aggDataFloat{0, 0, 0} } var total float64 = 0 for _, value := range v { total += value } sort.Float64s(v) return aggDataFloat{ Min: v[0], Max: v[len(v)-1], Avg: total / float64(len(v)), } } type cephPgDump struct { PgMap struct { OsdStats []struct { Name json.Number `json:"osd"` PerfStat struct { LatencyApply uint64 `json:"apply_latency_ms"` LatencyCommit uint64 `json:"commit_latency_ms"` } `json:"perf_stat"` NumPgs uint64 `json:"num_pgs"` Kb float64 `json:"kb"` KbUsed float64 `json:"kb_used"` } `json:"osd_stats"` } `json:"pg_map"` } type osdStat struct { LatencyApply uint64 `json:"osd_latency_apply"` LatencyCommit uint64 `json:"osd_latency_commit"` NumPgs uint64 `json:"num_pgs"` OsdFill float64 `json:"osd_fill"` } type outOsdStats struct { LatencyApply aggDataInt `json:"osd_latency_apply"` LatencyCommit aggDataInt `json:"osd_latency_commit"` Fill aggDataFloat `json:"osd_fill"` Pgs aggDataInt `json:"osd_pgs"` Osds map[string]osdStat `json:"osds"` } // osdHandler returns OSDs statistics provided by "pg dump" command. func osdHandler(data map[command][]byte) (interface{}, error) { var pgDump cephPgDump err := json.Unmarshal(data[cmdPgDump], &pgDump) if err != nil { return nil, zbxerr.ErrorCannotUnmarshalJSON.Wrap(err) } var ( fill float64 latencyApplyList []uint64 latencyCommitList []uint64 fillList []float64 PgsList []uint64 out outOsdStats ) out.Osds = make(map[string]osdStat) for _, osd := range pgDump.PgMap.OsdStats { fill = 0 if osd.Kb != 0 { fill = math.Ceil(osd.KbUsed / osd.Kb * 100) } out.Osds[osd.Name.String()] = osdStat{ LatencyApply: osd.PerfStat.LatencyApply, LatencyCommit: osd.PerfStat.LatencyCommit, NumPgs: osd.NumPgs, OsdFill: fill, } latencyApplyList = append(latencyApplyList, osd.PerfStat.LatencyApply) latencyCommitList = append(latencyCommitList, osd.PerfStat.LatencyCommit) PgsList = append(PgsList, osd.NumPgs) fillList = append(fillList, fill) } out.LatencyApply = newAggDataInt(latencyApplyList) out.LatencyCommit = newAggDataInt(latencyCommitList) out.Fill = newAggDataFloat(fillList) out.Pgs = newAggDataInt(PgsList) jsonRes, err := json.Marshal(out) if err != nil { return nil, zbxerr.ErrorCannotMarshalJSON.Wrap(err) } return string(jsonRes), nil }