Skip to content

Commit 0417aba

Browse files
committed
POC of server status poller
1 parent 345f757 commit 0417aba

2 files changed

Lines changed: 769 additions & 0 deletions

File tree

main.go

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
// Copyright 2018, OpenCensus Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"log"
20+
"time"
21+
22+
"contrib.go.opencensus.io/exporter/stackdriver"
23+
"go.opencensus.io/stats/view"
24+
"go.opencensus.io/trace"
25+
26+
"github.com/mongodb/mongo-go-driver/bson"
27+
"github.com/mongodb/mongo-go-driver/mongo"
28+
29+
"github.com/orijtech/otils"
30+
)
31+
32+
func main() {
33+
flushFn, err := enableOpenCensus()
34+
if err != nil {
35+
log.Fatalf("Failed to enable OpenCensus: %v", err)
36+
}
37+
defer flushFn()
38+
39+
mongoURI := otils.EnvOrAlternates("MONGO_SERVER_URI", "localhost:27017")
40+
mc, err := mongo.NewClient("mongodb://" + mongoURI)
41+
if err != nil {
42+
log.Fatalf("Failed to create MongoDB client: %v", err)
43+
}
44+
if err := mc.Connect(context.Background()); err != nil {
45+
log.Fatalf("Failed to connect to the MongoDB server: %v", err)
46+
}
47+
defer mc.Disconnect(context.Background())
48+
49+
db := mc.Database("test")
50+
blob, err := db.RunCommand(context.Background(), bson.NewDocument(bson.EC.Int32("serverStatus", 1)))
51+
if err != nil {
52+
log.Fatalf(`Failed to run "serverStatus": %v`, err)
53+
}
54+
ss := new(ServerStatus)
55+
if err := bson.Unmarshal(blob, ss); err != nil {
56+
log.Fatalf("Failed to unmarshal ServerStatus: %v", err)
57+
}
58+
log.Printf("ss: %+v\n\n", ss.RecordStats)
59+
60+
ss.recordStats(context.Background())
61+
62+
<-time.After(250 * time.Millisecond)
63+
}
64+
65+
func enableOpenCensus() (func(), error) {
66+
if err := view.Register(allViews...); err != nil {
67+
return nil, err
68+
}
69+
sd, err := stackdriver.NewExporter(stackdriver.Options{
70+
ProjectID: otils.EnvOrAlternates("MONGOSTATUSD_PROJECTID", "census-demos"),
71+
MetricPrefix: otils.EnvOrAlternates("MONGOSTATUSD_METRIC_PREFIX", "mongostatusd"),
72+
})
73+
if err != nil {
74+
return nil, err
75+
}
76+
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
77+
trace.RegisterExporter(sd)
78+
view.RegisterExporter(sd)
79+
view.SetReportingPeriod(150 * time.Millisecond)
80+
return sd.Flush, nil
81+
}
82+
83+
// The content from here on below is copied from https://github.com/mongodb/mongo/blob/30aded8889e2806aa22d0d4fcfb6314b07074771/src/mongo/gotools/mongostat/status/server_status.go
84+
//
85+
// Copyright (C) MongoDB, Inc. 2014-present.
86+
//
87+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
88+
// not use this file except in compliance with the License. You may obtain
89+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
90+
91+
type ServerStatus struct {
92+
SampleTime time.Time `bson:""`
93+
Flattened map[string]interface{} `bson:""`
94+
Host string `bson:"host"`
95+
Version string `bson:"version"`
96+
Process string `bson:"process"`
97+
Pid int64 `bson:"pid"`
98+
Uptime int64 `bson:"uptime"`
99+
UptimeMillis int64 `bson:"uptimeMillis"`
100+
UptimeEstimate int64 `bson:"uptimeEstimate"`
101+
LocalTime time.Time `bson:"localTime"`
102+
Asserts map[string]int64 `bson:"asserts"`
103+
BackgroundFlushing *FlushStats `bson:"backgroundFlushing"`
104+
ExtraInfo *ExtraInfo `bson:"extra_info"`
105+
Connections *ConnectionStats `bson:"connections"`
106+
Dur *DurStats `bson:"dur"`
107+
GlobalLock *GlobalLockStats `bson:"globalLock"`
108+
Locks map[string]LockStats `bson:"locks,omitempty"`
109+
Network *NetworkStats `bson:"network"`
110+
Opcounters *OpcountStats `bson:"opcounters"`
111+
OpcountersRepl *OpcountStats `bson:"opcountersRepl"`
112+
RecordStats *DBRecordStats `bson:"recordStats"`
113+
Mem *MemStats `bson:"mem"`
114+
Repl *ReplStatus `bson:"repl"`
115+
ShardCursorType map[string]interface{} `bson:"shardCursorType"`
116+
StorageEngine map[string]string `bson:"storageEngine"`
117+
WiredTiger *WiredTiger `bson:"wiredTiger"`
118+
}
119+
120+
// WiredTiger stores information related to the WiredTiger storage engine.
121+
type WiredTiger struct {
122+
Transaction TransactionStats `bson:"transaction"`
123+
Concurrent ConcurrentTransactions `bson:"concurrentTransactions"`
124+
Cache CacheStats `bson:"cache"`
125+
}
126+
127+
type ConcurrentTransactions struct {
128+
Write ConcurrentTransStats `bson:"write"`
129+
Read ConcurrentTransStats `bson:"read"`
130+
}
131+
132+
type ConcurrentTransStats struct {
133+
Out int64 `bson:"out"`
134+
}
135+
136+
// CacheStats stores cache statistics for WiredTiger.
137+
type CacheStats struct {
138+
TrackedDirtyBytes int64 `bson:"tracked dirty bytes in the cache"`
139+
CurrentCachedBytes int64 `bson:"bytes currently in the cache"`
140+
MaxBytesConfigured int64 `bson:"maximum bytes configured"`
141+
}
142+
143+
// TransactionStats stores transaction checkpoints in WiredTiger.
144+
type TransactionStats struct {
145+
TransCheckpoints int64 `bson:"transaction checkpoints"`
146+
}
147+
148+
// ReplStatus stores data related to replica sets.
149+
type ReplStatus struct {
150+
SetName string `bson:"setName"`
151+
IsMaster interface{} `bson:"ismaster"`
152+
Secondary interface{} `bson:"secondary"`
153+
IsReplicaSet interface{} `bson:"isreplicaset"`
154+
ArbiterOnly interface{} `bson:"arbiterOnly"`
155+
Hosts []string `bson:"hosts"`
156+
Passives []string `bson:"passives"`
157+
Me string `bson:"me"`
158+
}
159+
160+
// DBRecordStats stores data related to memory operations across databases.
161+
type DBRecordStats struct {
162+
AccessesNotInMemory int64 `bson:"accessesNotInMemory"`
163+
PageFaultExceptionsThrown int64 `bson:"pageFaultExceptionsThrown"`
164+
DBRecordAccesses map[string]RecordAccesses `bson:",inline"`
165+
}
166+
167+
// RecordAccesses stores data related to memory operations scoped to a database.
168+
type RecordAccesses struct {
169+
AccessesNotInMemory int64 `bson:"accessesNotInMemory"`
170+
PageFaultExceptionsThrown int64 `bson:"pageFaultExceptionsThrown"`
171+
}
172+
173+
// MemStats stores data related to memory statistics.
174+
type MemStats struct {
175+
Bits int64 `bson:"bits"`
176+
Resident int64 `bson:"resident"`
177+
Virtual int64 `bson:"virtual"`
178+
Supported interface{} `bson:"supported"`
179+
Mapped int64 `bson:"mapped"`
180+
MappedWithJournal int64 `bson:"mappedWithJournal"`
181+
}
182+
183+
// FlushStats stores information about memory flushes.
184+
type FlushStats struct {
185+
Flushes int64 `bson:"flushes"`
186+
TotalMs int64 `bson:"total_ms"`
187+
AverageMs float64 `bson:"average_ms"`
188+
LastMs int64 `bson:"last_ms"`
189+
LastFinished time.Time `bson:"last_finished"`
190+
}
191+
192+
// ConnectionStats stores information related to incoming database connections.
193+
type ConnectionStats struct {
194+
Current int64 `bson:"current"`
195+
Available int64 `bson:"available"`
196+
TotalCreated int64 `bson:"totalCreated"`
197+
}
198+
199+
// DurTiming stores information related to journaling.
200+
type DurTiming struct {
201+
Dt int64 `bson:"dt"`
202+
PrepLogBuffer int64 `bson:"prepLogBuffer"`
203+
WriteToJournal int64 `bson:"writeToJournal"`
204+
WriteToDataFiles int64 `bson:"writeToDataFiles"`
205+
RemapPrivateView int64 `bson:"remapPrivateView"`
206+
}
207+
208+
// DurStats stores information related to journaling statistics.
209+
type DurStats struct {
210+
Commits int64 `bson:"commits"`
211+
JournaledMB int64 `bson:"journaledMB"`
212+
WriteToDataFilesMB int64 `bson:"writeToDataFilesMB"`
213+
Compression int64 `bson:"compression"`
214+
CommitsInWriteLock int64 `bson:"commitsInWriteLock"`
215+
EarlyCommits int64 `bson:"earlyCommits"`
216+
TimeMs DurTiming
217+
}
218+
219+
// QueueStats stores the number of queued read/write operations.
220+
type QueueStats struct {
221+
Total int64 `bson:"total"`
222+
Readers int64 `bson:"readers"`
223+
Writers int64 `bson:"writers"`
224+
}
225+
226+
// ClientStats stores the number of active read/write operations.
227+
type ClientStats struct {
228+
Total int64 `bson:"total"`
229+
Readers int64 `bson:"readers"`
230+
Writers int64 `bson:"writers"`
231+
}
232+
233+
// GlobalLockStats stores information related locks in the MMAP storage engine.
234+
type GlobalLockStats struct {
235+
TotalTime int64 `bson:"totalTime"`
236+
LockTime int64 `bson:"lockTime"`
237+
CurrentQueue *QueueStats `bson:"currentQueue"`
238+
ActiveClients *ClientStats `bson:"activeClients"`
239+
}
240+
241+
// NetworkStats stores information related to network traffic.
242+
type NetworkStats struct {
243+
BytesIn int64 `bson:"bytesIn"`
244+
BytesOut int64 `bson:"bytesOut"`
245+
NumRequests int64 `bson:"numRequests"`
246+
}
247+
248+
// OpcountStats stores information related to comamnds and basic CRUD operations.
249+
type OpcountStats struct {
250+
Insert int64 `bson:"insert"`
251+
Query int64 `bson:"query"`
252+
Update int64 `bson:"update"`
253+
Delete int64 `bson:"delete"`
254+
GetMore int64 `bson:"getmore"`
255+
Command int64 `bson:"command"`
256+
}
257+
258+
// ReadWriteLockTimes stores time spent holding read/write locks.
259+
type ReadWriteLockTimes struct {
260+
Read int64 `bson:"R"`
261+
Write int64 `bson:"W"`
262+
ReadLower int64 `bson:"r"`
263+
WriteLower int64 `bson:"w"`
264+
}
265+
266+
// LockStats stores information related to time spent acquiring/holding locks
267+
// for a given database.
268+
type LockStats struct {
269+
TimeLockedMicros ReadWriteLockTimes `bson:"timeLockedMicros"`
270+
TimeAcquiringMicros ReadWriteLockTimes `bson:"timeAcquiringMicros"`
271+
272+
// AcquireCount and AcquireWaitCount are new fields of the lock stats only populated on 3.0 or newer.
273+
// Typed as a pointer so that if it is nil, mongostat can assume the field is not populated
274+
// with real namespace data.
275+
AcquireCount *ReadWriteLockTimes `bson:"acquireCount,omitempty"`
276+
AcquireWaitCount *ReadWriteLockTimes `bson:"acquireWaitCount,omitempty"`
277+
}
278+
279+
// ExtraInfo stores additional platform specific information.
280+
type ExtraInfo struct {
281+
PageFaults *int64 `bson:"page_faults"`
282+
}
283+
284+
// NodeError pairs an error with a hostname
285+
type NodeError struct {
286+
Host string
287+
err error
288+
}
289+
290+
func (ne *NodeError) Error() string {
291+
return ne.err.Error()
292+
}
293+
294+
func NewNodeError(host string, err error) *NodeError {
295+
return &NodeError{
296+
err: err,
297+
Host: host,
298+
}
299+
}
300+
301+
// Flatten takes a map and returns a new one where nested maps are replaced
302+
// by dot-delimited keys.
303+
func Flatten(m map[string]interface{}) map[string]interface{} {
304+
o := make(map[string]interface{})
305+
for k, v := range m {
306+
switch child := v.(type) {
307+
case map[string]interface{}:
308+
nm := Flatten(child)
309+
for nk, nv := range nm {
310+
o[k+"."+nk] = nv
311+
}
312+
default:
313+
o[k] = v
314+
}
315+
}
316+
return o
317+
}

0 commit comments

Comments
 (0)