Files
cloudpods/pkg/apis/monitor/unifiedmonitor_query.go
T
Zexi Li 9f1e77deb6 feat(monitor): add tag name/id mapping in metric measurement API (#24999)
Return structured MetricMeasurementOutput with TagNameIdMap and
TagNameIdValueMap so callers can resolve resource names to IDs.
2026-06-09 15:14:35 +08:00

364 lines
9.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package monitor
import (
"strconv"
"strings"
"time"
)
var (
UNIFIED_MONITOR_FIELD_OPT_TYPE = []string{"Aggregations", "Selectors"}
UNIFIED_MONITOR_GROUPBY_OPT_TYPE = []string{"time", "tag", "fill"}
UNIFIED_MONITOR_FIELD_OPT_VALUE = map[string][]string{
"Aggregations": {"MEAN", "SUM", "MAX", "MIN"}, // {"COUNT", "DISTINCT", "INTEGRAL", "MEAN", "MEDIAN", "MODE", "STDDEV", "SUM"},
"Selectors": {"BOTTOM", "FIRST", "LAST", "MAX", "MIN", "TOP"},
}
UNIFIED_MONITOR_GROUPBY_OPT_VALUE = map[string][]string{
"fill": {"linear", "none", "previous", "0"},
}
MEASUREMENT_TAG_KEYWORD = map[string]string{
METRIC_RES_TYPE_HOST: "host",
METRIC_RES_TYPE_GUEST: "vm_name",
METRIC_RES_TYPE_REDIS: "redis_name",
METRIC_RES_TYPE_RDS: "rds_name",
METRIC_RES_TYPE_OSS: "oss_name",
METRIC_RES_TYPE_CLOUDACCOUNT: "cloudaccount_name",
METRIC_RES_TYPE_STORAGE: "storage_name",
METRIC_RES_TYPE_AGENT: "vm_name",
}
MEASUREMENT_TAG_ID = map[string]string{
METRIC_RES_TYPE_HOST: "host_id",
METRIC_RES_TYPE_GUEST: "vm_id",
METRIC_RES_TYPE_AGENT: "vm_id",
METRIC_RES_TYPE_REDIS: "redis_id",
METRIC_RES_TYPE_RDS: "rds_id",
METRIC_RES_TYPE_OSS: "oss_id",
METRIC_RES_TYPE_CLOUDACCOUNT: "cloudaccount_id",
METRIC_RES_TYPE_TENANT: "tenant_id",
METRIC_RES_TYPE_DOMAIN: "domain_id",
METRIC_RES_TYPE_STORAGE: "storage_id",
}
AlertReduceFunc = map[string]string{
"avg": "average value",
"sum": "Summation",
"min": "minimum value",
"max": "Maximum",
"count": "count value",
"last": "Latest value",
"median": "median",
"diff": "The difference between the latest value and the oldest value. The judgment basis value must be legal",
"delta": "The signed difference between the latest value and the oldest value (can be positive or negative)",
"percent_diff": "The difference between the new value and the old value,based on the percentage of the old value",
}
)
func GetMeasurementTagIdKeyByResType(resType string) string {
return MEASUREMENT_TAG_ID[resType]
}
func GetMeasurementTagNameIdMapByResType(resType string) map[string]string {
nameTag := MEASUREMENT_TAG_KEYWORD[resType]
idTag := MEASUREMENT_TAG_ID[resType]
if nameTag == "" || idTag == "" {
return nil
}
return map[string]string{nameTag: idTag}
}
func GetMeasurementTagIdKeyByResTypeWithDefault(resType string) string {
tagId := GetMeasurementTagIdKeyByResType(resType)
if len(tagId) == 0 {
tagId = "host_id"
}
return tagId
}
func GetMeasurementResourceId(tags map[string]string, resType string) string {
return tags[GetMeasurementTagIdKeyByResType(resType)]
}
func GetResourceIdFromTagWithDefault(tags map[string]string, resType string) string {
tagId := GetMeasurementTagIdKeyByResTypeWithDefault(resType)
return tags[tagId]
}
type MetricFunc struct {
FieldOptType []string `json:"field_opt_type"`
FieldOptValue map[string][]string `json:"field_opt_value"`
GroupOptType []string `json:"group_opt_type"`
GroupOptValue map[string][]string `json:"group_opt_value"`
}
type SimpleQueryInput struct {
// 资源Id, 可以不填, 代表查询指定监控的所有监控数据
Id string `json:"id"`
// 查询指定数据库
// default: telegraf
Database string `json:"database"`
// 监控指标: https://github.com/codelinz/cloudpods/blob/monitor/pkg/cloudprovider/metrics.go
MetricName string `json:"metric_name"`
// 开始时间
StartTime time.Time `json:"start_time"`
// 结束时间
EndTime time.Time `json:"end_time"`
// 指定标签
Tags map[string]string `json:"tag_pairs"`
// 间隔周期
// default: 5m
Interval string `json:"interval"`
}
type CdfQueryInput struct {
// 查询指定数据库
// default: telegraf
Database string `json:"database"`
// 监控指标: https://github.com/codelinz/cloudpods/blob/monitor/pkg/cloudprovider/metrics.go
MetricName string `json:"metric_name"`
// 查询周期
// exaple: 4h
// default: 1h
Period string `json:"period"`
// 指定标签
Tags map[string]string `json:"tag_pairs"`
}
type SimpleQueryOutput struct {
Id string `json:"id"`
Time time.Time `json:"time"`
Value float64 `json:"value"`
}
type MetricsQueryResult struct {
SeriesTotal int64
Series TimeSeriesSlice
Metas []QueryResultMeta
ReducedResult *ReducedResult
}
type TimeSeriesPoints []TimePoint
type TimeSeriesSlice []*TimeSeries
type TimeSeries struct {
// RawName is used to frontend displaying the curve name
RawName string `json:"raw_name"`
Columns []string `json:"columns"`
Name string `json:"name"`
Points TimeSeriesPoints `json:"points"`
Tags map[string]string `json:"tags,omitempty"`
CloudTags map[string]string `json:"cloud_tags,omitempty"`
}
type TimePoint []interface{}
func NewTimePoint(value *float64, timestamp float64) TimePoint {
return TimePoint{value, timestamp}
}
func NewTimePointByVal(value float64, timestamp float64) TimePoint {
return NewTimePoint(&value, timestamp)
}
func (p TimePoint) IsValid() bool {
if val, ok := p[0].(*float64); ok && val != nil {
return true
}
return false
//return p[0].(*float64) != nil
}
func (p TimePoint) IsValids() bool {
for i := 0; i < len(p)-1; i++ {
if p[i] == nil {
return false
}
if p[i].(*float64) == nil {
return false
}
}
return true
}
func (p TimePoint) Value() float64 {
v := p[0]
if fval, ok := v.(*float64); ok {
return *fval
}
if ival, ok := v.(*int64); ok {
return float64(*ival)
}
if t, ok := v.(float64); ok {
return t
}
if t, ok := v.(int64); ok {
return float64(t)
}
return 0
}
func (p TimePoint) Timestamp() float64 {
v := p[len(p)-1]
if t, ok := v.(float64); ok {
return t
}
if t, ok := v.(int64); ok {
return float64(t)
}
return 0
}
func (p TimePoint) Time() time.Time {
return time.UnixMilli(int64(p.Timestamp()))
}
func (p TimePoint) Values() []float64 {
values := make([]float64, 0)
for i := 0; i < len(p)-1; i++ {
values = append(values, *(p[i].(*float64)))
}
return values
}
func (p TimePoint) PointValueStr() []string {
arrStr := make([]string, 0)
for i := 0; i < len(p)-1; i++ {
if p[i] == nil {
arrStr = append(arrStr, "")
}
if fval, ok := p[i].(*float64); ok {
arrStr = append(arrStr, strconv.FormatFloat((*fval), 'f', -1, 64))
continue
}
if ival, ok := p[i].(*int64); ok {
arrStr = append(arrStr, strconv.FormatInt((*ival), 64))
continue
}
arrStr = append(arrStr, p[i].(string))
}
return arrStr
}
func NewTimeSeriesPointsFromArgs(values ...float64) TimeSeriesPoints {
points := make(TimeSeriesPoints, 0)
for i := 0; i < len(values); i += 2 {
points = append(points, NewTimePoint(&values[i], values[i+1]))
}
return points
}
type QueryResultMeta struct {
RawQuery string `json:"raw_query"`
ResultReducerValue float64 `json:"result_reducer_value"`
}
const ConditionTypeMetricQuery = "metricquery"
type CdfQueryData struct {
Vmrange string
Metric float64
Value int
ValueAsc int
ValueDesc int
Total int
}
func (c CdfQueryData) Copy() CdfQueryData {
return CdfQueryData{
Vmrange: c.Vmrange,
Metric: c.Metric,
Value: c.Value,
ValueAsc: c.ValueAsc,
ValueDesc: c.ValueDesc,
Total: c.Total,
}
}
func (c CdfQueryData) Start() float64 {
s := strings.Split(c.Vmrange, "...")[0]
v, _ := strconv.ParseFloat(s, 64)
return v
}
func (c CdfQueryData) End() float64 {
info := strings.Split(c.Vmrange, "...")
v := 0.0
if len(info) == 2 {
v, _ = strconv.ParseFloat(info[1], 64)
}
return v
}
type CdfQueryDataSet []CdfQueryData
func (c CdfQueryDataSet) Len() int {
return len(c)
}
func (c CdfQueryDataSet) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func (c CdfQueryDataSet) Less(i, j int) bool {
return c[i].Start() < c[j].Start()
}
type CdfQueryOutput struct {
Data CdfQueryDataSet
}
// ResourceMetricsQueryInput 批量查询资源监控数据的输入参数
type ResourceMetricsQueryInput struct {
// 资源类型: "host" 或 "guest"
ResType string `json:"res_type"`
// 资源 ID 列表
ResIds []string `json:"res_ids"`
// 查询开始时间(默认: 1小时前)
StartTime time.Time `json:"start_time"`
// 查询结束时间(默认: now
EndTime time.Time `json:"end_time"`
// 查询间隔(默认: 5m
Interval string `json:"interval"`
}
// ResourceMetricValues 单个资源的监控数据
type ResourceMetricValues struct {
// CPU 使用率 (%)
CpuUsage *float64 `json:"cpu_usage"`
// 内存使用率 (%)
MemUsage *float64 `json:"mem_usage"`
// 磁盘使用率 (%)
DiskUsage *float64 `json:"disk_usage"`
// 磁盘读速率 (Bps)
DiskReadRate *float64 `json:"disk_read_rate"`
// 磁盘写速率 (Bps)
DiskWriteRate *float64 `json:"disk_write_rate"`
// 网络入流量 (bps)
NetInRate *float64 `json:"net_in_rate"`
// 网络出流量 (bps)
NetOutRate *float64 `json:"net_out_rate"`
// 告警状态: init/attach/alerting
AlertState string `json:"alert_state"`
}
// ResourceMetricsQueryOutput 批量查询资源监控数据的输出
type ResourceMetricsQueryOutput struct {
ResourceMetrics map[string]ResourceMetricValues `json:"resource_metrics"`
}