Added --skip-collections to query-digest

This commit is contained in:
Carlos Salguero
2017-02-03 13:37:01 -03:00
parent acda89fde5
commit 700b85f7c9
2 changed files with 73 additions and 20 deletions

View File

@@ -39,6 +39,7 @@ The last step is sorting the results. The default sort order is by ascending que
|-n|--limit|show the first n queries| |-n|--limit|show the first n queries|
|-o|--order-by|comma separated list of order by fields (max values): `count`, `ratio`, `query-time`, `docs-scanned`, `docs-returned`.<br> A `-` in front of the field name denotes reverse order.<br> Example:`--order-by="count,-ratio"`).| |-o|--order-by|comma separated list of order by fields (max values): `count`, `ratio`, `query-time`, `docs-scanned`, `docs-returned`.<br> A `-` in front of the field name denotes reverse order.<br> Example:`--order-by="count,-ratio"`).|
|-p|--password[=password]|Password (optional). If it is not specified it will be asked| |-p|--password[=password]|Password (optional). If it is not specified it will be asked|
|-s|--skip-collections|Comma separated list of collections to skip. Default: `system.profile`|
|-u|--user|Username| |-u|--user|Username|
|-v|--version|Show version & exit| |-v|--version|Show version & exit|

View File

@@ -45,20 +45,26 @@ type iter interface {
} }
type options struct { type options struct {
AuthDB string AuthDB string
Database string Database string
Debug bool Debug bool
Help bool Help bool
Host string Host string
Limit int Limit int
LogLevel string LogLevel string
NoVersionCheck bool NoVersionCheck bool
OrderBy []string OrderBy []string
Password string Password string
User string SkipCollections []string
Version bool User string
Version bool
} }
// This func receives a doc from the profiler and returns:
// true : the document must be considered
// false: the document must be skipped
type docsFilter func(proto.SystemProfile) bool
type statsArray []stat type statsArray []stat
func (a statsArray) Len() int { return len(a) } func (a statsArray) Len() int { return len(a) }
@@ -129,7 +135,7 @@ func main() {
opts, err := getOptions() opts, err := getOptions()
if err != nil { if err != nil {
log.Printf("error processing commad line arguments: %s", err) log.Errorf("error processing commad line arguments: %s", err)
os.Exit(1) os.Exit(1)
} }
if opts.Help { if opts.Help {
@@ -139,7 +145,7 @@ func main() {
logLevel, err := log.ParseLevel(opts.LogLevel) logLevel, err := log.ParseLevel(opts.LogLevel)
if err != nil { if err != nil {
fmt.Printf("cannot set log level: %s", err.Error()) fmt.Errorf("cannot set log level: %s", err.Error())
} }
log.SetLevel(logLevel) log.SetLevel(logLevel)
@@ -187,8 +193,36 @@ func main() {
os.Exit(5) os.Exit(5)
} }
i := session.DB(di.Database).C("system.profile").Find(bson.M{"op": bson.M{"$nin": []string{"getmore", "delete"}}}).Sort("-$natural").Iter() filters := []docsFilter{}
queries := sortQueries(getData(i), opts.OrderBy)
if len(opts.SkipCollections) > 0 {
// Sanitize the param. using --skip-collections="" will produce an 1 element array but
// that element will be empty. The same would be using --skip-collections=a,,d
cols := []string{}
for _, c := range opts.SkipCollections {
if strings.TrimSpace(c) != "" {
cols = append(cols, c)
}
}
if len(cols) > 0 {
// This func receives a doc from the profiler and returns:
// true : the document must be considered
// false: the document must be skipped
filterSystemProfile := func(doc proto.SystemProfile) bool {
for _, collection := range cols {
if strings.HasSuffix(doc.Ns, collection) {
return false
}
}
return true
}
filters = append(filters, filterSystemProfile)
}
}
query := bson.M{"op": bson.M{"$nin": []string{"getmore", "delete"}}}
i := session.DB(di.Database).C("system.profile").Find(query).Sort("-$natural").Iter()
queries := sortQueries(getData(i, filters), opts.OrderBy)
uptime := uptime(session) uptime := uptime(session)
@@ -372,13 +406,24 @@ func calcStats(samples []float64) statistics {
return s return s
} }
func getData(i iter) []stat { func getData(i iter, filters []docsFilter) []stat {
var doc proto.SystemProfile var doc proto.SystemProfile
stats := make(map[groupKey]*stat) stats := make(map[groupKey]*stat)
log.Debug(`Documents returned by db.getSiblinfDB("<dbnamehere>").system.profile.Find({"op": {"$nin": []string{"getmore", "delete"}}).Sort("-$natural")`) log.Debug(`Documents returned by db.getSiblinfDB("<dbnamehere>").system.profile.Find({"op": {"$nin": []string{"getmore", "delete"}}).Sort("-$natural")`)
for i.Next(&doc) && i.Err() == nil { for i.Next(&doc) && i.Err() == nil {
valid := true
for _, filter := range filters {
if filter(doc) == false {
valid = false
break
}
}
if !valid {
continue
}
log.Debugln("====================================================================================================") log.Debugln("====================================================================================================")
log.Debug(pretty.Sprint(doc)) log.Debug(pretty.Sprint(doc))
if len(doc.Query) > 0 { if len(doc.Query) > 0 {
@@ -424,7 +469,6 @@ func getData(i iter) []stat {
// We need to sort the data but a hash cannot be sorted so, convert the hash having // We need to sort the data but a hash cannot be sorted so, convert the hash having
// the results to a slice // the results to a slice
sa := statsArray{} sa := statsArray{}
for _, s := range stats { for _, s := range stats {
sa = append(sa, *s) sa = append(sa, *s)
@@ -435,7 +479,13 @@ func getData(i iter) []stat {
} }
func getOptions() (*options, error) { func getOptions() (*options, error) {
opts := &options{Host: "localhost:27017", LogLevel: "warn", OrderBy: []string{"count"}} opts := &options{
Host: "localhost:27017",
LogLevel: "warn",
OrderBy: []string{"count"},
SkipCollections: []string{"system.profile"},
}
getopt.BoolVarLong(&opts.Help, "help", '?', "Show help") getopt.BoolVarLong(&opts.Help, "help", '?', "Show help")
getopt.BoolVarLong(&opts.Version, "version", 'v', "show version & exit") getopt.BoolVarLong(&opts.Version, "version", 'v', "show version & exit")
getopt.BoolVarLong(&opts.NoVersionCheck, "no-version-check", 'c', "Don't check for updates") getopt.BoolVarLong(&opts.NoVersionCheck, "no-version-check", 'c', "Don't check for updates")
@@ -443,6 +493,7 @@ func getOptions() (*options, error) {
getopt.IntVarLong(&opts.Limit, "limit", 'n', "show the first n queries") getopt.IntVarLong(&opts.Limit, "limit", 'n', "show the first n queries")
getopt.ListVarLong(&opts.OrderBy, "order-by", 'o', "comma separated list of order by fields (max values): count,ratio,query-time,docs-scanned,docs-returned. - in front of the field name denotes reverse order.") getopt.ListVarLong(&opts.OrderBy, "order-by", 'o', "comma separated list of order by fields (max values): count,ratio,query-time,docs-scanned,docs-returned. - in front of the field name denotes reverse order.")
getopt.ListVarLong(&opts.SkipCollections, "skip-collections", 's', "comma separated list of collections (namespaces) to skip. Default: system.profile")
getopt.StringVarLong(&opts.AuthDB, "authenticationDatabase", 'a', "admin", "database used to establish credentials and privileges with a MongoDB server") getopt.StringVarLong(&opts.AuthDB, "authenticationDatabase", 'a', "admin", "database used to establish credentials and privileges with a MongoDB server")
getopt.StringVarLong(&opts.Database, "database", 'd', "", "database to profile") getopt.StringVarLong(&opts.Database, "database", 'd', "", "database to profile")
@@ -534,7 +585,8 @@ func keys(query map[string]interface{}, level int) []string {
func printHeader(opts *options) { func printHeader(opts *options) {
fmt.Printf("%s - %s\n", TOOLNAME, time.Now().Format(time.RFC1123Z)) fmt.Printf("%s - %s\n", TOOLNAME, time.Now().Format(time.RFC1123Z))
fmt.Printf("Host: %s", opts.Host) fmt.Printf("Host: %s\n", opts.Host)
fmt.Printf("Skipping docs in these collections: %v\n", opts.SkipCollections)
fmt.Println("") fmt.Println("")
} }