diff --git a/collector/collection_status.go b/collector/collection_status.go index 795af02c..f751cf48 100644 --- a/collector/collection_status.go +++ b/collector/collection_status.go @@ -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) } } diff --git a/collector/mongodb_collector.go b/collector/mongodb_collector.go index a16e8635..97da59cc 100644 --- a/collector/mongodb_collector.go +++ b/collector/mongodb_collector.go @@ -1,6 +1,8 @@ package collector import ( + "time" + "github.com/dcu/mongodb_exporter/shared" "github.com/golang/glog" "github.com/prometheus/client_golang/prometheus" @@ -29,6 +31,7 @@ type MongodbCollectorOpts struct { TLSHostnameValidation bool CollectReplSet bool CollectOplog bool + TailOplog bool CollectTopMetrics bool CollectDatabaseMetrics bool CollectCollectionMetrics bool @@ -36,6 +39,7 @@ type MongodbCollectorOpts struct { CollectConnPoolStats bool UserName string AuthMechanism string + SocketTimeout time.Duration } func (in MongodbCollectorOpts) toSessionOps() shared.MongoSessionOpts { @@ -47,6 +51,7 @@ func (in MongodbCollectorOpts) toSessionOps() shared.MongoSessionOpts { TLSHostnameValidation: in.TLSHostnameValidation, UserName: in.UserName, AuthMechanism: in.AuthMechanism, + SocketTimeout: in.SocketTimeout, } } @@ -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 { @@ -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) @@ -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) @@ -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 { diff --git a/collector/oplog_tail.go b/collector/oplog_tail.go new file mode 100644 index 00000000..35f57bbc --- /dev/null +++ b/collector/oplog_tail.go @@ -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 +} diff --git a/collector/replset_conf.go b/collector/replset_conf.go new file mode 100644 index 00000000..e451240d --- /dev/null +++ b/collector/replset_conf.go @@ -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 +} diff --git a/collector/server_status.go b/collector/server_status.go index a5c0eed4..bc8ee5ec 100644 --- a/collector/server_status.go +++ b/collector/server_status.go @@ -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"` @@ -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) } @@ -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) } diff --git a/collector/tcmalloc.go b/collector/tcmalloc.go new file mode 100644 index 00000000..dba74aaa --- /dev/null +++ b/collector/tcmalloc.go @@ -0,0 +1,121 @@ +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +var ( + tcmallocGeneral = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "tcmalloc_generic_heap", + Help: "High-level summary metricsInternal metrics from tcmalloc", + }, []string{"type"}) + tcmallocPageheapBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "tcmalloc_pageheap_bytes", + Help: "Sizes for tcpmalloc pageheaps", + }, []string{"type"}) + tcmallocPageheapCounts = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "tcmalloc_pageheap_count", + Help: "Sizes for tcpmalloc pageheaps", + }, []string{"type"}) + + tcmallocCacheBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "tcmalloc_cache_bytes", + Help: "Sizes for tcpmalloc caches in bytes", + }, []string{"cache", "type"}) + + tcmallocAggressiveDecommit = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: Namespace, + Name: "tcmalloc_aggressive_memory_decommit", + Help: "Whether aggressive_memory_decommit is on", + }) + + tcmallocFreeBytes = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: Namespace, + Name: "tcmalloc_free_bytes", + Help: "Total free bytes of tcmalloc", + }) +) + +// TCMallocStats tracks the mem stats metrics. +type TCMallocStats struct { + Generic GenericTCMAllocStats `bson:"generic"` + Details DetailedTCMallocStats `bson:"tcmalloc"` +} + +type GenericTCMAllocStats struct { + CurrentAllocatedBytes float64 `bson:"current_allocated_bytes"` + HeapSize float64 `bson:"heap_size"` +} + +type DetailedTCMallocStats struct { + PageheapFreeBytes float64 `bson:"pageheap_free_bytes"` + PageheapUnmappedBytes float64 `bson:"pageheap_unmapped_bytes"` + PageheapComittedBytes float64 `bson:"pageheap_committed_bytes"` + PageheapScavengeCount float64 `bson:"pageheap_scavenge_count"` + PageheapCommitCount float64 `bson:"pageheap_commit_count"` + PageheapTotalCommitBytes float64 `bson:"pageheap_total_commit_bytes"` + PageheapDecommitCount float64 `bson:"pageheap_decommit_count"` + PageheapTotalDecommitBytes float64 `bson:"pageheap_total_decommit_bytes"` + PageheapReserveCount float64 `bson:"pageheap_reserve_count"` + PageheapTotalReserveBytes float64 `bson:"pageheap_total_reserve_bytes"` + + MaxTotalThreadCacheBytes float64 `bson:"max_total_thread_cache_bytes"` + CurrentTotalThreadCacheBytes float64 `bson:"current_total_thread_cache_bytes"` + CentralCacheFreeBytes float64 `bson:"central_cache_free_bytes"` + TransferCacheFreeBytes float64 `bson:"transfer_cache_free_bytes"` + ThreadCacheFreeBytes float64 `bson:"thread_cache_free_bytes"` + + TotalFreeBytes float64 `bson:"total_free_bytes"` + AggressiveMemoryDecommit float64 `bson:"aggressive_memory_decommit"` +} + +// Export exports the data to prometheus. +func (m *TCMallocStats) Export(ch chan<- prometheus.Metric) { + // Generic metrics + tcmallocGeneral.WithLabelValues("allocated").Set(m.Generic.CurrentAllocatedBytes) + tcmallocGeneral.WithLabelValues("total").Set(m.Generic.HeapSize) + tcmallocGeneral.Collect(ch) + + // Pageheap + tcmallocPageheapBytes.WithLabelValues("free").Set(m.Details.PageheapFreeBytes) + tcmallocPageheapBytes.WithLabelValues("unmapped").Set(m.Details.PageheapUnmappedBytes) + tcmallocPageheapBytes.WithLabelValues("comitted").Set(m.Details.PageheapComittedBytes) + tcmallocPageheapBytes.WithLabelValues("total_commit").Set(m.Details.PageheapTotalCommitBytes) + tcmallocPageheapBytes.WithLabelValues("total_decommit").Set(m.Details.PageheapTotalDecommitBytes) + tcmallocPageheapBytes.WithLabelValues("total_reserve").Set(m.Details.PageheapTotalReserveBytes) + tcmallocPageheapBytes.Collect(ch) + + tcmallocPageheapCounts.WithLabelValues("scavenge").Set(m.Details.PageheapScavengeCount) + tcmallocPageheapCounts.WithLabelValues("commit").Set(m.Details.PageheapCommitCount) + tcmallocPageheapCounts.WithLabelValues("decommit").Set(m.Details.PageheapDecommitCount) + tcmallocPageheapCounts.WithLabelValues("reserve").Set(m.Details.PageheapReserveCount) + tcmallocPageheapCounts.Collect(ch) + + tcmallocCacheBytes.WithLabelValues("thread_cache", "max_total").Set(m.Details.MaxTotalThreadCacheBytes) + tcmallocCacheBytes.WithLabelValues("thread_cache", "current_total").Set(m.Details.CurrentTotalThreadCacheBytes) + tcmallocCacheBytes.WithLabelValues("central_cache", "free").Set(m.Details.CentralCacheFreeBytes) + tcmallocCacheBytes.WithLabelValues("transfer_cache", "free").Set(m.Details.TransferCacheFreeBytes) + tcmallocCacheBytes.WithLabelValues("thread_cache", "free").Set(m.Details.ThreadCacheFreeBytes) + tcmallocCacheBytes.Collect(ch) + + tcmallocAggressiveDecommit.Set(m.Details.AggressiveMemoryDecommit) + tcmallocAggressiveDecommit.Collect(ch) + + tcmallocFreeBytes.Set(m.Details.TotalFreeBytes) + tcmallocFreeBytes.Collect(ch) + +} + +// Describe describes the metrics for prometheus +func (m *TCMallocStats) Describe(ch chan<- *prometheus.Desc) { + tcmallocGeneral.Describe(ch) + tcmallocPageheapBytes.Describe(ch) + tcmallocPageheapCounts.Describe(ch) + tcmallocCacheBytes.Describe(ch) + tcmallocAggressiveDecommit.Describe(ch) + tcmallocFreeBytes.Describe(ch) +} diff --git a/glide.lock b/glide.lock index f7fe5f54..2699fcb2 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 7dc238d7118210ebe55b508ed1d11af8c39132025807b9cddc2ec2489d9926f6 -updated: 2016-11-23T09:05:11.556107146-08:00 +hash: 2daa265ce1037e5ac801ef074714e212b1ff69f2fea2e5c69a6c05ece9326f31 +updated: 2018-03-15T17:01:48.086832728-07:00 imports: - name: github.com/beorn7/perks version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 @@ -8,7 +8,7 @@ imports: - name: github.com/golang/glog version: 23def4e6c14b4da8ac2ed8007337bc5eb5007998 - name: github.com/golang/protobuf - version: 8ee79997227bf9b34611aee7946ae64735e6fd93 + version: 17ce1425424ab154092bbb43af630bd647f3bb0d subpackages: - proto - name: github.com/matttproud/golang_protobuf_extensions @@ -20,22 +20,29 @@ imports: subpackages: - prometheus - name: github.com/prometheus/client_model - version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6 + version: 6f3806018612930941127f2a7c6c453ba2c527d2 subpackages: - go - name: github.com/prometheus/common - version: 0d5de9d6d8629cb8bee6d4674da4127cd8b615a3 + version: e3fb1a1acd7605367a2b378bc2e2f893c05174b7 subpackages: - expfmt - - model - internal/bitbucket.org/ww/goautoneg + - model - name: github.com/prometheus/procfs - version: abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 + version: a6e9df898b1336106c743392c48ee0b71f5c4efa + subpackages: + - xfs +- name: github.com/rwynn/gtm + version: 495abc277593067479c3c528864191804ab04cf7 + repo: https://github.com/jacksontj/gtm.git +- name: github.com/serialx/hashring + version: 6a9381c5a83e926b9f1fd907395a581e69747e96 - name: gopkg.in/mgo.v2 version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 subpackages: - bson + - internal/json - internal/sasl - internal/scram - - internal/json testImports: [] diff --git a/glide.yaml b/glide.yaml index 17134852..63ca8349 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,3 +8,6 @@ import: - package: gopkg.in/mgo.v2 subpackages: - bson +- package: github.com/rwynn/gtm + version: 495abc277593067479c3c528864191804ab04cf7 + repo: https://github.com/jacksontj/gtm.git diff --git a/mongodb_exporter.go b/mongodb_exporter.go index b69fa7be..9d0607fa 100644 --- a/mongodb_exporter.go +++ b/mongodb_exporter.go @@ -50,12 +50,14 @@ var ( mongodbUserName = flag.String("mongodb.username", "", "Username to connect to Mongodb") mongodbAuthMechanism = flag.String("mongodb.mechanism", "", "auth mechanism to connect to Mongodb (ie: MONGODB-X509)") mongodbCollectOplog = flag.Bool("mongodb.collect.oplog", true, "collect Mongodb Oplog status") + mongodbCollectOplogTail = flag.Bool("mongodb.collect.oplog_tail", false, "tail Mongodb Oplog to get stats") mongodbCollectReplSet = flag.Bool("mongodb.collect.replset", true, "collect Mongodb replica set status") mongodbCollectTopMetrics = flag.Bool("mongodb.collect.top", false, "collect Mongodb Top metrics") mongodbCollectDatabaseMetrics = flag.Bool("mongodb.collect.database", false, "collect MongoDB database metrics") mongodbCollectCollectionMetrics = flag.Bool("mongodb.collect.collection", false, "Collect MongoDB collection metrics") mongodbCollectProfileMetrics = flag.Bool("mongodb.collect.profile", false, "Collect MongoDB profile metrics") mongodbCollectConnPoolStats = flag.Bool("mongodb.collect.connpoolstats", false, "Collect MongoDB connpoolstats") + mongodbSocketTimeout = flag.Duration("mongodb.socket-timeout", 0, "timeout for socket operations to mongodb") version = flag.Bool("version", false, "Print mongodb_exporter version") ) @@ -152,6 +154,7 @@ func registerCollector() { TLSCaFile: *mongodbTLSCa, TLSHostnameValidation: !(*mongodbTLSDisableHostnameValidation), CollectOplog: *mongodbCollectOplog, + TailOplog: *mongodbCollectOplogTail, CollectReplSet: *mongodbCollectReplSet, CollectTopMetrics: *mongodbCollectTopMetrics, CollectDatabaseMetrics: *mongodbCollectDatabaseMetrics, @@ -160,6 +163,7 @@ func registerCollector() { CollectConnPoolStats: *mongodbCollectConnPoolStats, UserName: *mongodbUserName, AuthMechanism: *mongodbAuthMechanism, + SocketTimeout: *mongodbSocketTimeout, }) prometheus.MustRegister(mongodbCollector) } diff --git a/shared/connection.go b/shared/connection.go index 6dbe71c3..c51fbd0c 100644 --- a/shared/connection.go +++ b/shared/connection.go @@ -26,6 +26,7 @@ type MongoSessionOpts struct { TLSHostnameValidation bool UserName string AuthMechanism string + SocketTimeout time.Duration } // MongoSession creates a Mongo session @@ -55,7 +56,7 @@ func MongoSession(opts MongoSessionOpts) *mgo.Session { } session.SetMode(mgo.Eventual, true) session.SetSyncTimeout(syncMongodbTimeout) - session.SetSocketTimeout(0) + session.SetSocketTimeout(opts.SocketTimeout) return session }