summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Russell <gabriel.russell@mongodb.com>2019-10-03 21:15:40 +0000
committerevergreen <evergreen@mongodb.com>2019-10-03 21:15:40 +0000
commitd7827a40dfa30bfaa2e3c275ea4bf07d8a1cd159 (patch)
treebd7171834ed303e70062ef8f5020d48c5a4e47db
parent8cda1be220ab092efb9a8c0657890c4348c701c1 (diff)
downloadmongo-d7827a40dfa30bfaa2e3c275ea4bf07d8a1cd159.tar.gz
SERVER-42726 enable logging via logv2
-rw-r--r--SConstruct1
-rw-r--r--src/mongo/SConscript14
-rw-r--r--src/mongo/db/commands/generic_servers.cpp2
-rw-r--r--src/mongo/db/initialize_server_global_state.cpp110
-rw-r--r--src/mongo/db/server_options.h3
-rw-r--r--src/mongo/db/server_options_base.idl4
-rw-r--r--src/mongo/db/server_options_helpers.cpp3
-rw-r--r--src/mongo/logger/logv2_appender.h81
-rw-r--r--src/mongo/logv2/SConscript31
-rw-r--r--src/mongo/logv2/log.h53
-rw-r--r--src/mongo/logv2/log_detail.cpp91
-rw-r--r--src/mongo/logv2/log_detail.h88
-rw-r--r--src/mongo/logv2/log_manager.cpp113
-rw-r--r--src/mongo/logv2/log_manager.h12
-rw-r--r--src/mongo/logv2/log_options.h7
-rw-r--r--src/mongo/util/log.cpp11
-rw-r--r--src/mongo/util/log.h2
-rw-r--r--src/mongo/util/signal_handlers.cpp3
-rw-r--r--src/third_party/boost-1.70.0/SConscript1
19 files changed, 513 insertions, 117 deletions
diff --git a/SConstruct b/SConstruct
index 91a3afebc85..683a07a836b 100644
--- a/SConstruct
+++ b/SConstruct
@@ -3335,6 +3335,7 @@ def doConfigure(myenv):
"BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS",
"BOOST_ENABLE_ASSERT_DEBUG_HANDLER",
"BOOST_LOG_NO_SHORTHAND_NAMES",
+ "BOOST_LOG_USE_NATIVE_SYSLOG",
"ABSL_FORCE_ALIGNED_ACCESS",
]
)
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index a84ee8bf016..e0bb62f04d3 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -110,8 +110,20 @@ baseEnv.Library(
'logger/redaction.cpp',
'logger/rotatable_file_manager.cpp',
'logger/rotatable_file_writer.cpp',
- 'platform/decimal128.cpp',
+ 'logv2/attributes.cpp',
+ 'logv2/console.cpp',
+ 'logv2/log_detail.cpp',
+ 'logv2/log_component.cpp',
+ 'logv2/log_component_settings.cpp',
+ 'logv2/log_domain.cpp',
+ 'logv2/log_domain_global.cpp',
+ 'logv2/log_manager.cpp',
+ 'logv2/log_record.cpp',
+ 'logv2/log_severity.cpp',
+ 'logv2/log_tag.cpp',
+ 'logv2/ramlog.cpp',
'platform/condition_variable.cpp',
+ 'platform/decimal128.cpp',
'platform/mutex.cpp',
'platform/posix_fadvise.cpp',
'platform/process_id.cpp',
diff --git a/src/mongo/db/commands/generic_servers.cpp b/src/mongo/db/commands/generic_servers.cpp
index d753f010b4c..f89c1975c6c 100644
--- a/src/mongo/db/commands/generic_servers.cpp
+++ b/src/mongo/db/commands/generic_servers.cpp
@@ -198,7 +198,7 @@ public:
const string& ns,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
- bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate);
+ bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate, serverGlobalParams.logV2);
if (didRotate)
logProcessDetailsForLogRotate(opCtx->getServiceContext());
return didRotate;
diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp
index e09338d5d55..3ea79435897 100644
--- a/src/mongo/db/initialize_server_global_state.cpp
+++ b/src/mongo/db/initialize_server_global_state.cpp
@@ -50,6 +50,7 @@
#include "mongo/db/server_options.h"
#include "mongo/logger/console_appender.h"
#include "mongo/logger/logger.h"
+#include "mongo/logger/logv2_appender.h"
#include "mongo/logger/message_event.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/logger/ramlog.h"
@@ -219,25 +220,41 @@ MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
// Hook up this global into our logging encoder
MessageEventDetailsEncoder::setMaxLogSizeKBSource(gMaxLogSizeKB);
+ LogManager* manager = logger::globalLogManager();
+ auto& lv2Manager = logv2::LogManager::global();
if (serverGlobalParams.logWithSyslog) {
#ifdef _WIN32
return Status(ErrorCodes::InternalError,
"Syslog requested in Windows build; command line processor logic error");
#else
- using logger::SyslogAppender;
+ std::unique_ptr<logger::Appender<MessageEventEphemeral>> appender;
- StringBuilder sb;
- sb << serverGlobalParams.binaryName << "." << serverGlobalParams.port;
- openlog(strdup(sb.str().c_str()), LOG_PID | LOG_CONS, serverGlobalParams.syslogFacility);
- LogManager* manager = logger::globalLogManager();
+ if (serverGlobalParams.logV2) {
+
+ appender = std::make_unique<logger::LogV2Appender<MessageEventEphemeral>>(
+ &(lv2Manager.getGlobalDomain()));
+
+ lv2Manager.detachConsoleBackend();
+ lv2Manager.setupSyslogBackend(serverGlobalParams.syslogFacility);
+ lv2Manager.reattachSyslogBackend();
+
+ } else {
+
+ using logger::SyslogAppender;
+ StringBuilder sb;
+ sb << serverGlobalParams.binaryName << "." << serverGlobalParams.port;
+ openlog(
+ strdup(sb.str().c_str()), LOG_PID | LOG_CONS, serverGlobalParams.syslogFacility);
+ appender = std::make_unique<SyslogAppender<MessageEventEphemeral>>(
+ std::make_unique<logger::MessageEventDetailsEncoder>());
+ manager->getNamedDomain("javascriptOutput")
+ ->attachAppender(std::make_unique<SyslogAppender<MessageEventEphemeral>>(
+ std::make_unique<logger::MessageEventDetailsEncoder>()));
+ }
manager->getGlobalDomain()->clearAppenders();
- manager->getGlobalDomain()->attachAppender(
- std::make_unique<SyslogAppender<MessageEventEphemeral>>(
- std::make_unique<logger::MessageEventDetailsEncoder>()));
- manager->getNamedDomain("javascriptOutput")
- ->attachAppender(std::make_unique<SyslogAppender<MessageEventEphemeral>>(
- std::make_unique<logger::MessageEventDetailsEncoder>()));
+ manager->getGlobalDomain()->attachAppender(std::move(appender));
+
#endif // defined(_WIN32)
} else if (!serverGlobalParams.logpath.empty()) {
fassert(16448, !serverGlobalParams.logWithSyslog);
@@ -280,32 +297,59 @@ MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
}
}
- StatusWithRotatableFileWriter writer = logger::globalRotatableFileManager()->openFile(
- absoluteLogpath, serverGlobalParams.logAppend);
- if (!writer.isOK()) {
- return writer.getStatus();
+ std::unique_ptr<logger::Appender<MessageEventEphemeral>> appender;
+
+ if (serverGlobalParams.logV2) {
+
+ appender = std::make_unique<logger::LogV2Appender<MessageEventEphemeral>>(
+ &(lv2Manager.getGlobalDomain()));
+
+ lv2Manager.detachConsoleBackend();
+ lv2Manager.setupRotatableFileBackend(absoluteLogpath, serverGlobalParams.logAppend);
+ lv2Manager.reattachRotatableFileBackend();
+
+ if (serverGlobalParams.logAppend && exists) {
+ log() << "***** SERVER RESTARTED *****";
+ // FIXME rewrite for logv2
+ // Status status = logger::RotatableFileWriter::Use(writer.getValue()).status();
+ // if (!status.isOK())
+ // return status;
+ }
+
+ } else {
+ StatusWithRotatableFileWriter writer = logger::globalRotatableFileManager()->openFile(
+ absoluteLogpath, serverGlobalParams.logAppend);
+ if (!writer.isOK()) {
+ return writer.getStatus();
+ }
+ appender = std::make_unique<RotatableFileAppender<MessageEventEphemeral>>(
+ std::make_unique<MessageEventDetailsEncoder>(), writer.getValue());
+ manager->getNamedDomain("javascriptOutput")
+ ->attachAppender(std::make_unique<RotatableFileAppender<MessageEventEphemeral>>(
+ std::make_unique<MessageEventDetailsEncoder>(), writer.getValue()));
+ if (serverGlobalParams.logAppend && exists) {
+ log() << "***** SERVER RESTARTED *****";
+ Status status = logger::RotatableFileWriter::Use(writer.getValue()).status();
+ if (!status.isOK())
+ return status;
+ }
}
- LogManager* manager = logger::globalLogManager();
manager->getGlobalDomain()->clearAppenders();
- manager->getGlobalDomain()->attachAppender(
- std::make_unique<RotatableFileAppender<MessageEventEphemeral>>(
- std::make_unique<MessageEventDetailsEncoder>(), writer.getValue()));
- manager->getNamedDomain("javascriptOutput")
- ->attachAppender(std::make_unique<RotatableFileAppender<MessageEventEphemeral>>(
- std::make_unique<MessageEventDetailsEncoder>(), writer.getValue()));
-
- if (serverGlobalParams.logAppend && exists) {
- log() << "***** SERVER RESTARTED *****";
- Status status = logger::RotatableFileWriter::Use(writer.getValue()).status();
- if (!status.isOK())
- return status;
- }
+ manager->getGlobalDomain()->attachAppender(std::move(appender));
+
} else {
- logger::globalLogManager()
- ->getNamedDomain("javascriptOutput")
- ->attachAppender(std::make_unique<logger::ConsoleAppender<MessageEventEphemeral>>(
- std::make_unique<MessageEventDetailsEncoder>()));
+ if (serverGlobalParams.logV2) {
+ manager->getGlobalDomain()->clearAppenders();
+ manager->getGlobalDomain()->attachAppender(
+ std::make_unique<logger::LogV2Appender<MessageEventEphemeral>>(
+ &(lv2Manager.getGlobalDomain())));
+ } else {
+ logger::globalLogManager()
+ ->getNamedDomain("javascriptOutput")
+ ->attachAppender(std::make_unique<logger::ConsoleAppender<MessageEventEphemeral>>(
+ std::make_unique<MessageEventDetailsEncoder>()));
+ }
}
logger::globalLogDomain()->attachAppender(
diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h
index 8161061f80d..ed333a8ed13 100644
--- a/src/mongo/db/server_options.h
+++ b/src/mongo/db/server_options.h
@@ -100,7 +100,8 @@ struct ServerGlobalParams {
bool logAppend = false; // True if logging to a file in append mode.
bool logRenameOnRotate = true; // True if logging should rename log files on rotate
bool logWithSyslog = false; // True if logging to syslog; must not be set if logpath is set.
- int syslogFacility; // Facility used when appending messages to the syslog.
+ bool logV2 = false; // True if logV1 logging statements should get plumbed through to logV2
+ int syslogFacility; // Facility used when appending messages to the syslog.
#ifndef _WIN32
ProcessId parentProc; // --fork pid of initial process
diff --git a/src/mongo/db/server_options_base.idl b/src/mongo/db/server_options_base.idl
index 2f85aaaaa08..bbfafc21c9e 100644
--- a/src/mongo/db/server_options_base.idl
+++ b/src/mongo/db/server_options_base.idl
@@ -115,6 +115,10 @@ configs:
validator:
callback: validateSystemLogDestinationSetting
+ logv2:
+ description: "logging gets directed to the logv2 backend"
+ arg_vartype: Switch
+ source: [ cli, ini ]
syslog:
description: "Log to system's syslog facility instead of file or stdout"
arg_vartype: Switch
diff --git a/src/mongo/db/server_options_helpers.cpp b/src/mongo/db/server_options_helpers.cpp
index 9ff88f5c9ef..25b0db6bfac 100644
--- a/src/mongo/db/server_options_helpers.cpp
+++ b/src/mongo/db/server_options_helpers.cpp
@@ -321,6 +321,9 @@ Status storeBaseOptions(const moe::Environment& params) {
return Status(ErrorCodes::BadValue, sb.str());
}
}
+ if (params.count("logv2")) {
+ serverGlobalParams.logV2 = true;
+ }
if (params.count("systemLog.destination")) {
std::string systemLogDestination = params["systemLog.destination"].as<std::string>();
if (systemLogDestination == "file") {
diff --git a/src/mongo/logger/logv2_appender.h b/src/mongo/logger/logv2_appender.h
new file mode 100644
index 00000000000..b94401877ee
--- /dev/null
+++ b/src/mongo/logger/logv2_appender.h
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2019-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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 "mongo/base/status.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logv2/attribute_argument_set.h"
+#include "mongo/logv2/log_component.h"
+#include "mongo/logv2/log_detail.h"
+#include "mongo/logv2/log_domain.h"
+
+namespace mongo {
+namespace logger {
+
+/**
+ * Appender for writing to a logv2 domain
+ */
+template <typename Event>
+class LogV2Appender : public Appender<Event> {
+public:
+ LogV2Appender(const LogV2Appender&) = delete;
+ LogV2Appender& operator=(const LogV2Appender&) = delete;
+
+ explicit LogV2Appender(logv2::LogDomain* domain) : _domain(domain) {}
+
+ Status append(const Event& event) override {
+ logv2::detail::doLog(
+
+ // We need to cast from the v1 logging severity to the equivalent v2 severity
+ logv2::LogSeverity::cast(event.getSeverity().toInt()),
+
+ // Similarly, we need to transcode the options. They don't offer a cast
+ // operator, so we need to do some metaprogramming on the types.
+ logv2::LogOptions{logv2::LogComponent(static_cast<logv2::LogComponent::Value>(
+ static_cast<std::underlying_type_t<LogComponent::Value>>(
+ static_cast<LogComponent::Value>(event.getComponent())))),
+ _domain,
+ logv2::LogTag{}},
+
+ // stable id doesn't exist in logv1
+ StringData{},
+
+ "{} {}", // TODO remove this lv2 when it's no longer fun to have
+ "engine"_attr = "lv2",
+ "message"_attr = event.getMessage());
+ return Status::OK();
+ }
+
+private:
+ logv2::LogDomain* _domain;
+};
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logv2/SConscript b/src/mongo/logv2/SConscript
index ef31e488ce7..9772cb9c60b 100644
--- a/src/mongo/logv2/SConscript
+++ b/src/mongo/logv2/SConscript
@@ -4,43 +4,22 @@ Import("env")
env = env.Clone()
-env.Library(
- target='logv2',
- source=[
- 'attributes.cpp',
- 'console.cpp',
- 'log.cpp',
- 'log_component.cpp',
- 'log_component_settings.cpp',
- 'log_domain.cpp',
- 'log_domain_global.cpp',
- 'log_manager.cpp',
- 'log_record.cpp',
- 'log_severity.cpp',
- 'log_tag.cpp',
- 'ramlog.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- ],
- LIBDEPS_PRIVATE=[
- ],
-)
-
env.CppUnitTest(
target='log_test_v2',
source=[
'log_test_v2.cpp',
],
LIBDEPS=[
- 'logv2',
+ '$BUILD_DIR/mongo/base',
]
)
env.Benchmark(
target='logv2_bm',
- source='logv2_bm.cpp',
+ source=[
+ 'logv2_bm.cpp',
+ ],
LIBDEPS=[
- 'logv2',
+ '$BUILD_DIR/mongo/base',
],
)
diff --git a/src/mongo/logv2/log.h b/src/mongo/logv2/log.h
index adc47130aec..a27265e6283 100644
--- a/src/mongo/logv2/log.h
+++ b/src/mongo/logv2/log.h
@@ -44,6 +44,8 @@
#else // MONGO_UTIL_LOGV2_H_
#define MONGO_UTIL_LOGV2_H_
+#include <boost/preprocessor/variadic/size.hpp>
+
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
#include "mongo/logv2/attribute_argument_set.h"
@@ -52,8 +54,6 @@
#include "mongo/logv2/log_severity.h"
#include "mongo/util/errno_util.h"
-#include <boost/preprocessor/variadic/size.hpp>
-
// Provide log component in global scope so that MONGO_LOG will always have a valid component.
// Global log component will be kDefault unless overridden by MONGO_LOGV2_DEFAULT_COMPONENT.
#if defined(MONGO_LOGV2_DEFAULT_COMPONENT)
@@ -65,52 +65,11 @@ const ::mongo::logv2::LogComponent MongoLogV2DefaultComponent_component =
"Please see http://www.mongodb.org/about/contributors/reference/server-logging-rules/ "
#endif // MONGO_LOGV2_DEFAULT_COMPONENT
+// include log_detail.h and log_options.h after MONGO_LOGV2_DEFAULT_COMPONENT gets set
+#include "mongo/logv2/log_detail.h"
#include "mongo/logv2/log_options.h"
namespace mongo {
-namespace logv2 {
-namespace detail {
-void doLogImpl(LogSeverity const& severity,
- LogOptions const& options,
- StringData stable_id,
- StringData message,
- AttributeArgumentSet const& attrs);
-
-void doLogRecordImpl(LogRecord&& debugRecord,
- LogDomain& domain,
- StringData message,
- AttributeArgumentSet const& attrs);
-
-template <typename S, typename... Args>
-void doLog(LogSeverity const& severity,
- LogOptions const& options,
- StringData stable_id,
- S const& message,
- fmt::internal::named_arg<Args, char>&&... args) {
- AttributeArgumentSet attr_set;
- auto arg_store = fmt::internal::make_args_checked(message, (args.value)...);
- attr_set._values = arg_store;
- (attr_set._names.push_back(::mongo::StringData(args.name.data(), args.name.size())), ...);
- auto msg = static_cast<fmt::string_view>(message);
- doLogImpl(severity, options, stable_id, ::mongo::StringData(msg.data(), msg.size()), attr_set);
-}
-
-template <typename S, typename... Args>
-void doLogRecord(LogRecord&& record,
- LogDomain& domain,
- S const& message,
- fmt::internal::named_arg<Args, char>&&... args) {
- AttributeArgumentSet attr_set;
- auto arg_store = fmt::internal::make_args_checked(message, (args.value)...);
- attr_set._values = arg_store;
- (attr_set._names.push_back(::mongo::StringData(args.name.data(), args.name.size())), ...);
- auto msg = static_cast<fmt::string_view>(message);
- doLogRecordImpl(
- std::move(record), domain, ::mongo::StringData(msg.data(), msg.size()), attr_set);
-}
-
-} // namespace detail
-} // namespace logv2
#define LOGV2_IMPL_0(SEVERITY, OPTIONS, ID, MESSAGE) \
do { \
@@ -245,10 +204,6 @@ void doLogRecord(LogRecord&& record,
#endif // BOOST_PP_VARIADICS_MSVC
-inline fmt::internal::udl_arg<char> operator"" _attr(const char* s, std::size_t) {
- return {s};
-}
-
} // namespace mongo
#endif // MONGO_UTIL_LOGV2_H_
diff --git a/src/mongo/logv2/log_detail.cpp b/src/mongo/logv2/log_detail.cpp
new file mode 100644
index 00000000000..8b0b2aab30f
--- /dev/null
+++ b/src/mongo/logv2/log_detail.cpp
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/logv2/attributes.h"
+#include "mongo/logv2/log.h"
+#include "mongo/logv2/log_domain.h"
+#include "mongo/logv2/log_domain_impl.h"
+#include "mongo/logv2/log_options.h"
+#include "mongo/logv2/log_record_impl.h"
+#include "mongo/logv2/log_source.h"
+
+namespace mongo {
+namespace logv2 {
+namespace detail {
+
+void doLogImpl(LogSeverity const& severity,
+ LogOptions const& options,
+ StringData stable_id,
+ StringData message,
+ AttributeArgumentSet const& attrs) {
+ auto& source = options.domain().impl().source();
+ auto record = source.open_record(severity, options.component(), options.tags(), stable_id);
+ if (record) {
+ record.attribute_values().insert(
+ attributes::message(),
+ boost::log::attribute_value(
+ new boost::log::attributes::attribute_value_impl<StringData>(message)));
+
+ record.attribute_values().insert(
+ attributes::attributes(),
+ boost::log::attribute_value(
+ new boost::log::attributes::attribute_value_impl<AttributeArgumentSet>(attrs)));
+
+ source.push_record(std::move(record));
+ }
+}
+
+void doLogRecordImpl(LogRecord&& record,
+ LogDomain& domain,
+ StringData message,
+ AttributeArgumentSet const& attrs) {
+ auto& source = domain.impl().source();
+ auto rec = std::move(record.impl()->_record);
+ if (rec) {
+ rec.attribute_values().insert(
+ attributes::message(),
+ boost::log::attribute_value(
+ new boost::log::attributes::attribute_value_impl<StringData>(message)));
+
+ rec.attribute_values().insert(
+ attributes::attributes(),
+ boost::log::attribute_value(
+ new boost::log::attributes::attribute_value_impl<AttributeArgumentSet>(attrs)));
+
+ source.push_record(std::move(rec));
+ }
+}
+
+} // namespace detail
+} // namespace logv2
+} // namespace mongo
diff --git a/src/mongo/logv2/log_detail.h b/src/mongo/logv2/log_detail.h
new file mode 100644
index 00000000000..b1a1948b08e
--- /dev/null
+++ b/src/mongo/logv2/log_detail.h
@@ -0,0 +1,88 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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.
+ */
+
+#include "mongo/base/status.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/logv2/attribute_argument_set.h"
+#include "mongo/logv2/log_component.h"
+#include "mongo/logv2/log_domain.h"
+#include "mongo/logv2/log_options.h"
+#include "mongo/logv2/log_severity.h"
+#include "mongo/util/errno_util.h"
+
+namespace mongo {
+namespace logv2 {
+namespace detail {
+void doLogImpl(LogSeverity const& severity,
+ LogOptions const& options,
+ StringData stable_id,
+ StringData message,
+ AttributeArgumentSet const& attrs);
+
+void doLogRecordImpl(LogRecord&& debugRecord,
+ LogDomain& domain,
+ StringData message,
+ AttributeArgumentSet const& attrs);
+
+template <typename S, typename... Args>
+void doLog(LogSeverity const& severity,
+ LogOptions const& options,
+ StringData stable_id,
+ S const& message,
+ fmt::internal::named_arg<Args, char>&&... args) {
+ AttributeArgumentSet attr_set;
+ auto arg_store = fmt::internal::make_args_checked(message, (args.value)...);
+ attr_set._values = arg_store;
+ (attr_set._names.push_back(::mongo::StringData(args.name.data(), args.name.size())), ...);
+ auto msg = static_cast<fmt::string_view>(message);
+ doLogImpl(severity, options, stable_id, ::mongo::StringData(msg.data(), msg.size()), attr_set);
+}
+
+template <typename S, typename... Args>
+void doLogRecord(LogRecord&& record,
+ LogDomain& domain,
+ S const& message,
+ fmt::internal::named_arg<Args, char>&&... args) {
+ AttributeArgumentSet attr_set;
+ auto arg_store = fmt::internal::make_args_checked(message, (args.value)...);
+ attr_set._values = arg_store;
+ (attr_set._names.push_back(::mongo::StringData(args.name.data(), args.name.size())), ...);
+ auto msg = static_cast<fmt::string_view>(message);
+ doLogRecordImpl(
+ std::move(record), domain, ::mongo::StringData(msg.data(), msg.size()), attr_set);
+}
+
+} // namespace detail
+} // namespace logv2
+
+inline fmt::internal::udl_arg<char> operator"" _attr(const char* s, std::size_t) {
+ return {s};
+}
+
+} // namespace mongo
diff --git a/src/mongo/logv2/log_manager.cpp b/src/mongo/logv2/log_manager.cpp
index 4cd8e7d8382..420665fa62f 100644
--- a/src/mongo/logv2/log_manager.cpp
+++ b/src/mongo/logv2/log_manager.cpp
@@ -39,21 +39,61 @@
#include "mongo/logv2/ramlog_sink.h"
#include "mongo/logv2/tagged_severity_filter.h"
#include "mongo/logv2/text_formatter.h"
-
+#include "mongo/util/time_support.h"
#include <boost/core/null_deleter.hpp>
+#include <boost/filesystem/operations.hpp>
#include <boost/log/core.hpp>
#include <boost/log/sinks.hpp>
+#include <iostream>
+#include <string>
+#ifndef _WIN32
+#include <boost/log/sinks/syslog_backend.hpp>
+#endif
namespace mongo {
namespace logv2 {
+namespace {
+
+class RotateCollector : public boost::log::sinks::file::collector {
+public:
+ explicit RotateCollector(bool renameOnRotate) : _renameOnRotate{renameOnRotate} {}
+
+ void store_file(boost::filesystem::path const& file) override {
+ if (_renameOnRotate) {
+ auto renameTarget = file.string() + "." + terseCurrentTime(false);
+ boost::system::error_code ec;
+ boost::filesystem::rename(file, renameTarget, ec);
+ if (ec) {
+ // throw here or propagate this error in another way?
+ }
+ }
+ }
+
+ uintmax_t scan_for_files(boost::log::sinks::file::scan_method,
+ boost::filesystem::path const&,
+ unsigned int*) override {
+ return 0;
+ }
+
+private:
+ bool _renameOnRotate;
+};
+
+} // namespace
+
+
struct LogManager::Impl {
typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>
ConsoleBackend;
-
typedef boost::log::sinks::unlocked_sink<RamLogSink> RamLogBackend;
+#ifndef _WIN32
+ typedef boost::log::sinks::synchronous_sink<boost::log::sinks::syslog_backend> SyslogBackend;
+#endif
+ typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend>
+ RotatableFileBackend;
Impl() {
_consoleBackend = boost::make_shared<ConsoleBackend>();
@@ -75,14 +115,57 @@ struct LogManager::Impl {
_startupWarningsBackend->set_formatter(TextFormatter());
}
+ void setupSyslogBackend(int syslogFacility) {
+#ifndef _WIN32
+ // Create a backend
+ auto backend = boost::make_shared<boost::log::sinks::syslog_backend>(
+ boost::log::keywords::facility =
+ boost::log::sinks::syslog::make_facility(syslogFacility),
+ boost::log::keywords::use_impl = boost::log::sinks::syslog::native);
+
+ // // Set the straightforward level translator for the "Severity" attribute of type int
+ // backend->set_severity_mapper(
+ // boost::log::sinks::syslog::direct_severity_mapping<int>("Severity"));
+ _syslogBackend = boost::make_shared<SyslogBackend>(backend);
+ _syslogBackend->set_filter(ComponentSettingsFilter(_globalDomain.settings()));
+ _syslogBackend->set_formatter(TextFormatter());
+#endif
+ }
+
+ void setupRotatableFileBackend(std::string path, bool append) {
+
+ auto backend = boost::make_shared<boost::log::sinks::text_file_backend>(
+ boost::log::keywords::file_name = path);
+ backend->auto_flush(true);
+
+ backend->set_file_collector(boost::make_shared<RotateCollector>(!append));
+
+ _rotatableFileBackend = boost::make_shared<RotatableFileBackend>(backend);
+ _rotatableFileBackend->set_filter(ComponentSettingsFilter(_globalDomain.settings()));
+ _rotatableFileBackend->set_formatter(TextFormatter());
+ }
+
LogDomain _globalDomain{std::make_unique<LogDomainGlobal>()};
+ // I think that, technically, these are logging front ends
+ // and that they get to hold or wrap a backend
boost::shared_ptr<ConsoleBackend> _consoleBackend;
+ boost::shared_ptr<RotatableFileBackend> _rotatableFileBackend;
+#ifndef _WIN32
+ boost::shared_ptr<SyslogBackend> _syslogBackend;
+#endif
boost::shared_ptr<RamLogBackend> _globalLogCacheBackend;
boost::shared_ptr<RamLogBackend> _startupWarningsBackend;
bool _defaultBackendsAttached{false};
};
+void LogManager::rotate() {
+ if (_impl->_rotatableFileBackend) {
+ auto backend = _impl->_rotatableFileBackend->locked_backend();
+ backend->rotate_file();
+ }
+}
+
LogManager::LogManager() {
_impl = std::make_unique<Impl>();
reattachDefaultBackends();
@@ -108,6 +191,32 @@ void LogManager::detachDefaultBackends() {
_impl->_defaultBackendsAttached = false;
}
+void LogManager::detachConsoleBackend() {
+ _impl->_globalDomain.impl().core()->remove_sink(_impl->_consoleBackend);
+}
+
+void LogManager::setupRotatableFileBackend(std::string path, bool append) {
+ _impl->setupRotatableFileBackend(path, append);
+}
+
+void LogManager::setupSyslogBackend(int syslogFacility) {
+ _impl->setupSyslogBackend(syslogFacility);
+}
+
+void LogManager::reattachSyslogBackend() {
+#ifndef _WIN32
+ _impl->_globalDomain.impl().core()->add_sink(_impl->_syslogBackend);
+#endif
+}
+
+void LogManager::reattachRotatableFileBackend() {
+ _impl->_globalDomain.impl().core()->add_sink(_impl->_rotatableFileBackend);
+}
+
+void LogManager::reattachConsoleBackend() {
+ _impl->_globalDomain.impl().core()->add_sink(_impl->_consoleBackend);
+}
+
void LogManager::reattachDefaultBackends() {
invariant(!isDefaultBackendsAttached());
diff --git a/src/mongo/logv2/log_manager.h b/src/mongo/logv2/log_manager.h
index 059a3e7d019..69df533ab9a 100644
--- a/src/mongo/logv2/log_manager.h
+++ b/src/mongo/logv2/log_manager.h
@@ -30,6 +30,7 @@
#pragma once
#include <memory>
+#include <string>
namespace mongo {
namespace logv2 {
@@ -42,10 +43,10 @@ class LogDomain;
* Use this while setting up the logging system, before launching any threads.
*/
class LogManager {
+public:
LogManager(const LogManager&) = delete;
LogManager& operator=(const LogManager&) = delete;
-public:
LogManager();
~LogManager();
@@ -63,6 +64,7 @@ public:
* @note This function is not thread safe.
*/
void detachDefaultBackends();
+ void detachConsoleBackend();
/**
* Reattaches the default log backends
@@ -70,6 +72,14 @@ public:
* @note This function is not thread safe.
*/
void reattachDefaultBackends();
+ void reattachConsoleBackend();
+
+ void setupSyslogBackend(int syslogFacility);
+ void reattachSyslogBackend();
+
+ void setupRotatableFileBackend(std::string path, bool append);
+ void reattachRotatableFileBackend();
+ void rotate();
/**
* Checks if the default log backends are attached
diff --git a/src/mongo/logv2/log_options.h b/src/mongo/logv2/log_options.h
index c5d2b073762..481c98db403 100644
--- a/src/mongo/logv2/log_options.h
+++ b/src/mongo/logv2/log_options.h
@@ -46,6 +46,9 @@ public:
LogOptions(LogTag tags) : _tags(tags) {}
+ LogOptions(LogComponent component, LogDomain* domain, LogTag tags)
+ : _domain(domain), _tags(tags), _component(component) {}
+
LogComponent component() const {
return _component;
}
@@ -61,7 +64,11 @@ public:
private:
LogDomain* _domain = &LogManager::global().getGlobalDomain();
LogTag _tags;
+#ifdef MONGO_LOGV2_DEFAULT_COMPONENT
LogComponent _component = MongoLogV2DefaultComponent_component;
+#else
+ LogComponent _component = LogComponent::kDefault;
+#endif // MONGO_LOGV2_DEFAULT_COMPONENT
};
} // namespace logv2
diff --git a/src/mongo/util/log.cpp b/src/mongo/util/log.cpp
index a46186d8a83..62e8ba95bd6 100644
--- a/src/mongo/util/log.cpp
+++ b/src/mongo/util/log.cpp
@@ -28,15 +28,19 @@
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl
+#define MONGO_LOGV2_DEFAULT_COMPONENT mongo::logv2::LogComponent::kControl
+
#include "mongo/platform/basic.h"
#include "mongo/util/log.h"
+#include "mongo/db/server_options.h"
#include "mongo/logger/console_appender.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/logger/ramlog.h"
#include "mongo/logger/rotatable_file_manager.h"
+#include "mongo/logv2/log.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/stacktrace.h"
@@ -61,7 +65,12 @@ Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) {
return Status::OK();
}
-bool rotateLogs(bool renameFiles) {
+bool rotateLogs(bool renameFiles, bool useLogV2) {
+ if (useLogV2) {
+ log() << "Logv2 rotation initiated";
+ ::mongo::logv2::LogManager::global().rotate();
+ return true;
+ }
using logger::RotatableFileManager;
RotatableFileManager* manager = logger::globalRotatableFileManager();
log() << "Log rotation initiated";
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index 2f9cc2442ba..24a321892e4 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -235,7 +235,7 @@ inline bool shouldLog(logger::LogSeverity severity) {
* We expect logrotate to rename the existing file before we rotate, and so the next open
* we do should result in a file create.
*/
-bool rotateLogs(bool renameFiles);
+bool rotateLogs(bool renameFiles, bool useLogV2);
extern Tee* const warnings; // Things put here go in serverStatus
extern Tee* const startupWarningsLog; // Things put here get reported in MMS
diff --git a/src/mongo/util/signal_handlers.cpp b/src/mongo/util/signal_handlers.cpp
index f4ff57e8238..eb1ae13d6ea 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -187,7 +187,8 @@ void signalProcessingThread(LogFileStatus rotate) {
}
lastSignalTimeSeconds = signalTimeSeconds;
- fassert(16782, rotateLogs(serverGlobalParams.logRenameOnRotate));
+ fassert(16782,
+ rotateLogs(serverGlobalParams.logRenameOnRotate, serverGlobalParams.logV2));
if (rotate == LogFileStatus::kNeedToRotateLogFile) {
logProcessDetailsForLogRotate(getGlobalServiceContext());
}
diff --git a/src/third_party/boost-1.70.0/SConscript b/src/third_party/boost-1.70.0/SConscript
index babb7c3e4c0..12d11298e4f 100644
--- a/src/third_party/boost-1.70.0/SConscript
+++ b/src/third_party/boost-1.70.0/SConscript
@@ -142,6 +142,7 @@ loglib_env.Library(
'libs/log/src/record_ostream.cpp',
'libs/log/src/severity_level.cpp',
'libs/log/src/spirit_encoding.cpp',
+ 'libs/log/src/syslog_backend.cpp' if not env.TargetOSIs('windows') else [],
'libs/log/src/text_file_backend.cpp',
'libs/log/src/text_multifile_backend.cpp',
'libs/log/src/text_ostream_backend.cpp',