liuhaijun e94826ce29 add server
Change-Id: I0760f17f6a01c0121b59fcbfafc666032dbc30af
2024-09-19 09:44:15 +00:00

468 lines
12 KiB
Go

package v1
import (
"context"
"encoding/json"
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/data"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
mc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/metric"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
"github.com/gin-gonic/gin"
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/common/model"
"strings"
"time"
)
type QueryBody struct {
Rids string `json:"rids"`
OrgId string `json:"orgId"`
AssetType string `json:"assetType"`
RuleNos string `json:"ruleNo"`
Start string `json:"start"`
End string `json:"end"`
Step time.Duration `json:"step"`
}
type Metric struct {
RuleNo string `json:"ruleNo"`
RuleName string `json:"ruleName"`
Data interface{} `json:"data"`
}
type Pair struct {
Time model.Time `json:"time"`
Value interface{} `json:"value"`
}
func QueryMetric(c *gin.Context) {
body := request.GetBody(c)
var b QueryBody
err := json.Unmarshal(body, &b)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
return
}
var end time.Time
if b.End != "" {
end, err = time.Parse(time.RFC3339, b.End)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "invalid end")
return
}
} else {
end = time.Now()
}
var start time.Time
if b.Start != "" {
start, err = time.Parse(time.RFC3339, b.Start)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "invalid start")
return
}
} else if b.End == "" {
start = end
}
if end.Before(start) {
controller.FailCode(c, errors.InvalidParameter, err, "invalid start and end")
return
}
if b.Step == 0 {
duration := end.Sub(start)
durationSeconds := duration.Seconds()
b.Step = time.Duration(durationSeconds/6) * time.Second
if b.Step == 0 {
b.Step = time.Second
}
}
ruleNos := strings.Split(b.RuleNos, ",")
if len(ruleNos) == 0 {
controller.Success(c, nil)
return
}
rids := strings.Split(b.Rids, ",")
if len(rids) == 0 {
controller.Success(c, nil)
return
}
if data.V1api == nil {
log.Info("prometheus client is nil")
controller.Success(c, nil)
return
}
device := &device.DeviceInfo{}
devices, err := device.GetBySerialNos(rids)
if len(devices) == 0 {
controller.FailCode(c, errors.InvalidParameter, err, "rids are not exist")
return
}
osType := make(map[string]string, len(devices))
for _, info := range devices {
osType[info.SerialNo] = info.OsType
}
rule := mc.MetricsRule{}
rules, err := rule.GetByRuleNo(ruleNos)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
return
}
if len(rules) == 0 {
controller.Success(c, nil)
return
}
result := make(map[string][]Metric, len(rids))
for _, rid := range rids {
var isWindows bool
if osType[rid] == "" || strings.ToLower(osType[rid]) == "windows" {
isWindows = true
} else {
isWindows = false
}
result[rid] = []Metric{}
for _, metricsRule := range rules {
var ruleQl string
if isWindows {
ruleQl = metricsRule.RuleQlWindows
} else {
ruleQl = metricsRule.RuleQl
}
promQl := strings.ReplaceAll(ruleQl, "$rid", rid)
queryRange, _, err := data.V1api.QueryRange(context.TODO(), promQl, v1.Range{
Start: start,
End: end,
Step: b.Step,
})
if err != nil {
log.Info("failed to query range, err: ", err.Error())
continue
}
var data interface{}
resultType := queryRange.Type()
switch resultType {
case model.ValScalar:
scalar := queryRange.(*model.Scalar)
data = []Pair{
{
scalar.Timestamp,
scalar.Value,
},
}
case model.ValMatrix:
matrix := queryRange.(model.Matrix)
size := len(matrix)
if size > 1 {
temp := make(map[string][]Pair)
for _, stream := range matrix {
var pairs []Pair
for _, value := range stream.Values {
pairs = append(pairs, Pair{
value.Timestamp,
value.Value,
})
}
key, _ := json.Marshal(stream.Metric)
temp[string(key)] = pairs
}
data = temp
} else if size > 0 {
var pairs []Pair
values := matrix[0].Values
for i := range values {
pairs = append(pairs, Pair{
values[i].Timestamp,
values[i].Value,
})
}
data = pairs
}
case model.ValString:
str := queryRange.(*model.String)
data = []Pair{
{
str.Timestamp,
str.Value,
},
}
case model.ValVector:
vector := queryRange.(model.Vector)
size := len(vector)
if size > 1 {
temp := make(map[string][]Pair)
for _, sample := range vector {
key, _ := json.Marshal(sample.Metric.String())
temp[string(key)] = []Pair{{
sample.Timestamp,
sample.Value},
}
}
data = temp
} else if size > 0 {
data = []Pair{
{
vector[0].Timestamp,
vector[0].Value,
},
}
}
default:
continue
}
result[rid] = append(result[rid], Metric{
metricsRule.RuleNo,
metricsRule.RuleName,
data,
})
}
}
controller.Success(c, result)
}
type ProcessMetricQueryBody struct {
Rid string `json:"rid"`
PName string `json:"pName"`
Start string `json:"start"`
End string `json:"end"`
Step time.Duration `json:"step"`
}
func QueryProcessMetric(c *gin.Context) {
body := request.GetBody(c)
var b ProcessMetricQueryBody
err := json.Unmarshal(body, &b)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
return
}
if b.Rid == "" || b.PName == "" {
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
}
var end time.Time
if b.End != "" {
end, err = time.Parse(time.RFC3339, b.End)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "invalid end")
return
}
} else {
end = time.Now()
}
var start time.Time
if b.Start != "" {
start, err = time.Parse(time.RFC3339, b.Start)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "invalid start")
return
}
} else if b.End == "" {
start = end
}
if end.Before(start) {
controller.FailCode(c, errors.InvalidParameter, err, "invalid start and end")
return
}
if b.Step == 0 {
duration := end.Sub(start)
durationSeconds := duration.Seconds()
b.Step = time.Duration(durationSeconds/6) * time.Second
if b.Step == 0 {
b.Step = time.Second
}
}
d := &device.DeviceInfo{}
r, err := d.GetBySerialNo(b.Rid)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "rid are not exist")
return
}
isWindows := strings.ToLower(r.OsType) == "windows"
promQLs := make(map[string]string)
if isWindows {
promQLs["read"] = fmt.Sprintf(
`rate(windows_process_io_bytes_total{rid="%s", process="%s", mode="read"}[5m])`, b.Rid, b.PName)
promQLs["write"] = fmt.Sprintf(
`rate(windows_process_io_bytes_total{rid="%s", process="%s", mode="write"}[5m])`, b.Rid, b.PName)
promQLs["cpu"] = fmt.Sprintf(
`sum(rate(windows_process_cpu_time_total{rid="%s", process="%s"}[5m]))`, b.Rid, b.PName)
promQLs["memory"] = fmt.Sprintf(
`sum(windows_process_page_file_bytes{rid="%s", process="%s"})`, b.Rid, b.PName)
} else {
promQLs["read"] = fmt.Sprintf(
`rate(namedprocess_namegroup_read_bytes_total{rid="%s",groupname="%s"}[5m])`, b.Rid, b.PName)
promQLs["write"] = fmt.Sprintf(
`rate(namedprocess_namegroup_write_bytes_total{rid="%s",groupname="%s"}[5m])`, b.Rid, b.PName)
promQLs["cpu"] = fmt.Sprintf(
`sum(rate(namedprocess_namegroup_cpu_seconds_total{rid="%s",groupname="%s"}[5m]))`, b.Rid, b.PName)
promQLs["memory"] = fmt.Sprintf(
`sum(namedprocess_namegroup_memory_bytes{rid="%s",groupname="%s"})`, b.Rid, b.PName)
}
result := make(map[string][]Pair)
for key, promQL := range promQLs {
queryRange, _, err := data.V1api.QueryRange(context.TODO(), promQL, v1.Range{
Start: start,
End: end,
Step: b.Step,
})
if err != nil {
log.Info("failed to query range, err: ", err.Error())
continue
}
var pairs []Pair
resultType := queryRange.Type()
switch resultType {
case model.ValScalar:
scalar := queryRange.(*model.Scalar)
pairs = append(pairs, Pair{
scalar.Timestamp,
scalar.Value,
})
case model.ValMatrix:
matrix := queryRange.(model.Matrix)
if len(matrix) == 0 {
continue
}
values := matrix[0].Values
for i := range values {
pairs = append(pairs, Pair{
values[i].Timestamp,
values[i].Value,
})
}
case model.ValString:
str := queryRange.(*model.String)
pairs = append(pairs, Pair{
str.Timestamp,
str.Value,
})
case model.ValVector:
vector := queryRange.(model.Vector)
for i := range vector {
pairs = append(pairs, Pair{
vector[i].Timestamp,
vector[i].Value,
})
}
default:
continue
}
result[key] = pairs
}
controller.Success(c, result)
}
func QueryProcessListMetric(c *gin.Context) {
rid := c.Param("rid")
d := &device.DeviceInfo{}
r, err := d.GetBySerialNo(rid)
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "rid are not exist")
return
}
isWindows := strings.ToLower(r.OsType) == "windows"
promQLs := make(map[string]string)
if isWindows {
promQLs["pName"] = fmt.Sprintf(
`sum(windows_process_start_time{rid="%s"}) by (process)`, rid)
promQLs["state"] = fmt.Sprintf(
`sum(windows_process_threads{rid="%s"}) by (process) > 0`, rid)
promQLs["cpu"] = fmt.Sprintf(
`sum(rate(windows_process_cpu_time_total{rid="%s"}[5m])) by (process)`, rid)
promQLs["memory"] = fmt.Sprintf(
`sum(windows_process_page_file_bytes{rid="%s"}) by (process)`, rid)
promQLs["diskIO"] = fmt.Sprintf(
`sum(rate(windows_process_io_bytes_total{rid="%s", mode="read"}[5m])) by (process)`, rid)
} else {
promQLs["pName"] = fmt.Sprintf(
`namedprocess_namegroup_num_procs{rid="%s"} == 1`, rid)
promQLs["state"] = fmt.Sprintf(
`sum(namedprocess_namegroup_states{rid="%s", state=~"Other|Zombie"}) by (groupname) == 0`, rid)
promQLs["cpu"] = fmt.Sprintf(
`sum(rate(namedprocess_namegroup_cpu_seconds_total{rid="%s"}[5m])) by (groupname)`, rid)
promQLs["memory"] = fmt.Sprintf(
`sum(namedprocess_namegroup_memory_bytes{rid="%s"}) by (groupname)`, rid)
promQLs["diskIO"] = fmt.Sprintf(
`rate(namedprocess_namegroup_read_bytes_total{rid="%s"}[5m]) + rate(namedprocess_namegroup_write_bytes_total{rid="%s"}[5m])`, rid, rid)
}
temp := make(map[string][]*model.Sample)
time := time.Now()
for key, promQL := range promQLs {
queryRange, _, err := data.V1api.Query(context.TODO(), promQL, time)
if err != nil {
log.Info("failed to query range, err: ", err.Error())
continue
}
if queryRange.Type() == model.ValVector {
temp[key] = queryRange.(model.Vector)
}
}
samples := temp["pName"]
result := make(map[string]map[string]interface{}, len(samples))
var processName model.LabelName
if isWindows {
processName = "process"
} else {
processName = "groupname"
}
for _, sample := range samples {
result[string(sample.Metric[processName])] = make(map[string]interface{}, 3)
}
delete(temp, "pName")
samples = temp["state"]
for _, sample := range samples {
pName := string(sample.Metric[processName])
if _, ok := result[pName]; ok {
result[pName]["status"] = true
}
}
delete(temp, "state")
for key, value := range temp {
for _, sample := range value {
pName := string(sample.Metric[processName])
if _, ok := result[pName]; !ok {
continue
}
result[pName][key] = sample.Value
}
}
controller.Success(c, result)
}