ceph_exporter/ceph/exporter.go

146 lines
3.9 KiB
Go

// Copyright 2022 DigitalOcean
//
// 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 ceph
import (
"encoding/json"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
)
// Exporter wraps all the ceph collectors and provides a single global
// exporter to extracts metrics out of. It also ensures that the collection
// is done in a thread-safe manner, the necessary requirement stated by
// prometheus. It also implements a prometheus.Collector interface in order
// to register it correctly.
type Exporter struct {
mu sync.Mutex
Conn Conn
Cluster string
Config string
RgwMode int
Logger *logrus.Logger
Version *Version
}
// NewExporter returns an initialized *Exporter
// We can choose to enable a collector to extract stats out of by adding it to the list of collectors.
func NewExporter(conn Conn, cluster string, config string, rgwMode int, logger *logrus.Logger) *Exporter {
return &Exporter{
Conn: conn,
Cluster: cluster,
Config: config,
RgwMode: rgwMode,
Logger: logger,
}
}
func (exporter *Exporter) getCollectors() []prometheus.Collector {
standardCollectors := []prometheus.Collector{
NewClusterUsageCollector(exporter),
NewPoolUsageCollector(exporter),
NewPoolInfoCollector(exporter),
NewClusterHealthCollector(exporter),
NewMonitorCollector(exporter),
NewOSDCollector(exporter),
NewCrashesCollector(exporter),
}
switch exporter.RgwMode {
case RGWModeForeground:
standardCollectors = append(standardCollectors, NewRGWCollector(exporter, false))
case RGWModeBackground:
standardCollectors = append(standardCollectors, NewRGWCollector(exporter, true))
case RGWModeDisabled:
// nothing to do
default:
exporter.Logger.WithField("RgwMode", exporter.RgwMode).Warn("RGW collector disabled due to invalid mode")
}
return standardCollectors
}
func (exporter *Exporter) cephVersionCmd() []byte {
cmd, err := json.Marshal(map[string]interface{}{
"prefix": "version",
"format": "json",
})
if err != nil {
exporter.Logger.WithError(err).Panic("failed to marshal ceph version command")
}
return cmd
}
func (exporter *Exporter) setCephVersion() error {
buf, _, err := exporter.Conn.MonCommand(exporter.cephVersionCmd())
if err != nil {
return err
}
cephVersion := &struct {
Version string `json:"Version"`
}{}
err = json.Unmarshal(buf, cephVersion)
if err != nil {
return err
}
parsedVersion, err := ParseCephVersion(cephVersion.Version)
if err != nil {
exporter.Logger.Info("version " + cephVersion.Version)
return err
}
exporter.Version = parsedVersion
return nil
}
// Describe sends all the descriptors of the collectors included to
// the provided channel.
func (exporter *Exporter) Describe(ch chan<- *prometheus.Desc) {
err := exporter.setCephVersion()
if err != nil {
exporter.Logger.WithError(err).Error("failed to set ceph Version")
return
}
for _, cc := range exporter.getCollectors() {
cc.Describe(ch)
}
}
// Collect sends the collected metrics from each of the collectors to
// prometheus. Collect could be called several times concurrently
// and thus its run is protected by a single mutex.
func (exporter *Exporter) Collect(ch chan<- prometheus.Metric) {
exporter.mu.Lock()
defer exporter.mu.Unlock()
err := exporter.setCephVersion()
if err != nil {
exporter.Logger.WithError(err).Error("failed to set ceph Version")
return
}
for _, cc := range exporter.getCollectors() {
cc.Collect(ch)
}
}