diff --git a/configs/qcloud-clb7-product.yml b/configs/qcloud-clb7-product.yml new file mode 100644 index 0000000..91cc2fe --- /dev/null +++ b/configs/qcloud-clb7-product.yml @@ -0,0 +1,17 @@ +credential: + access_key: "access_key" + secret_key: "secret_key" + region: "region" + +rate_limit: 15 #云监控拉数据接口最大限制, 20/秒, 1200/分钟, https://cloud.tencent.com/document/product/248/31014 + +products: + - namespace: QCE/LOADBALANCE #指标详情: https://cloud.tencent.com/document/product/248/45045 + all_metrics: true + all_instances: true + #only_include_metrics: [] + #only_include_instances: [lb-xxxxxxxx] + #extra_labels: [InstanceName] + #statistics_types: [last] + #period_seconds: 60 + #metric_name_type: 2 \ No newline at end of file diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 21586c7..f35bcad 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -36,6 +36,7 @@ var ( collectorState = make(map[string]int) ) +// 总指标采集器, 包含多个产品的采集器 type TcMonitorCollector struct { Collectors map[string]*TcProductCollector config *config.TencentConfig diff --git a/pkg/collector/handler.go b/pkg/collector/handler.go index 852f645..99b6737 100644 --- a/pkg/collector/handler.go +++ b/pkg/collector/handler.go @@ -11,12 +11,19 @@ var ( handlerFactoryMap = make(map[string]func(*TcProductCollector, log.Logger) (productHandler, error)) ) +// 每个产品的指标处理逻辑 type productHandler interface { + // 获取云监控指标namespace GetNamespace() string + // 对指标元数据做检验和补充 + CheckMetricMeta(meta *metric.TcmMeta) bool + // 是否包含该指标, ture=包含, false=不包含 IsIncludeMetric(m *metric.TcmMetric) bool + // 获取该指标下符合条件的所有实例, 并生成所有的series GetSeries(tcmMetric *metric.TcmMetric) (series []*metric.TcmSeries, err error) } +// 将对应的产品handler注册到Factory中 func registerHandler(namespace string, isDefaultEnabled bool, factory func(*TcProductCollector, log.Logger) (productHandler, error)) { handlerFactoryMap[namespace] = factory } @@ -36,7 +43,7 @@ func (h *baseProductHandler) GetSeries(m *metric.TcmMetric) (slist []*metric.Tcm continue } ql := map[string]string{ - h.monitorQueryKey: ins.GetInstanceId(), + h.monitorQueryKey: ins.GetMonitorQueryKey(), } s, err := metric.NewTcmSeries(m, ql, ins) if err != nil { @@ -52,7 +59,7 @@ func (h *baseProductHandler) GetSeries(m *metric.TcmMetric) (slist []*metric.Tcm } for _, ins := range insList { ql := map[string]string{ - h.monitorQueryKey: ins.GetInstanceId(), + h.monitorQueryKey: ins.GetMonitorQueryKey(), } s, err := metric.NewTcmSeries(m, ql, ins) if err != nil { @@ -71,13 +78,13 @@ func (h *baseProductHandler) GetSeries(m *metric.TcmMetric) (slist []*metric.Tcm } ins, err := h.collector.InstanceRepo.Get(v) if err != nil { - level.Error(h.logger).Log("msg", "Instance not found", "id", v) + level.Error(h.logger).Log("msg", "Instance not found", "err", err, "id", v) continue } s, err := metric.NewTcmSeries(m, ql, ins) if err != nil { - level.Error(h.logger).Log("msg", "Create metric series fail", "metric", m.Meta.MetricName, "instacne", ins.GetInstanceId()) + level.Error(h.logger).Log("msg", "Create metric series fail", "err", err, "metric", m.Meta.MetricName, "instacne", ins.GetInstanceId()) continue } slist = append(slist, s) diff --git a/pkg/collector/handler_cdb.go b/pkg/collector/handler_cdb.go index 7711280..554a756 100644 --- a/pkg/collector/handler_cdb.go +++ b/pkg/collector/handler_cdb.go @@ -18,6 +18,10 @@ type cdbHandler struct { baseProductHandler } +func (h *cdbHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *cdbHandler) GetNamespace() string { return CdbNamespace } diff --git a/pkg/collector/handler_cdn.go b/pkg/collector/handler_cdn.go index 390aff2..a7c074d 100644 --- a/pkg/collector/handler_cdn.go +++ b/pkg/collector/handler_cdn.go @@ -20,6 +20,10 @@ type cdnHandler struct { baseProductHandler } +func (h *cdnHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *cdnHandler) GetNamespace() string { return CdnNamespace } diff --git a/pkg/collector/handler_clb.go b/pkg/collector/handler_clb.go index 22d3678..6ee0d97 100644 --- a/pkg/collector/handler_clb.go +++ b/pkg/collector/handler_clb.go @@ -18,6 +18,13 @@ type clbHandler struct { baseProductHandler } +func (h *clbHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + if len(meta.SupportDimensions) == 0 { + meta.SupportDimensions = append(meta.SupportDimensions, "vip") + } + return true +} + func (h *clbHandler) GetNamespace() string { return ClbNamespace } diff --git a/pkg/collector/handler_clb7.go b/pkg/collector/handler_clb7.go new file mode 100644 index 0000000..3acc660 --- /dev/null +++ b/pkg/collector/handler_clb7.go @@ -0,0 +1,60 @@ +package collector + +import ( + "github.com/go-kit/kit/log" + "github.com/tencentyun/tencentcloud-exporter/pkg/metric" + "github.com/tencentyun/tencentcloud-exporter/pkg/util" + "strings" +) + +const ( + Clb7Namespace = "QCE/LOADBALANCE" + Clb7InstanceidKey = "vip" +) + +var ( + Clb7ExcludeMetrics = []string{ + "outpkgratio", + "intrafficratio", + "inpkgratio", + "qpsratio", + "activeconnratio", + "newactiveconnratio", + "outtrafficratio", + } +) + +func init() { + registerHandler(Clb7Namespace, defaultHandlerEnabled, NewClb7Handler) +} + +type clb7Handler struct { + baseProductHandler +} + +func (h *clb7Handler) CheckMetricMeta(meta *metric.TcmMeta) bool { + meta.SupportDimensions = append(meta.SupportDimensions, "vip") + return true +} + +func (h *clb7Handler) GetNamespace() string { + return Clb7Namespace +} + +func (h *clb7Handler) IsIncludeMetric(m *metric.TcmMetric) bool { + if util.IsStrInList(Clb7ExcludeMetrics, strings.ToLower(m.Meta.MetricName)) { + return false + } + return true +} + +func NewClb7Handler(c *TcProductCollector, logger log.Logger) (handler productHandler, err error) { + handler = &clb7Handler{ + baseProductHandler{ + monitorQueryKey: Clb7InstanceidKey, + collector: c, + logger: logger, + }, + } + return +} diff --git a/pkg/collector/handler_cos.go b/pkg/collector/handler_cos.go index 5b2114e..1833831 100644 --- a/pkg/collector/handler_cos.go +++ b/pkg/collector/handler_cos.go @@ -24,6 +24,10 @@ type cosHandler struct { baseProductHandler } +func (h *cosHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *cosHandler) GetNamespace() string { return CosNamespace } diff --git a/pkg/collector/handler_cvm.go b/pkg/collector/handler_cvm.go index 8877a5b..61696fd 100644 --- a/pkg/collector/handler_cvm.go +++ b/pkg/collector/handler_cvm.go @@ -24,6 +24,10 @@ type cvmHandler struct { baseProductHandler } +func (h *cvmHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *cvmHandler) GetNamespace() string { return CvmNamespace } diff --git a/pkg/collector/handler_dc.go b/pkg/collector/handler_dc.go index af5dc23..d4feebc 100644 --- a/pkg/collector/handler_dc.go +++ b/pkg/collector/handler_dc.go @@ -18,6 +18,10 @@ type dcHandler struct { baseProductHandler } +func (h *dcHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *dcHandler) GetNamespace() string { return DcNamespace } diff --git a/pkg/collector/handler_dcx.go b/pkg/collector/handler_dcx.go index ca1d2a6..c4dc783 100644 --- a/pkg/collector/handler_dcx.go +++ b/pkg/collector/handler_dcx.go @@ -18,6 +18,10 @@ type dcxHandler struct { baseProductHandler } +func (h *dcxHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *dcxHandler) GetNamespace() string { return DcxNamespace } diff --git a/pkg/collector/handler_mongo.go b/pkg/collector/handler_mongo.go index 14f172b..4b7e735 100644 --- a/pkg/collector/handler_mongo.go +++ b/pkg/collector/handler_mongo.go @@ -17,7 +17,6 @@ const ( ) var ( - // TODO: Disk未找到 MongoClusterMetrics = []string{ "inserts", "reads", "updates", "deletes", "counts", "aggregates", "clusterconn", "commands", "connper", "clusterdiskusage", "qps", "success", "delay10", "delay50", "delay100", "timeouts", @@ -39,6 +38,10 @@ type mongoHandler struct { logger log.Logger } +func (h *mongoHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *mongoHandler) GetNamespace() string { return MongoNamespace } diff --git a/pkg/collector/handler_nat.go b/pkg/collector/handler_nat.go index 481c6f5..629aa64 100644 --- a/pkg/collector/handler_nat.go +++ b/pkg/collector/handler_nat.go @@ -18,6 +18,10 @@ type natHandler struct { baseProductHandler } +func (h *natHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *natHandler) GetNamespace() string { return NatNamespace } diff --git a/pkg/collector/handler_redis.go b/pkg/collector/handler_redis.go index efb5814..8d4941d 100644 --- a/pkg/collector/handler_redis.go +++ b/pkg/collector/handler_redis.go @@ -35,6 +35,10 @@ type redisHandler struct { baseProductHandler } +func (h *redisHandler) CheckMetricMeta(meta *metric.TcmMeta) bool { + return true +} + func (h *redisHandler) GetNamespace() string { return RedisNamespace } diff --git a/pkg/collector/product.go b/pkg/collector/product.go index b00311c..ecca64f 100644 --- a/pkg/collector/product.go +++ b/pkg/collector/product.go @@ -13,6 +13,7 @@ import ( "sync" ) +// 每个产品的指标采集默认实现, 不同的逻辑通过对应的productHandler实现 type TcProductCollector struct { Namespace string MetricRepo metric.TcmMetricRepository @@ -118,7 +119,12 @@ func (c *TcProductCollector) loadMetricsByProductConf() (err error) { for _, mname := range metricNames { meta, err := c.MetricRepo.GetMeta(c.Namespace, mname) if err != nil { - level.Error(c.logger).Log("msg", "not found metric meta", "Namespace", c.Namespace, "name", mname) + level.Error(c.logger).Log("msg", "Not found metric meta", "Namespace", c.Namespace, "name", mname) + continue + } + // 指标元数据处理, false=跳过 + if !c.handler.CheckMetricMeta(meta) { + level.Error(c.logger).Log("msg", " Metric meta check fail, skip", "Namespace", c.Namespace, "name", meta.MetricName) continue } @@ -177,6 +183,7 @@ func (c *TcProductCollector) initQuerys() (err error) { return } +// 执行所有指标的采集 func (c *TcProductCollector) Collect(ch chan<- prometheus.Metric) (err error) { wg := sync.WaitGroup{} wg.Add(len(c.Querys)) @@ -203,14 +210,16 @@ func (c *TcProductCollector) Collect(ch chan<- prometheus.Metric) (err error) { return } +// 创建新的TcProductCollector, 每个产品一个 func NewTcProductCollector(namespace string, metricRepo metric.TcmMetricRepository, conf *config.TencentConfig, logger log.Logger) (*TcProductCollector, error) { factory, exists := handlerFactoryMap[namespace] if !exists { - return nil, fmt.Errorf("Product handler not found, Namespace=%s ", namespace) + return nil, fmt.Errorf("product handler not found, Namespace=%s ", namespace) } var instanceRepoCache instance.TcInstanceRepository if !util.IsStrInList(instance.NotSupportInstances, namespace) { + // 支持实例自动发现的产品 instanceRepo, err := instance.NewTcInstanceRepository(namespace, conf, logger) if err != nil { return nil, err diff --git a/pkg/config/config.go b/pkg/config/config.go index 9d666db..b0504ee 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -30,6 +30,8 @@ var ( "dcx": "QCE/DCX", "lb_public": "QCE/LB_PUBLIC", "public_clb": "QCE/LB_PUBLIC", + "loadbalance": "QCE/LOADBALANCE", + "7layer_clb": "QCE/LOADBALANCE", "nat_gateway": "QCE/NAT_GATEWAY", "nat": "QCE/NAT_GATEWAY", "cos": "QCE/COS", diff --git a/pkg/instance/cache.go b/pkg/instance/cache.go index ea668ad..ece48c2 100644 --- a/pkg/instance/cache.go +++ b/pkg/instance/cache.go @@ -7,6 +7,7 @@ import ( "time" ) +// 可用于产品的实例的缓存, TcInstanceRepository type TcInstanceCache struct { Raw TcInstanceRepository cache map[string]TcInstance diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index 2a90c8b..c0f3bef 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -12,14 +12,18 @@ var NotSupportInstances = []string{ "QCE/CDN", } +// 每个产品的实例对象, 可用于配置导出指标的额外label填充, 根据字段名获取值 type TcInstance interface { + // 获取实例的id GetInstanceId() string + // 用于查询云监控数据的主键字段, 一般是实例id GetMonitorQueryKey() string // 根据字段名称获取该字段的值, 由各个产品接口具体实现 GetFieldValueByName(string) (string, error) + // 获取实例raw元数据, 每个实例类型不一样 GetMeta() interface{} } diff --git a/pkg/instance/repository.go b/pkg/instance/repository.go index d035a33..9c7ac0c 100644 --- a/pkg/instance/repository.go +++ b/pkg/instance/repository.go @@ -10,10 +10,15 @@ var ( factoryMap = make(map[string]func(*config.TencentConfig, log.Logger) (TcInstanceRepository, error)) ) +// 每个产品的实例对象的Repository type TcInstanceRepository interface { + // 获取实例id GetInstanceKey() string + // 根据id, 获取实例对象 Get(id string) (TcInstance, error) + // 根据id列表, 获取所有的实例对象 ListByIds(ids []string) ([]TcInstance, error) + // 根据filters, 获取符合条件的所有实例对象 ListByFilters(filters map[string]string) ([]TcInstance, error) } @@ -25,6 +30,7 @@ func NewTcInstanceRepository(namespace string, conf *config.TencentConfig, logge return f(conf, logger) } +// 将TcInstanceRepository注册到factoryMap中 func registerRepository(namespace string, factory func(*config.TencentConfig, log.Logger) (TcInstanceRepository, error)) { factoryMap[namespace] = factory } diff --git a/pkg/instance/repository_clb.go b/pkg/instance/repository_clb.go index 9993609..8bb1dcb 100644 --- a/pkg/instance/repository_clb.go +++ b/pkg/instance/repository_clb.go @@ -7,10 +7,13 @@ import ( sdk "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317" "github.com/tencentyun/tencentcloud-exporter/pkg/client" "github.com/tencentyun/tencentcloud-exporter/pkg/config" + "net" ) func init() { + // LB_PUBLIC、LOADBALANCE实例对象是一样的 registerRepository("QCE/LB_PUBLIC", NewClbTcInstanceRepository) + registerRepository("QCE/LOADBALANCE", NewClbTcInstanceRepository) } type ClbTcInstanceRepository struct { @@ -24,13 +27,24 @@ func (repo *ClbTcInstanceRepository) GetInstanceKey() string { func (repo *ClbTcInstanceRepository) Get(id string) (instance TcInstance, err error) { req := sdk.NewDescribeLoadBalancersRequest() - req.LoadBalancerIds = []*string{&id} + + ip := net.ParseIP(id) + if ip != nil { + ipstr := ip.String() + req.LoadBalancerVips = []*string{&ipstr} + } else { + req.LoadBalancerIds = []*string{&id} + } + resp, err := repo.client.DescribeLoadBalancers(req) if err != nil { return } - if len(resp.Response.LoadBalancerSet) != 1 { - return nil, fmt.Errorf("Response instanceDetails size != 1, id=%s ", id) + + if len(resp.Response.LoadBalancerSet) == 0 { + return nil, fmt.Errorf("loadBalancer instance not found") + } else if len(resp.Response.LoadBalancerSet) > 1 { + return nil, fmt.Errorf("response instanceDetails size != 1") } meta := resp.Response.LoadBalancerSet[0] instance, err = NewClbTcInstance(id, meta) diff --git a/pkg/metric/cache.go b/pkg/metric/cache.go index 9b3a68b..553b409 100644 --- a/pkg/metric/cache.go +++ b/pkg/metric/cache.go @@ -7,6 +7,7 @@ import ( "time" ) +// 腾讯云监控指标缓存, 在TcmMetricRepository封装一层, 指标元数据使用缓存, 转发获取数据点请求 type TcmMetricCache struct { Raw TcmMetricRepository metaCache map[string]map[string]*TcmMeta //k1=namespace, k2=metricname(小写) @@ -42,6 +43,7 @@ func (c *TcmMetricCache) ListSamples(metric *TcmMetric, startTime int64, endTime return c.Raw.ListSamples(metric, startTime, endTime) } +// 检测是否需要reload缓存的数据 func (c *TcmMetricCache) checkMetaNeedreload(namespace string) (err error) { v, ok := c.metaLastReloadTime[namespace] if ok && v != 0 { @@ -55,7 +57,6 @@ func (c *TcmMetricCache) checkMetaNeedreload(namespace string) (err error) { if !ok { np = map[string]*TcmMeta{} c.metaCache[namespace] = np - } for _, meta := range metas { np[strings.ToLower(meta.MetricName)] = meta diff --git a/pkg/metric/label.go b/pkg/metric/label.go index d2aae6c..54caa18 100644 --- a/pkg/metric/label.go +++ b/pkg/metric/label.go @@ -19,13 +19,15 @@ func (l *Labels) Md5() (string, error) { return fmt.Sprintf("%x", h.Sum(jb)), nil } +// 代表一个指标的labels type TcmLabels struct { - queryLableNames []string - instanceLabelNames []string - constLabels Labels - Names []string + queryLableNames []string // 用于查询数据的条件标签 + instanceLabelNames []string // 从获取实例对象动态获取字段值的标签 + constLabels Labels // 用户自定义的常量标签 + Names []string // 所有标签名列表 } +// 根据标签名, 获取所有标签的值 func (l *TcmLabels) GetValues(filters map[string]string, ins instance.TcInstance) (values []string, err error) { nameValues := map[string]string{} for _, name := range l.queryLableNames { diff --git a/pkg/metric/meta.go b/pkg/metric/meta.go index d82f5fe..c689679 100644 --- a/pkg/metric/meta.go +++ b/pkg/metric/meta.go @@ -10,6 +10,7 @@ import ( "strings" ) +// 代表一个云监控指标的元数据 type TcmMeta struct { Id string Namespace string diff --git a/pkg/metric/metric.go b/pkg/metric/metric.go index d6a8524..a423a08 100644 --- a/pkg/metric/metric.go +++ b/pkg/metric/metric.go @@ -8,12 +8,13 @@ import ( "time" ) +// 代表一个指标, 包含多个时间线 type TcmMetric struct { Id string - Meta *TcmMeta - Labels *TcmLabels - Series map[string]*TcmSeries - StatPromDesc map[string]*prometheus.Desc + Meta *TcmMeta // 指标元数据 + Labels *TcmLabels // 指标labels + Series map[string]*TcmSeries // 包含的多个时间线 + StatPromDesc map[string]*prometheus.Desc // 按统计纬度的Desc, max、min、avg、last Conf *TcmMetricConfig } @@ -94,6 +95,7 @@ func (m TcmMetric) GetSeriesSplitByBatch(batch int) (steps [][]*TcmSeries) { return } +// 创建TcmMetric func NewTcmMetric(meta *TcmMeta, conf *TcmMetricConfig) (*TcmMetric, error) { id := fmt.Sprintf("%s-%s", meta.Namespace, meta.MetricName) diff --git a/pkg/metric/query.go b/pkg/metric/query.go index 56ffdbf..d7427af 100644 --- a/pkg/metric/query.go +++ b/pkg/metric/query.go @@ -4,6 +4,7 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// 负责一个指标的查询管理 type TcmQuery struct { Metric *TcmMetric LatestQueryStatus int diff --git a/pkg/metric/repository.go b/pkg/metric/repository.go index cfd96b3..e83f376 100644 --- a/pkg/metric/repository.go +++ b/pkg/metric/repository.go @@ -16,13 +16,15 @@ var ( timeStampFormat = "2006-01-02 15:04:05" ) +// 腾讯云监控指标Repository type TcmMetricRepository interface { + // 获取指标的元数据 GetMeta(namespace string, name string) (*TcmMeta, error) - + // 根据namespace获取所有的指标元数据 ListMetaByNamespace(namespace string) ([]*TcmMeta, error) - + // 按时间范围获取单个时间线的数据点 GetSamples(series *TcmSeries, startTime int64, endTime int64) (samples *TcmSamples, err error) - + // 按时间范围获取单个指标下所有时间线的数据点 ListSamples(metric *TcmMetric, startTime int64, endTime int64) (samplesList []*TcmSamples, err error) } diff --git a/pkg/metric/sample.go b/pkg/metric/sample.go index d6c43ec..3d6685a 100644 --- a/pkg/metric/sample.go +++ b/pkg/metric/sample.go @@ -5,11 +5,13 @@ import ( monitor "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/monitor/v20180724" ) +// 代表一个数据点 type TcmSample struct { Timestamp float64 Value float64 } +// 代表一个时间线的多个数据点 type TcmSamples struct { Series *TcmSeries Samples []*TcmSample diff --git a/pkg/metric/series.go b/pkg/metric/series.go index baec866..b1cc3a8 100644 --- a/pkg/metric/series.go +++ b/pkg/metric/series.go @@ -5,6 +5,7 @@ import ( "github.com/tencentyun/tencentcloud-exporter/pkg/instance" ) +// 代表某个指标的一个时间线 type TcmSeries struct { Id string Metric *TcmMetric