forked from dcu/mongodb_exporter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request dcu#87 from jacksontj/master
Add replsetConf metrics
- Loading branch information
Showing
10 changed files
with
414 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.