From d7827a40dfa30bfaa2e3c275ea4bf07d8a1cd159 Mon Sep 17 00:00:00 2001 From: Gabriel Russell Date: Thu, 3 Oct 2019 21:15:40 +0000 Subject: SERVER-42726 enable logging via logv2 --- SConstruct | 1 + src/mongo/SConscript | 14 ++- src/mongo/db/commands/generic_servers.cpp | 2 +- src/mongo/db/initialize_server_global_state.cpp | 110 ++++++++++++++++------- src/mongo/db/server_options.h | 3 +- src/mongo/db/server_options_base.idl | 4 + src/mongo/db/server_options_helpers.cpp | 3 + src/mongo/logger/logv2_appender.h | 81 +++++++++++++++++ src/mongo/logv2/SConscript | 31 ++----- src/mongo/logv2/log.h | 53 +---------- src/mongo/logv2/log_detail.cpp | 91 +++++++++++++++++++ src/mongo/logv2/log_detail.h | 88 ++++++++++++++++++ src/mongo/logv2/log_manager.cpp | 113 +++++++++++++++++++++++- src/mongo/logv2/log_manager.h | 12 ++- src/mongo/logv2/log_options.h | 7 ++ src/mongo/util/log.cpp | 11 ++- src/mongo/util/log.h | 2 +- src/mongo/util/signal_handlers.cpp | 3 +- src/third_party/boost-1.70.0/SConscript | 1 + 19 files changed, 513 insertions(+), 117 deletions(-) create mode 100644 src/mongo/logger/logv2_appender.h create mode 100644 src/mongo/logv2/log_detail.cpp create mode 100644 src/mongo/logv2/log_detail.h 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> 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>( + &(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>( + std::make_unique()); + manager->getNamedDomain("javascriptOutput") + ->attachAppender(std::make_unique>( + std::make_unique())); + } manager->getGlobalDomain()->clearAppenders(); - manager->getGlobalDomain()->attachAppender( - std::make_unique>( - std::make_unique())); - manager->getNamedDomain("javascriptOutput") - ->attachAppender(std::make_unique>( - std::make_unique())); + 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> appender; + + if (serverGlobalParams.logV2) { + + appender = std::make_unique>( + &(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>( + std::make_unique(), writer.getValue()); + manager->getNamedDomain("javascriptOutput") + ->attachAppender(std::make_unique>( + std::make_unique(), 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>( - std::make_unique(), writer.getValue())); - manager->getNamedDomain("javascriptOutput") - ->attachAppender(std::make_unique>( - std::make_unique(), 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>( - std::make_unique())); + if (serverGlobalParams.logV2) { + manager->getGlobalDomain()->clearAppenders(); + manager->getGlobalDomain()->attachAppender( + std::make_unique>( + &(lv2Manager.getGlobalDomain()))); + } else { + logger::globalLogManager() + ->getNamedDomain("javascriptOutput") + ->attachAppender(std::make_unique>( + std::make_unique())); + } } 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(); 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 + * . + * + * 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 +class LogV2Appender : public Appender { +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( + static_cast>( + static_cast(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 + #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 - // 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 -void doLog(LogSeverity const& severity, - LogOptions const& options, - StringData stable_id, - S const& message, - fmt::internal::named_arg&&... 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(message); - doLogImpl(severity, options, stable_id, ::mongo::StringData(msg.data(), msg.size()), attr_set); -} - -template -void doLogRecord(LogRecord&& record, - LogDomain& domain, - S const& message, - fmt::internal::named_arg&&... 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(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 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 + * . + * + * 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(message))); + + record.attribute_values().insert( + attributes::attributes(), + boost::log::attribute_value( + new boost::log::attributes::attribute_value_impl(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(message))); + + rec.attribute_values().insert( + attributes::attributes(), + boost::log::attribute_value( + new boost::log::attributes::attribute_value_impl(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 + * . + * + * 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 +void doLog(LogSeverity const& severity, + LogOptions const& options, + StringData stable_id, + S const& message, + fmt::internal::named_arg&&... 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(message); + doLogImpl(severity, options, stable_id, ::mongo::StringData(msg.data(), msg.size()), attr_set); +} + +template +void doLogRecord(LogRecord&& record, + LogDomain& domain, + S const& message, + fmt::internal::named_arg&&... 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(message); + doLogRecordImpl( + std::move(record), domain, ::mongo::StringData(msg.data(), msg.size()), attr_set); +} + +} // namespace detail +} // namespace logv2 + +inline fmt::internal::udl_arg 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 +#include #include #include +#include +#include +#ifndef _WIN32 +#include +#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 ConsoleBackend; - typedef boost::log::sinks::unlocked_sink RamLogBackend; +#ifndef _WIN32 + typedef boost::log::sinks::synchronous_sink SyslogBackend; +#endif + typedef boost::log::sinks::synchronous_sink + RotatableFileBackend; Impl() { _consoleBackend = boost::make_shared(); @@ -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::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("Severity")); + _syslogBackend = boost::make_shared(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::keywords::file_name = path); + backend->auto_flush(true); + + backend->set_file_collector(boost::make_shared(!append)); + + _rotatableFileBackend = boost::make_shared(backend); + _rotatableFileBackend->set_filter(ComponentSettingsFilter(_globalDomain.settings())); + _rotatableFileBackend->set_formatter(TextFormatter()); + } + LogDomain _globalDomain{std::make_unique()}; + // I think that, technically, these are logging front ends + // and that they get to hold or wrap a backend boost::shared_ptr _consoleBackend; + boost::shared_ptr _rotatableFileBackend; +#ifndef _WIN32 + boost::shared_ptr _syslogBackend; +#endif boost::shared_ptr _globalLogCacheBackend; boost::shared_ptr _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(); 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 +#include 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', -- cgit v1.2.1