Skip to content

Commit

Permalink
Merge pull request dcu#87 from jacksontj/master
Browse files Browse the repository at this point in the history
Add replsetConf metrics
  • Loading branch information
dcu authored May 22, 2018
2 parents e755a44 + 733087c commit 8f53431
Show file tree
Hide file tree
Showing 10 changed files with 414 additions and 10 deletions.
2 changes: 1 addition & 1 deletion collector/collection_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func CollectCollectionStatus(session *mgo.Session, db string, ch chan<- promethe
for _, collection_name := range collection_names {
collStats := GetCollectionStatus(session, db, collection_name)
if collStats != nil {
glog.Infof("exporting Database Metrics for db=%q, table=%q", db, collection_name)
glog.V(1).Infof("exporting Database Metrics for db=%q, table=%q", db, collection_name)
collStats.Export(ch)
}
}
Expand Down
34 changes: 34 additions & 0 deletions collector/mongodb_collector.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package collector

import (
"time"

"github.com/dcu/mongodb_exporter/shared"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -29,13 +31,15 @@ type MongodbCollectorOpts struct {
TLSHostnameValidation bool
CollectReplSet bool
CollectOplog bool
TailOplog bool
CollectTopMetrics bool
CollectDatabaseMetrics bool
CollectCollectionMetrics bool
CollectProfileMetrics bool
CollectConnPoolStats bool
UserName string
AuthMechanism string
SocketTimeout time.Duration
}

func (in MongodbCollectorOpts) toSessionOps() shared.MongoSessionOpts {
Expand All @@ -47,6 +51,7 @@ func (in MongodbCollectorOpts) toSessionOps() shared.MongoSessionOpts {
TLSHostnameValidation: in.TLSHostnameValidation,
UserName: in.UserName,
AuthMechanism: in.AuthMechanism,
SocketTimeout: in.SocketTimeout,
}
}

Expand All @@ -68,6 +73,7 @@ func NewMongodbCollector(opts MongodbCollectorOpts) *MongodbCollector {
func (exporter *MongodbCollector) Describe(ch chan<- *prometheus.Desc) {
(&ServerStatus{}).Describe(ch)
(&ReplSetStatus{}).Describe(ch)
(&ReplSetConf{}).Describe(ch)
(&DatabaseStatus{}).Describe(ch)

if exporter.Opts.CollectTopMetrics {
Expand All @@ -88,12 +94,18 @@ func (exporter *MongodbCollector) Collect(ch chan<- prometheus.Metric) {
if exporter.Opts.CollectReplSet {
glog.Info("Collecting ReplSet Status")
exporter.collectReplSetStatus(mongoSess, ch)
exporter.collectReplSetConf(mongoSess, ch)
}
if exporter.Opts.CollectOplog {
glog.Info("Collecting Oplog Status")
exporter.collectOplogStatus(mongoSess, ch)
}

if exporter.Opts.TailOplog {
glog.Info("Collecting Oplog Tail Stats")
exporter.collectOplogTailStats(mongoSess, ch)
}

if exporter.Opts.CollectTopMetrics {
glog.Info("Collecting Top Metrics")
exporter.collectTopStatus(mongoSess, ch)
Expand Down Expand Up @@ -145,6 +157,17 @@ func (exporter *MongodbCollector) collectReplSetStatus(session *mgo.Session, ch
return replSetStatus
}

func (exporter *MongodbCollector) collectReplSetConf(session *mgo.Session, ch chan<- prometheus.Metric) *ReplSetConf {
replSetConf := GetReplSetConf(session)

if replSetConf != nil {
glog.Info("exporting ReplSetConf Metrics")
replSetConf.Export(ch)
}

return replSetConf
}

func (exporter *MongodbCollector) collectOplogStatus(session *mgo.Session, ch chan<- prometheus.Metric) *OplogStatus {
oplogStatus := GetOplogStatus(session)

Expand All @@ -156,6 +179,17 @@ func (exporter *MongodbCollector) collectOplogStatus(session *mgo.Session, ch ch
return oplogStatus
}

func (exporter *MongodbCollector) collectOplogTailStats(session *mgo.Session, ch chan<- prometheus.Metric) *OplogTailStats {
oplogTailStats := GetOplogTailStats(session)

if oplogTailStats != nil {
glog.Info("exporting oplogTailStats Metrics")
oplogTailStats.Export(ch)
}

return oplogTailStats
}

func (exporter *MongodbCollector) collectTopStatus(session *mgo.Session, ch chan<- prometheus.Metric) *TopStatus {
topStatus := GetTopStatus(session)
if topStatus != nil {
Expand Down
83 changes: 83 additions & 0 deletions collector/oplog_tail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package collector

import (
"time"

"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"github.com/rwynn/gtm"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)

var (
oplogEntryCount = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: "oplogtail",
Name: "entry_count",
Help: "The total number of entries observed in the oplog by ns/op",
}, []string{"ns", "op"})
oplogTailError = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: "oplogtail",
Name: "tail_error",
Help: "The total number of errors while tailing the oplog",
})
)

var tailer *OplogTailStats

type OplogTailStats struct{}

func (o *OplogTailStats) Start(session *mgo.Session) {
// Override the socket timeout for oplog tailing
// Here we want a long-running socket, otherwise we cause lots of locks
// which seriously impede oplog performance
timeout := time.Second * 120
session.SetSocketTimeout(timeout)
// Set cursor timeout
var tmp map[string]interface{}
session.Run(bson.D{{"setParameter", 1}, {"cursorTimeoutMillis", timeout / time.Millisecond}}, &tmp)

defer session.Close()
session.SetMode(mgo.Monotonic, true)

ctx := gtm.Start(session, nil)
defer ctx.Stop()

// ctx.OpC is a channel to read ops from
// ctx.ErrC is a channel to read errors from
// ctx.Stop() stops all go routines started by gtm.Start
for {
// loop forever receiving events
select {
case err := <-ctx.ErrC:
oplogTailError.Add(1)
glog.Errorf("Error getting entry from oplog: %v", err)
case op := <-ctx.OpC:
oplogEntryCount.WithLabelValues(op.Namespace, op.Operation).Add(1)
}
}
}

// Export exports metrics to Prometheus
func (status *OplogTailStats) Export(ch chan<- prometheus.Metric) {
oplogEntryCount.Collect(ch)
oplogTailError.Collect(ch)
}

// Describe describes metrics collected
func (status *OplogTailStats) Describe(ch chan<- *prometheus.Desc) {
oplogEntryCount.Describe(ch)
oplogTailError.Describe(ch)
}

func GetOplogTailStats(session *mgo.Session) *OplogTailStats {
if tailer == nil {
tailer = &OplogTailStats{}
// Start a tailer with a copy of the session (to avoid messing with the other metrics in the session)
go tailer.Start(session.Copy())
}

return tailer
}
144 changes: 144 additions & 0 deletions collector/replset_conf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package collector

import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"

"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
)

var (
memberHidden = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "member_hidden",
Help: "This field conveys if the member is hidden (1) or not-hidden (0).",
}, []string{"id", "host"})
memberArbiter = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "member_arbiter",
Help: "This field conveys if the member is an arbiter (1) or not (0).",
}, []string{"id", "host"})
memberBuildIndexes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "member_build_indexes",
Help: "This field conveys if the member is builds indexes (1) or not (0).",
}, []string{"id", "host"})
memberPriority = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "member_priority",
Help: "This field conveys the priority of a given member",
}, []string{"id", "host"})
memberVotes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "member_votes",
Help: "This field conveys the number of votes of a given member",
}, []string{"id", "host"})
)

