1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
package collector
import (
"time"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var (
oplogStatusCount = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: "replset_oplog",
Name: "items_total",
Help: "The total number of changes in the oplog",
})
oplogStatusHeadTimestamp = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: "replset_oplog",
Name: "head_timestamp",
Help: "The timestamp of the newest change in the oplog",
})
oplogStatusTailTimestamp = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: "replset_oplog",
Name: "tail_timestamp",
Help: "The timestamp of the oldest change in the oplog",
})
oplogStatusSizeBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: "replset_oplog",
Name: "size_bytes",
Help: "Size of oplog in bytes",
}, []string{"type"})
)
// OplogCollectionStats represents metrics about an oplog collection
type OplogCollectionStats struct {
Count float64 `bson:"count"`
Size float64 `bson:"size"`
StorageSize float64 `bson:"storageSize"`
}
// OplogStatus represents oplog metrics
type OplogStatus struct {
TailTimestamp float64
HeadTimestamp float64
CollectionStats *OplogCollectionStats
}
// BsonMongoTimestampToUnix converts a mongo timestamp to UNIX time
// there's gotta be a better way to do this, but it works for now :/
func BsonMongoTimestampToUnix(timestamp bson.MongoTimestamp) float64 {
return float64(timestamp >> 32)
}
// GetOplogTimestamp fetches the latest oplog timestamp
func GetOplogTimestamp(session *mgo.Session, returnTail bool) (float64, error) {
sortBy := "$natural"
if returnTail {
sortBy = "-$natural"
}
var (
err error
tries int
result struct {
Timestamp bson.MongoTimestamp `bson:"ts"`
}
)
maxTries := 2
for tries < maxTries {
err = session.DB("local").C("oplog.rs").Find(nil).Sort(sortBy).Limit(1).One(&result)
if err != nil {
tries++
time.Sleep(500 * time.Millisecond)
} else {
return BsonMongoTimestampToUnix(result.Timestamp), err
}
}
return 0, err
}
// GetOplogCollectionStats fetches oplog collection stats
func GetOplogCollectionStats(session *mgo.Session) (*OplogCollectionStats, error) {
results := &OplogCollectionStats{}
err := session.DB("local").Run(bson.M{"collStats": "oplog.rs"}, &results)
return results, err
}
// Export exports metrics to Prometheus
func (status *OplogStatus) Export(ch chan<- prometheus.Metric) {
oplogStatusSizeBytes.WithLabelValues("current").Set(0)
oplogStatusSizeBytes.WithLabelValues("storage").Set(0)
if status.CollectionStats != nil {
oplogStatusCount.Set(status.CollectionStats.Count)
oplogStatusSizeBytes.WithLabelValues("current").Set(status.CollectionStats.Size)
oplogStatusSizeBytes.WithLabelValues("storage").Set(status.CollectionStats.StorageSize)
}
if status.HeadTimestamp != 0 && status.TailTimestamp != 0 {
oplogStatusHeadTimestamp.Set(status.HeadTimestamp)
oplogStatusTailTimestamp.Set(status.TailTimestamp)
}
oplogStatusCount.Collect(ch)
oplogStatusHeadTimestamp.Collect(ch)
oplogStatusTailTimestamp.Collect(ch)
oplogStatusSizeBytes.Collect(ch)
}
// Describe describes metrics collected
func (status *OplogStatus) Describe(ch chan<- *prometheus.Desc) {
oplogStatusCount.Describe(ch)
oplogStatusHeadTimestamp.Describe(ch)
oplogStatusTailTimestamp.Describe(ch)
oplogStatusSizeBytes.Describe(ch)
}
// GetOplogStatus fetches oplog collection stats
func GetOplogStatus(session *mgo.Session) *OplogStatus {
oplogStatus := &OplogStatus{}
collectionStats, err := GetOplogCollectionStats(session)
if err != nil {
glog.Error("Failed to get local.oplog_rs collection stats.")
return nil
}
headTimestamp, err := GetOplogTimestamp(session, false)
tailTimestamp, err := GetOplogTimestamp(session, true)
if err != nil {
glog.Error("Failed to get oplog head or tail timestamps.")
return nil
}
oplogStatus.CollectionStats = collectionStats
oplogStatus.HeadTimestamp = headTimestamp
oplogStatus.TailTimestamp = tailTimestamp
return oplogStatus
}
|