summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Whalen <ian.whalen@gmail.com>2017-09-21 10:20:20 -0400
committerIan Whalen <ian.whalen@gmail.com>2017-09-21 10:20:20 -0400
commit0e3c8a96af7f9ddd6d5a059c92f6303eba1d0b32 (patch)
tree8b92add4f9b8a2a9ca939f93656ecac9781d03cb
parent48cdb7d69246339e097bf23ec0e6b9187a3f9221 (diff)
downloadmongo-0e3c8a96af7f9ddd6d5a059c92f6303eba1d0b32.tar.gz
Revert "SERVER-21677 Remove "diaglog" support from the server"
This reverts commit d5d61785d59f62e29ba01843f8c15cf08a5ca55a.
-rw-r--r--debian/mongod.186
-rw-r--r--debian/mongosniff.1200
-rw-r--r--jstests/auth/lib/commands_lib.js14
-rw-r--r--jstests/core/views/views_all_commands.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_drop_recreate.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js1
-rw-r--r--src/mongo/db/SConscript13
-rw-r--r--src/mongo/db/auth/action_types.txt1
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp1
-rw-r--r--src/mongo/db/commands/dbcommands.cpp59
-rw-r--r--src/mongo/db/db.cpp4
-rw-r--r--src/mongo/db/diag_log.cpp109
-rw-r--r--src/mongo/db/diag_log.h65
-rw-r--r--src/mongo/db/mongod_options.cpp16
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp21
-rw-r--r--src/mongo/db/storage/mmap_v1/SConscript1
-rw-r--r--src/mongo/db/storage/mmap_v1/data_file_sync.cpp2
18 files changed, 596 insertions, 0 deletions
diff --git a/debian/mongod.1 b/debian/mongod.1
index 7982e554870..b775b7004d5 100644
--- a/debian/mongod.1
+++ b/debian/mongod.1
@@ -232,6 +232,92 @@ _
.UNINDENT
.INDENT 0.0
.TP
+.B \-\-diaglog <value>
+\fIDefault\fP: 0
+.sp
+Deprecated since version 2.6.
+
+.sp
+\fI\%\-\-diaglog\fP is for internal use and not intended for most users.
+.sp
+Creates a very verbose \fIdiagnostic log\fP for troubleshooting and
+recording various errors. MongoDB writes these log files in the
+\fBdbPath\fP directory in a series of files that begin with the
+string \fBdiaglog\fP and end with the initiation time of the logging as a
+hex string.
+.sp
+The specified value configures the level of verbosity:
+.TS
+center;
+|l|l|.
+_
+T{
+Value
+T} T{
+Setting
+T}
+_
+T{
+0
+T} T{
+Off. No logging.
+T}
+_
+T{
+1
+T} T{
+Log write operations.
+T}
+_
+T{
+2
+T} T{
+Log read operations.
+T}
+_
+T{
+3
+T} T{
+Log both read and write operations.
+T}
+_
+T{
+7
+T} T{
+Log write and some read operations.
+T}
+_
+.TE
+.sp
+You can use the \fBmongosniff\fP tool to replay this output for
+investigation. Given a typical diaglog file located at
+\fB/data/db/diaglog.4f76a58c\fP, you might use a command in the following
+form to read these files:
+.INDENT 7.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+mongosniff \-\-source DIAGLOG /data/db/diaglog.4f76a58c
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+\fBWARNING:\fP
+.INDENT 7.0
+.INDENT 3.5
+Setting the diagnostic level to \fB0\fP will cause \fBmongod\fP
+to stop writing data to the \fIdiagnostic log\fP file. However,
+the \fBmongod\fP instance will continue to keep the file open,
+even if it is no longer writing data to the file. If you want to
+rename, move, or delete the diagnostic log you must cleanly shut
+down the \fBmongod\fP instance before doing so.
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
.B \-\-traceExceptions
For internal diagnostic use only.
.UNINDENT
diff --git a/debian/mongosniff.1 b/debian/mongosniff.1
new file mode 100644
index 00000000000..600a792c3df
--- /dev/null
+++ b/debian/mongosniff.1
@@ -0,0 +1,200 @@
+.\" Man page generated from reStructuredText.
+.
+.TH "MONGOSNIFF" "1" "January 30, 2015" "3.0" "mongodb-manual"
+.SH NAME
+mongosniff \- MongoDB Protocol Introspection Utility
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.sp
+\fBmongosniff\fP provides a low\-level operation tracing/sniffing view
+into database activity in real time. Think of \fBmongosniff\fP as a
+MongoDB\-specific analogue of \fBtcpdump\fP for TCP/IP network
+traffic. Typically, \fBmongosniff\fP is most frequently used in driver
+development.
+.sp
+\fBNOTE:\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBmongosniff\fP requires \fBlibpcap\fP and is only available for
+Unix\-like systems.
+.UNINDENT
+.UNINDENT
+.sp
+As an alternative to \fBmongosniff\fP, Wireshark, a popular
+network sniffing tool is capable of inspecting and parsing the MongoDB
+wire protocol.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B mongosniff
+.UNINDENT
+.INDENT 0.0
+.TP
+.B mongosniff
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-help
+Returns information on the options and use of \fBmongosniff\fP\&.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-forward <host><:port>
+Declares a host to forward all parsed requests that the
+\fBmongosniff\fP intercepts to another \fBmongod\fP instance
+and issue those operations on that database instance.
+.sp
+Specify the target host name and port in the \fB<host><:port>\fP format.
+.sp
+To connect to a replica set, specify the \fBreplica set name\fP and a seed list of set members. Use the
+following form:
+.INDENT 7.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+<replSetName>/<hostname1><:port>,<hostname2><:port>,<...>
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-source <NET [interface]>
+Specifies source material to inspect. Use \fB\-\-source NET [interface]\fP
+to inspect traffic from a network interface (e.g. \fBeth0\fP or \fBlo\fP\&.)
+Use \fB\-\-source FILE [filename]\fP to read captured packets in
+\fIpcap\fP format.
+.sp
+You may use the \fB\-\-source DIAGLOG [filename]\fP option to read the
+output files produced by the \fI\-\-diaglog\fP
+option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-objcheck
+Displays invalid BSON objects only and nothing else. Use this option for
+troubleshooting driver development. This option has some performance
+impact on the performance of \fBmongosniff\fP\&.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B <port>
+Specifies alternate ports to sniff for traffic. By default,
+\fBmongosniff\fP watches for MongoDB traffic on port \fB27017\fP\&. Append
+multiple port numbers to the end of \fBmongosniff\fP to monitor
+traffic on multiple ports.
+.UNINDENT
+.SH USE
+.sp
+Use the following command to connect to a \fBmongod\fP or
+\fBmongos\fP running on port 27017 \fIand\fP 27018 on the localhost
+interface:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+mongosniff \-\-source NET lo 27017 27018
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Use the following command to only log invalid \fIBSON\fP objects for
+the \fBmongod\fP or \fBmongos\fP running on the localhost
+interface and port 27018, for driver development and troubleshooting:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+mongosniff \-\-objcheck \-\-source NET lo 27018
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH BUILD MONGOSNIFF
+.sp
+To build \fBmongosniff\fP yourself, Linux users can use the following
+procedure:
+.INDENT 0.0
+.IP 1. 3
+Obtain prerequisites using your operating
+systems package management software. Dependencies include:
+.INDENT 3.0
+.IP \(bu 2
+\fBlibpcap\fP \- to capture network packets.
+.IP \(bu 2
+\fBgit\fP \- to download the MongoDB source code.
+.IP \(bu 2
+\fBscons\fP and a C++ compiler \- to build \fBmongosniff\fP\&.
+.UNINDENT
+.IP 2. 3
+Download a copy of the MongoDB source code using \fBgit\fP:
+.INDENT 3.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+git clone git://github.com/mongodb/mongo.git
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.IP 3. 3
+Issue the following sequence of commands to change to the
+\fBmongo/\fP directory and build \fBmongosniff\fP:
+.INDENT 3.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+cd mongo
+scons mongosniff
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBNOTE:\fP
+.INDENT 0.0
+.INDENT 3.5
+If you run \fBscons mongosniff\fP before installing \fBlibpcap\fP you
+must run \fBscons clean\fP before you can build \fBmongosniff\fP\&.
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+MongoDB Documentation Project
+.SH COPYRIGHT
+2011-2015
+.\" Generated by docutils manpage writer.
+.
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js
index 90b8d1051f8..077ed4fe388 100644
--- a/jstests/auth/lib/commands_lib.js
+++ b/jstests/auth/lib/commands_lib.js
@@ -2246,6 +2246,20 @@ var authCommandsLib = {
]
},
{
+ testname: "diagLogging",
+ command: {diagLogging: 1},
+ skipSharded: true,
+ testcases: [
+ {
+ runOnDb: adminDbName,
+ roles: roles_hostManager,
+ privileges: [{resource: {cluster: true}, actions: ["diagLogging"]}]
+ },
+ {runOnDb: firstDbName, roles: {}},
+ {runOnDb: secondDbName, roles: {}}
+ ]
+ },
+ {
testname: "distinct",
command: {distinct: "coll", key: "a", query: {}},
testcases: [
diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js
index ff5842be316..b56d61fe7a7 100644
--- a/jstests/core/views/views_all_commands.js
+++ b/jstests/core/views/views_all_commands.js
@@ -180,6 +180,7 @@
},
dbStats: {skip: "TODO(SERVER-25948)"},
delete: {command: {delete: "view", deletes: [{q: {x: 1}, limit: 1}]}, expectFailure: true},
+ diagLogging: {skip: isUnrelated},
distinct: {command: {distinct: "view", key: "_id"}},
driverOIDTest: {skip: isUnrelated},
drop: {command: {drop: "view"}},
diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js
index 488906bef52..5b49fd1dc24 100644
--- a/jstests/sharding/safe_secondary_reads_drop_recreate.js
+++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js
@@ -132,6 +132,7 @@
dbHash: {skip: "does not return user data"},
dbStats: {skip: "does not return user data"},
delete: {skip: "primary only"},
+ diagLogging: {skip: "does not return user data"},
distinct: {
setUp: function(mongosConn) {
assert.writeOK(mongosConn.getCollection(nss).insert({x: 1}));
diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
index ccb774e5f8f..44ac466c435 100644
--- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
+++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
@@ -151,6 +151,7 @@
dbHash: {skip: "does not return user data"},
dbStats: {skip: "does not return user data"},
delete: {skip: "primary only"},
+ diagLogging: {skip: "does not return user data"},
distinct: {
setUp: function(mongosConn) {
assert.writeOK(mongosConn.getCollection(nss).insert({x: 1}));
diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
index 98713affc78..bf09aebe9f5 100644
--- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
+++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
@@ -134,6 +134,7 @@
dbHash: {skip: "does not return user data"},
dbStats: {skip: "does not return user data"},
delete: {skip: "primary only"},
+ diagLogging: {skip: "does not return user data"},
distinct: {
setUp: function(mongosConn) {
assert.writeOK(mongosConn.getCollection(nss).insert({x: 1}));
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index cf2b8e6cd7f..e63c3b20742 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -413,6 +413,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/storage/mmap_v1/mmap_v1_options',
+ 'diag_log',
'repl/repl_settings',
'server_options',
'storage/storage_options',
@@ -591,6 +592,7 @@ env.Library(
'concurrency/lock_manager',
'curop',
'curop_metrics',
+ 'diag_log',
'lasterror',
'ops/write_ops_parsers',
'rw_concern_d',
@@ -755,6 +757,16 @@ env.Library(
)
env.Library(
+ target="diag_log",
+ source=[
+ "diag_log.cpp",
+ ],
+ LIBDEPS=[
+ "storage/storage_options",
+ ],
+)
+
+env.Library(
target="authz_manager_external_state_factory_d",
source=[
"authz_manager_external_state_factory_d.cpp",
@@ -806,6 +818,7 @@ env.Library(
"db_raii",
"dbdirectclient",
"dbhelpers",
+ "diag_log",
"exec/exec",
"exec/working_set",
"ftdc/ftdc_mongod",
diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt
index 1f57ba6084b..2fdb27bbeb0 100644
--- a/src/mongo/db/auth/action_types.txt
+++ b/src/mongo/db/auth/action_types.txt
@@ -34,6 +34,7 @@
"createUser",
"dbHash",
"dbStats",
+"diagLogging",
"dropAllRolesFromDatabase", # Not used for permissions checks, but to id the event in logs.
"dropAllUsersFromDatabase", # Not used for permissions checks, but to id the event in logs.
"dropCollection",
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 47ba56ce752..d79149c368d 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -213,6 +213,7 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) {
<< ActionType::shutdown
<< ActionType::touch
<< ActionType::unlock
+ << ActionType::diagLogging
<< ActionType::flushRouterConfig // clusterManager gets this also
<< ActionType::fsync
<< ActionType::invalidateUserCache // userAdminAnyDatabase gets this also
diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp
index 15851760bc5..791d851c376 100644
--- a/src/mongo/db/commands/dbcommands.cpp
+++ b/src/mongo/db/commands/dbcommands.cpp
@@ -64,6 +64,7 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/diag_log.h"
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_descriptor.h"
@@ -390,6 +391,64 @@ public:
} cmdProfile;
+class CmdDiagLogging : public BasicCommand {
+public:
+ virtual bool slaveOk() const {
+ return true;
+ }
+ CmdDiagLogging() : BasicCommand("diagLogging") {}
+ bool adminOnly() const {
+ return true;
+ }
+
+ void help(stringstream& h) const {
+ h << "http://dochub.mongodb.org/core/"
+ "monitoring#MonitoringandDiagnostics-DatabaseRecord%2FReplay%28diagLoggingcommand%29";
+ }
+
+
+ virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return false;
+ }
+
+ virtual void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) {
+ ActionSet actions;
+ actions.addAction(ActionType::diagLogging);
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
+ }
+
+ bool run(OperationContext* opCtx,
+ const string& dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder& result) {
+ const char* deprecationWarning =
+ "CMD diagLogging is deprecated and will be removed in a future release";
+ warning() << deprecationWarning << startupWarningsLog;
+
+ // This doesn't look like it requires exclusive DB lock, because it uses its own diag
+ // locking, but originally the lock was set to be WRITE, so preserving the behaviour.
+ Lock::DBLock dbXLock(opCtx, dbname, MODE_X);
+
+ // TODO (Kal): OldClientContext legacy, needs to be removed
+ {
+ CurOp::get(opCtx)->ensureStarted();
+ stdx::lock_guard<Client> lk(*opCtx->getClient());
+ CurOp::get(opCtx)->setNS_inlock(dbname);
+ }
+
+ int was = _diaglog.setLevel(cmdObj.firstElement().numberInt());
+ _diaglog.flush();
+ if (!serverGlobalParams.quiet.load()) {
+ LOG(0) << "CMD: diagLogging set to " << _diaglog.getLevel() << " from: " << was;
+ }
+ result.append("was", was);
+ result.append("note", deprecationWarning);
+ return true;
+ }
+} cmddiaglogging;
+
/* drop collection */
class CmdDrop : public ErrmsgCommandDeprecated {
public:
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index ef1e073e1db..7bef30a8593 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -65,6 +65,7 @@
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/dbmessage.h"
+#include "mongo/db/diag_log.h"
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/ftdc/ftdc_mongod.h"
#include "mongo/db/index_names.h"
@@ -1012,6 +1013,9 @@ void shutdownTask() {
log(LogComponent::kNetwork) << "shutdown: going to close listening sockets...";
ListeningSockets::get()->closeAll();
+ log(LogComponent::kNetwork) << "shutdown: going to flush diaglog...";
+ _diaglog.flush();
+
if (serviceContext->getGlobalStorageEngine()) {
ServiceContext::UniqueOperationContext uniqueOpCtx;
OperationContext* opCtx = client->getOperationContext();
diff --git a/src/mongo/db/diag_log.cpp b/src/mongo/db/diag_log.cpp
new file mode 100644
index 00000000000..9b4606d478f
--- /dev/null
+++ b/src/mongo/db/diag_log.cpp
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2008-2014 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault;
+
+#include "mongo/platform/basic.h"
+
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+
+#include "mongo/db/diag_log.h"
+
+#include "mongo/db/storage/storage_options.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+
+using std::hex;
+using std::ios;
+using std::ofstream;
+using std::string;
+using std::stringstream;
+
+DiagLog::DiagLog() : f(0), level(0) {}
+
+void DiagLog::openFile() {
+ verify(f == 0);
+ stringstream ss;
+ ss << storageGlobalParams.dbpath << "/diaglog." << hex << time(0);
+ string name = ss.str();
+ f = new ofstream(name.c_str(), ios::out | ios::binary);
+ if (!f->good()) {
+ str::stream msg;
+ msg << "diagLogging couldn't open " << name;
+ log() << msg.ss.str();
+ uasserted(ErrorCodes::FileStreamFailed, msg.ss.str());
+ } else {
+ log() << "diagLogging using file " << name;
+ }
+}
+
+int DiagLog::setLevel(int newLevel) {
+ stdx::lock_guard<stdx::mutex> lk(mutex);
+ int old = level;
+ log() << "diagLogging level=" << newLevel;
+ if (f == 0) {
+ openFile();
+ }
+ level = newLevel; // must be done AFTER f is set
+ return old;
+}
+
+void DiagLog::flush() {
+ if (level) {
+ log() << "flushing diag log";
+ stdx::lock_guard<stdx::mutex> lk(mutex);
+ f->flush();
+ }
+}
+
+void DiagLog::writeop(char* data, int len) {
+ if (level & 1) {
+ stdx::lock_guard<stdx::mutex> lk(mutex);
+ f->write(data, len);
+ }
+}
+
+void DiagLog::readop(char* data, int len) {
+ if (level & 2) {
+ bool log = (level & 4) == 0;
+ OCCASIONALLY log = true;
+ if (log) {
+ stdx::lock_guard<stdx::mutex> lk(mutex);
+ verify(f);
+ f->write(data, len);
+ }
+ }
+}
+
+DiagLog _diaglog;
+
+} // namespace mongo
diff --git a/src/mongo/db/diag_log.h b/src/mongo/db/diag_log.h
new file mode 100644
index 00000000000..739f15aec43
--- /dev/null
+++ b/src/mongo/db/diag_log.h
@@ -0,0 +1,65 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#pragma once
+
+#include <iosfwd>
+
+#include "mongo/stdx/mutex.h"
+
+namespace mongo {
+
+/** a high level recording of operations to the database - sometimes used for diagnostics
+ and debugging.
+ */
+class DiagLog {
+ std::ofstream* f; // note this is never freed
+ /* 0 = off; 1 = writes, 2 = reads, 3 = both
+ 7 = log a few reads, and all writes.
+ */
+ int level;
+ stdx::mutex mutex;
+ void openFile();
+
+public:
+ DiagLog();
+ int getLevel() const {
+ return level;
+ }
+ /**
+ * @return old
+ */
+ int setLevel(int newLevel);
+ void flush();
+ void writeop(char* data, int len);
+ void readop(char* data, int len);
+};
+
+extern DiagLog _diaglog;
+
+} // namespace mongo
diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp
index 7e31a8f2890..ae7407bbd6a 100644
--- a/src/mongo/db/mongod_options.cpp
+++ b/src/mongo/db/mongod_options.cpp
@@ -40,6 +40,7 @@
#include "mongo/bson/util/builder.h"
#include "mongo/config.h"
#include "mongo/db/db.h"
+#include "mongo/db/diag_log.h"
#include "mongo/db/repl/repl_settings.h"
#include "mongo/db/server_options.h"
#include "mongo/db/server_options_helpers.h"
@@ -132,6 +133,12 @@ Status addMongodOptions(moe::OptionSection* options) {
// Diagnostic Options
general_options
+ .addOptionChaining(
+ "diaglog", "diaglog", moe::Int, "DEPRECATED: 0=off 1=W 2=R 3=both 7=W+some reads")
+ .hidden()
+ .setSources(moe::SourceAllLegacy);
+
+ general_options
.addOptionChaining("operationProfiling.slowOpThresholdMs",
"slowms",
moe::Int,
@@ -1069,6 +1076,15 @@ Status storeMongodOptions(const moe::Environment& params) {
if (params.count("storage.mmapv1.smallFiles")) {
mmapv1GlobalOptions.smallfiles = params["storage.mmapv1.smallFiles"].as<bool>();
}
+ if (params.count("diaglog")) {
+ warning() << "--diaglog is deprecated and will be removed in a future release"
+ << startupWarningsLog;
+ int x = params["diaglog"].as<int>();
+ if (x < 0 || x > 7) {
+ return Status(ErrorCodes::BadValue, "can't interpret --diaglog setting");
+ }
+ _diaglog.setLevel(x);
+ }
if ((params.count("storage.journal.enabled") &&
params["storage.journal.enabled"].as<bool>() == true) &&
diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp
index dfec6d0382b..1e24a469a1d 100644
--- a/src/mongo/db/service_entry_point_mongod.cpp
+++ b/src/mongo/db/service_entry_point_mongod.cpp
@@ -44,6 +44,7 @@
#include "mongo/db/curop_metrics.h"
#include "mongo/db/cursor_manager.h"
#include "mongo/db/dbdirectclient.h"
+#include "mongo/db/diag_log.h"
#include "mongo/db/initialize_operation_session_info.h"
#include "mongo/db/introspect.h"
#include "mongo/db/jsobj.h"
@@ -106,6 +107,18 @@ const StringMap<int> cmdWhitelist = {{"delete", 1},
{"refreshLogicalSessionCacheNow", 1},
{"update", 1}};
+inline void opread(const Message& m) {
+ if (_diaglog.getLevel() & 2) {
+ _diaglog.readop(m.singleData().view2ptr(), m.header().getLen());
+ }
+}
+
+inline void opwrite(const Message& m) {
+ if (_diaglog.getLevel() & 1) {
+ _diaglog.writeop(m.singleData().view2ptr(), m.header().getLen());
+ }
+}
+
void generateLegacyQueryErrorResponse(const AssertionException* exception,
const QueryMessage& queryMessage,
CurOp* curop,
@@ -1068,9 +1081,17 @@ DbResponse ServiceEntryPointMongod::handleRequest(OperationContext* opCtx, const
if (op == dbQuery) {
if (nsString.isCommand()) {
isCommand = true;
+ opwrite(m);
+ } else {
+ opread(m);
}
+ } else if (op == dbGetMore) {
+ opread(m);
} else if (op == dbCommand || op == dbMsg) {
isCommand = true;
+ opwrite(m);
+ } else {
+ opwrite(m);
}
CurOp& currentOp = *CurOp::get(opCtx);
diff --git a/src/mongo/db/storage/mmap_v1/SConscript b/src/mongo/db/storage/mmap_v1/SConscript
index 0e308816953..a1642bc578a 100644
--- a/src/mongo/db/storage/mmap_v1/SConscript
+++ b/src/mongo/db/storage/mmap_v1/SConscript
@@ -69,6 +69,7 @@ env.Library(
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/db/commands/server_status',
'$BUILD_DIR/mongo/db/concurrency/lock_manager',
+ '$BUILD_DIR/mongo/db/diag_log',
'$BUILD_DIR/mongo/db/index_names',
'$BUILD_DIR/mongo/db/index/index_descriptor',
'$BUILD_DIR/mongo/db/storage/journal_listener',
diff --git a/src/mongo/db/storage/mmap_v1/data_file_sync.cpp b/src/mongo/db/storage/mmap_v1/data_file_sync.cpp
index 4d895c09b20..ab7dca95ff9 100644
--- a/src/mongo/db/storage/mmap_v1/data_file_sync.cpp
+++ b/src/mongo/db/storage/mmap_v1/data_file_sync.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/client.h"
#include "mongo/db/commands/server_status_metric.h"
+#include "mongo/db/diag_log.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/service_context.h"
#include "mongo/db/storage/mmap_v1/dur_journal.h"
@@ -65,6 +66,7 @@ void DataFileSync::run() {
}
int time_flushing = 0;
while (!globalInShutdownDeprecated()) {
+ _diaglog.flush();
if (storageGlobalParams.syncdelay == 0) {
// in case at some point we add an option to change at runtime
sleepsecs(5);