// Although the docs say that it returns a map with id etc. it *actually* returns
// that wrapped in a map
type OuterReplSetConf struct {
Config ReplSetConf `bson:"config"`
}

// ReplSetConf keeps the data returned by the GetReplSetConf method
type ReplSetConf struct {
Id string `bson:"_id"`
Version int `bson:"version"`
Members []MemberConf `bson:"members"`
}

/*
Example:
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 5000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}
*/
type ReplSetConfSettings struct {
}

// Member represents an array element of ReplSetConf.Members
type MemberConf struct {
Id int32 `bson:"_id"`
Host string `bson:"host"`
ArbiterOnly bool `bson:"arbiterOnly"`
BuildIndexes bool `bson:"buildIndexes"`
Hidden bool `bson:"hidden"`
Priority int32 `bson:"priority"`

Tags map[string]string `bson:"tags"`
SlaveDelay float64 `bson:"saveDelay"`
Votes int32 `bson:"votes"`
}

// Export exports the replSetGetStatus stati to be consumed by prometheus
func (replConf *ReplSetConf) Export(ch chan<- prometheus.Metric) {
for _, member := range replConf.Members {
ls := prometheus.Labels{
"id": replConf.Id,
"host": member.Host,
}
if member.Hidden {
memberHidden.With(ls).Set(1)
} else {
memberHidden.With(ls).Set(0)
}

if member.ArbiterOnly {
memberArbiter.With(ls).Set(1)
} else {
memberArbiter.With(ls).Set(0)
}

if member.BuildIndexes {
memberBuildIndexes.With(ls).Set(1)
} else {
memberBuildIndexes.With(ls).Set(0)
}

memberPriority.With(ls).Set(float64(member.Priority))
memberVotes.With(ls).Set(float64(member.Votes))
}
// collect metrics
memberHidden.Collect(ch)
memberArbiter.Collect(ch)
memberBuildIndexes.Collect(ch)
memberPriority.Collect(ch)
memberVotes.Collect(ch)
}

