forked from mongodb/mongo
/
mongotop.go
125 lines (109 loc) · 2.99 KB
/
mongotop.go
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
// Package mongotop provides a method to track the amount of time a MongoDB instance spends reading and writing data.
package mongotop
import (
"fmt"
"github.com/mongodb/mongo-tools/common/db"
"github.com/mongodb/mongo-tools/common/log"
"github.com/mongodb/mongo-tools/common/options"
"time"
)
// MongoTop is a container for the user-specified options and
// internal state used for running mongotop.
type MongoTop struct {
// Generic mongo tool options
Options *options.ToolOptions
// Mongotop-specific output options
OutputOptions *Output
// for connecting to the db
SessionProvider *db.SessionProvider
// Length of time to sleep between each polling.
Sleeptime time.Duration
previousServerStatus *ServerStatus
previousTop *Top
}
func (mt *MongoTop) runDiff() (outDiff FormattableDiff, err error) {
session, err := mt.SessionProvider.GetSession()
if err != nil {
return nil, err
}
defer session.Close()
session.SetSocketTimeout(0)
var currentServerStatus ServerStatus
var currentTop Top
commandName := "top"
var dest interface{} = ¤tTop
if mt.OutputOptions.Locks {
commandName = "serverStatus"
dest = ¤tServerStatus
}
err = session.DB("admin").Run(commandName, dest)
if err != nil {
mt.previousServerStatus = nil
mt.previousTop = nil
return nil, err
}
if mt.OutputOptions.Locks {
if currentServerStatus.Locks == nil {
return nil, fmt.Errorf("server does not support reporting lock information")
}
for _, ns := range currentServerStatus.Locks {
if ns.AcquireCount != nil {
return nil, fmt.Errorf("server does not support reporting lock information")
}
}
if mt.previousServerStatus != nil {
serverStatusDiff := currentServerStatus.Diff(*mt.previousServerStatus)
outDiff = serverStatusDiff
}
mt.previousServerStatus = ¤tServerStatus
} else {
if mt.previousTop != nil {
topDiff := currentTop.Diff(*mt.previousTop)
outDiff = topDiff
}
mt.previousTop = ¤tTop
}
return outDiff, nil
}
// Run executes the mongotop program.
func (mt *MongoTop) Run() error {
connURL := mt.Options.Host
if connURL == "" {
connURL = "127.0.0.1"
}
if mt.Options.Port != "" {
connURL = connURL + ":" + mt.Options.Port
}
hasData := false
numPrinted := 0
for {
if mt.OutputOptions.RowCount > 0 && numPrinted > mt.OutputOptions.RowCount {
return nil
}
numPrinted++
diff, err := mt.runDiff()
if err != nil {
// If this is the first time trying to poll the server and it fails,
// just stop now instead of trying over and over.
if !hasData {
return err
}
log.Logvf(log.Always, "Error: %v\n", err)
time.Sleep(mt.Sleeptime)
}
// if this is the first time and the connection is successful, print
// the connection message
if !hasData && !mt.OutputOptions.Json {
log.Logvf(log.Always, "connected to: %v\n", connURL)
}
hasData = true
if diff != nil {
if mt.OutputOptions.Json {
fmt.Println(diff.JSON())
} else {
fmt.Println(diff.Grid())
}
}
time.Sleep(mt.Sleeptime)
}
}