-
Notifications
You must be signed in to change notification settings - Fork 141
Adding the getMongoReport script #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
svivesmdb
wants to merge
10
commits into
mongodb:master
Choose a base branch
from
svivesmdb:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
b360215
Adding modified copy of the getMongoData script to remove user, roles…
svivesmdb f5a1677
Renamed the script to remove 'data' to make it explicit we just gathe…
svivesmdb bceeac6
Removed the users and roles information from the script, removed samp…
svivesmdb d3a6f42
Removing auth information from the script, not interested in roles an…
svivesmdb 7961610
Pushing changes on sample report
svivesmdb 9f7bfa1
Changing version of the script to 1.0.0
svivesmdb 5adfeb3
Added hard limits on the script to avoid processing too many collecti…
svivesmdb dbecb32
Adding changes as per the requested changes: commment and collection …
svivesmdb 68283c2
Fixed problem with limit collections spelling, also converted to vari…
svivesmdb 595089c
We want to gather the count of all collections in the server, not onl…
svivesmdb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,371 @@ | ||
/* global db, tojson, tojsononeline, rs, print, printjson */ | ||
|
||
/* ================================================= | ||
* getMongoReport.js: MongoDB Deployment and Schema Report | ||
* ================================================= | ||
* | ||
* Copyright MongoDB, Inc, 2015 | ||
* | ||
* Gather MongoDB deployment and schema information. | ||
* | ||
* To execute on a locally running mongod on default port (27017) without | ||
* authentication, run: | ||
* | ||
* mongo getMongoReport.js > getMongoReport.log | ||
* | ||
* To execute on a remote mongod or mongos with authentication, run: | ||
* | ||
* mongo HOST:PORT/admin -u ADMIN_USER -p ADMIN_PASSWORD getMongoReport.js > getMongoReport.log | ||
* | ||
* For details, see | ||
* https://github.com/mongodb/support-tools/tree/master/getMongoReport. | ||
* | ||
* | ||
* DISCLAIMER | ||
* | ||
* Please note: all tools/ scripts in this repo are released for use "AS | ||
* IS" without any warranties of any kind, including, but not limited to | ||
* their installation, use, or performance. We disclaim any and all | ||
* warranties, either express or implied, including but not limited to | ||
* any warranty of noninfringement, merchantability, and/ or fitness for | ||
* a particular purpose. We do not warrant that the technology will | ||
* meet your requirements, that the operation thereof will be | ||
* uninterrupted or error-free, or that any errors will be corrected. | ||
* | ||
* Any use of these scripts and tools is at your own risk. There is no | ||
* guarantee that they have been through thorough testing in a | ||
* comparable environment and we are not responsible for any damage | ||
* or data loss incurred with their use. | ||
* | ||
* You are responsible for reviewing and testing any scripts you run | ||
* thoroughly before use in any non-testing environment. | ||
* | ||
* | ||
* LICENSE | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
var _version = "1.0.0"; | ||
|
||
// Limits the number of collections that this script will gather stats on in order to avoid | ||
// the possibility of running out of file descriptors. | ||
var _LIMIT_COLLECTIONS = 2500; | ||
|
||
(function () { | ||
"use strict"; | ||
}()); | ||
|
||
|
||
// Taken from the >= 3.1.9 shell to capture print output | ||
if (typeof print.captureAllOutput === "undefined") { | ||
print.captureAllOutput = function (fn, args) { | ||
var res = {}; | ||
res.output = []; | ||
var __orig_print = print; | ||
print = function () { | ||
Array.prototype.push.apply(res.output, Array.prototype.slice.call(arguments).join(" ").split("\n")); | ||
}; | ||
try { | ||
res.result = fn.apply(undefined, args); | ||
} | ||
finally { | ||
// Stop capturing print() output | ||
print = __orig_print; | ||
} | ||
return res; | ||
}; | ||
} | ||
|
||
// Convert NumberLongs to strings to save precision | ||
function longmangle(n) { | ||
if (! n instanceof NumberLong) | ||
return null; | ||
var s = n.toString(); | ||
s = s.replace("NumberLong(","").replace(")",""); | ||
if (s[0] == '"') | ||
s = s.slice(1, s.length-1) | ||
return s; | ||
} | ||
|
||
// For use in JSON.stringify to properly serialize known types | ||
function jsonStringifyReplacer(k, v){ | ||
if (v instanceof ObjectId) | ||
return { "$oid" : v.valueOf() }; | ||
if (v instanceof NumberLong) | ||
return { "$numberLong" : longmangle(v) }; | ||
if (v instanceof NumberInt) | ||
return v.toNumber(); | ||
// For ISODates; the $ check prevents recursion | ||
if (typeof v === "string" && k.startsWith('$') == false){ | ||
try { | ||
iso = ISODate(v); | ||
return { "$date" : iso.valueOf() }; | ||
} | ||
// Nothing to do here, we'll get the return at the end | ||
catch(e) {} | ||
} | ||
return v; | ||
} | ||
|
||
// Copied from Mongo Shell | ||
function printShardInfo(){ | ||
section = "shard_info"; | ||
var configDB = db.getSiblingDB("config"); | ||
|
||
printInfo("Sharding version", | ||
function(){return db.getSiblingDB("config").getCollection("version").findOne()}, | ||
section); | ||
|
||
printInfo("Shards", function(){ | ||
return configDB.shards.find().sort({ _id : 1 }).toArray(); | ||
}, section); | ||
|
||
printInfo("Sharded databases", function(){ | ||
var ret = []; | ||
configDB.databases.find().sort( { name : 1 } ).forEach( | ||
function(db) { | ||
doc = {}; | ||
for (k in db) { | ||
if (db.hasOwnProperty(k)) doc[k] = db[k]; | ||
} | ||
if (db.partitioned) { | ||
doc['collections'] = []; | ||
configDB.collections.find( { _id : new RegExp( "^" + | ||
RegExp.escape(db._id) + "\\." ) } ). | ||
sort( { _id : 1 } ).forEach( function( coll ) { | ||
if ( coll.dropped === false ){ | ||
collDoc = {}; | ||
collDoc['_id'] = coll._id; | ||
collDoc['key'] = coll.key; | ||
|
||
var res = configDB.chunks.aggregate( | ||
{ "$match": { ns: coll._id } }, | ||
{ "$group": { _id: "$shard", nChunks: { "$sum": 1 } } } | ||
); | ||
// MongoDB 2.6 and above returns a cursor instead of a document | ||
res = (res.result ? res.result : res.toArray()); | ||
|
||
collDoc['distribution'] = []; | ||
res.forEach( function(z) { | ||
chunkDistDoc = {'shard': z._id, 'nChunks': z.nChunks}; | ||
collDoc['distribution'].push(chunkDistDoc); | ||
} ); | ||
|
||
collDoc['chunks'] = []; | ||
configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach( | ||
function(chunk) { | ||
chunkDoc = {} | ||
chunkDoc['min'] = chunk.min; | ||
chunkDoc['max'] = chunk.max; | ||
chunkDoc['shard'] = chunk.shard; | ||
chunkDoc['jumbo'] = chunk.jumbo ? true : false; | ||
collDoc['chunks'].push(chunkDoc); | ||
} | ||
); | ||
|
||
collDoc['tags'] = []; | ||
configDB.tags.find( { ns : coll._id } ).sort( { min : 1 } ).forEach( | ||
function(tag) { | ||
tagDoc = {} | ||
tagDoc['tag'] = tag.tag; | ||
tagDoc['min'] = tag.min; | ||
tagDoc['max'] = tag.max; | ||
collDoc['tags'].push(tagDoc); | ||
} | ||
); | ||
} | ||
doc['collections'].push(collDoc); | ||
} | ||
); | ||
} | ||
ret.push(doc); | ||
} | ||
); | ||
return ret; | ||
}, section); | ||
} | ||
|
||
function printInfo(message, command, section, printCapture) { | ||
var result = false; | ||
printCapture = (printCapture === undefined ? false: true); | ||
if (! _printJSON) print("\n** " + message + ":"); | ||
startTime = new Date(); | ||
try { | ||
if (printCapture) { | ||
result = print.captureAllOutput(command); | ||
} else { | ||
result = command(); | ||
} | ||
err = null | ||
} catch(err) { | ||
if (! _printJSON) { | ||
print("Error running '" + command + "':"); | ||
print(err); | ||
} | ||
result = null | ||
} | ||
endTime = new Date(); | ||
doc = {}; | ||
doc['command'] = command.toString(); | ||
doc['error'] = err; | ||
doc['host'] = _host; | ||
doc['ref'] = _ref; | ||
doc['tag'] = _tag; | ||
doc['output'] = result; | ||
if (typeof(section) !== "undefined") { | ||
doc['section'] = section; | ||
doc['subsection'] = message.toLowerCase().replace(/ /g, "_"); | ||
} else { | ||
doc['section'] = message.toLowerCase().replace(/ /g, "_"); | ||
} | ||
doc['ts'] = {'start': startTime, 'end': endTime}; | ||
doc['version'] = _version; | ||
_output.push(doc); | ||
if (! _printJSON) printjson(result); | ||
return result; | ||
} | ||
|
||
function printServerInfo() { | ||
section = "server_info"; | ||
printInfo('Shell version', version, section); | ||
printInfo('Shell hostname', hostname, section); | ||
printInfo('db', function(){return db.getName()}, section); | ||
printInfo('Server status info', function(){return db.serverStatus()}, section); | ||
printInfo('Host info', function(){return db.hostInfo()}, section); | ||
printInfo('Command line info', function(){return db.serverCmdLineOpts()}, section); | ||
printInfo('Server build info', function(){return db.serverBuildInfo()}, section); | ||
} | ||
|
||
function printReplicaSetInfo() { | ||
section = "replicaset_info"; | ||
printInfo('Replica set config', function(){return rs.conf()}, section); | ||
printInfo('Replica status', function(){return rs.status()}, section); | ||
printInfo('Replica info', function(){return db.getReplicationInfo()}, section); | ||
printInfo('Replica slave info', function(){return db.printSlaveReplicationInfo()}, section, true); | ||
} | ||
|
||
function printDataInfo(isMongoS) { | ||
section = "data_info"; | ||
var dbs = printInfo('List of databases', function(){return db.getMongo().getDBs()}, section); | ||
|
||
if (dbs.databases) { | ||
dbs.databases.forEach(function(mydb) { | ||
|
||
var collections = printInfo("List of collections for database '"+ mydb.name +"'", | ||
function(){return db.getSiblingDB(mydb.name).getCollectionNames()}, section); | ||
|
||
printInfo('Database stats (MB)', | ||
function(){return db.getSiblingDB(mydb.name).stats(1024*1024)}, section); | ||
if (!isMongoS) { | ||
printInfo('Database profiler', | ||
function(){return db.getSiblingDB(mydb.name).getProfilingStatus()}, section); | ||
} | ||
|
||
if (collections && _collections_counter > _LIMIT_COLLECTIONS) { | ||
print("Error: Too many collections to process, stopped to avoid stressing the server"); | ||
} else if (collections) { | ||
|
||
for (let c = 0; c < collections.length; c++) { | ||
var col = collections[c]; | ||
_collections_counter++; | ||
|
||
if (_collections_counter > _LIMIT_COLLECTIONS) { break; } | ||
|
||
printInfo('Collection stats (MB)', | ||
function(){return db.getSiblingDB(mydb.name).getCollection(col).stats(1024*1024)}, section); | ||
if (isMongoS) { | ||
printInfo('Shard distribution', | ||
function(){return db.getSiblingDB(mydb.name).getCollection(col).getShardDistribution()}, section, true); | ||
} | ||
printInfo('Indexes', | ||
function(){return db.getSiblingDB(mydb.name).getCollection(col).getIndexes()}, section); | ||
printInfo('Index Stats', | ||
function(){ | ||
var res = db.getSiblingDB(mydb.name).runCommand( { | ||
aggregate: col, | ||
pipeline: [ | ||
{$indexStats: {}}, | ||
{$group: {_id: "$key", stats: {$push: {accesses: "$accesses.ops", host: "$host", since: "$accesses.since"}}}}, | ||
{$project: {key: "$_id", stats: 1, _id: 0}} | ||
], | ||
cursor: {} | ||
}); | ||
|
||
//It is assumed that there always will be a single batch as collections | ||
//are limited to 64 indexes and usage from all shards is grouped | ||
//into a single document | ||
if (res.hasOwnProperty('cursor') && res.cursor.hasOwnProperty('firstBatch')) { | ||
res.cursor.firstBatch.forEach( | ||
function(d){ | ||
d.stats.forEach( | ||
function(d){ | ||
d.since = d.since.toUTCString(); | ||
}) | ||
}); | ||
} | ||
|
||
return res; | ||
}, section); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
|
||
function printShardOrReplicaSetInfo() { | ||
section = "shard_or_replicaset_info"; | ||
printInfo('isMaster', function(){return db.isMaster()}, section); | ||
var state; | ||
var stateInfo = rs.status(); | ||
if (stateInfo.ok) { | ||
stateInfo.members.forEach( function( member ) { if ( member.self ) { state = member.stateStr; } } ); | ||
if ( !state ) state = stateInfo.myState; | ||
} else { | ||
var info = stateInfo.info; | ||
if ( info && info.length < 20 ) { | ||
state = info; // "mongos", "configsvr" | ||
} | ||
if ( ! state ) state = "standalone"; | ||
} | ||
if (! _printJSON) print("\n** Connected to " + state); | ||
if (state == "mongos") { | ||
printShardInfo(); | ||
return true; | ||
} else if (state != "standalone" && state != "configsvr") { | ||
if (state == "SECONDARY" || state == 2) { | ||
rs.slaveOk(); | ||
} | ||
printReplicaSetInfo(); | ||
} | ||
return false; | ||
} | ||
|
||
|
||
|
||
if (typeof _printJSON === "undefined") var _printJSON = false; | ||
if (typeof _ref === "undefined") var _ref = null; | ||
var _collections_counter = 0; | ||
var _output = []; | ||
var _tag = ObjectId(); | ||
if (! _printJSON) { | ||
print("================================"); | ||
print("MongoDB Deployment and Schema Report"); | ||
print("getMongoReport.js version " + _version); | ||
print("================================"); | ||
} | ||
var _host = hostname(); | ||
printServerInfo(); | ||
var isMongoS = printShardOrReplicaSetInfo(); | ||
printDataInfo(isMongoS); | ||
if (_printJSON) print(JSON.stringify(_output, jsonStringifyReplacer, 4)); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation somehow got messed up here.