// Describe describes the replSetGetStatus metrics for prometheus
func (replConf *ReplSetConf) Describe(ch chan<- *prometheus.Desc) {
memberHidden.Describe(ch)
memberArbiter.Describe(ch)
memberBuildIndexes.Describe(ch)
memberPriority.Describe(ch)
memberVotes.Describe(ch)
}

// GetReplSetConf returns the replica status info
func GetReplSetConf(session *mgo.Session) *ReplSetConf {
result := &OuterReplSetConf{}
err := session.DB("admin").Run(bson.D{{"replSetGetConfig", 1}}, result)
if err != nil {
glog.Error("Failed to get replSet config.")
return nil
}
return &result.Config
}
7 changes: 7 additions & 0 deletions collector/server_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type ServerStatus struct {

Opcounters *OpcountersStats `bson:"opcounters"`
OpcountersRepl *OpcountersReplStats `bson:"opcountersRepl"`
TCMallocStats *TCMallocStats `bson:"tcmalloc"`
Mem *MemStats `bson:"mem"`
Metrics *MetricsStats `bson:"metrics"`

Expand Down Expand Up @@ -104,6 +105,9 @@ func (status *ServerStatus) Export(ch chan<- prometheus.Metric) {
if status.OpcountersRepl != nil {
status.OpcountersRepl.Export(ch)
}
if status.TCMallocStats != nil {
status.TCMallocStats.Export(ch)
}
if status.Mem != nil {
status.Mem.Export(ch)
}
Expand Down Expand Up @@ -168,6 +172,9 @@ func (status *ServerStatus) Describe(ch chan<- *prometheus.Desc) {
if status.OpcountersRepl != nil {
status.OpcountersRepl.Describe(ch)
}
if status.TCMallocStats != nil {
status.TCMallocStats.Describe(ch)
}
if status.Mem != nil {
status.Mem.Describe(ch)
}
Expand Down
Loading

0 comments on commit 8f53431

Please sign in to comment.