summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/evergreen.yml1
-rw-r--r--jstests/noPassthroughWithMongod/logpath.js1
-rw-r--r--src/mongo/SConscript2
-rw-r--r--src/mongo/db/commands/generic_servers.cpp2
-rw-r--r--src/mongo/logv2/file_rotate_sink.cpp128
-rw-r--r--src/mongo/logv2/file_rotate_sink.h57
-rw-r--r--src/mongo/logv2/log_domain_global.cpp56
-rw-r--r--src/mongo/logv2/log_domain_global.h2
-rw-r--r--src/mongo/logv2/shared_access_fstream.cpp296
-rw-r--r--src/mongo/logv2/shared_access_fstream.h137
-rw-r--r--src/mongo/util/log.cpp20
-rw-r--r--src/mongo/util/log.h2
-rw-r--r--src/mongo/util/signal_handlers.cpp2
-rw-r--r--src/mongo/util/text.cpp23
-rw-r--r--src/mongo/util/text.h1
15 files changed, 673 insertions, 57 deletions
diff --git a/etc/evergreen.yml b/etc/evergreen.yml
index b499595afd7..92f572029cf 100644
--- a/etc/evergreen.yml
+++ b/etc/evergreen.yml
@@ -9285,7 +9285,6 @@ buildvariants:
# spawning a large number of linker processes.
num_scons_link_jobs_available: $(( $(grep -c ^processor /proc/cpuinfo) / 4 ))
python: '/cygdrive/c/python/python37/python.exe'
- test_flags: --excludeWithAnyTags=SERVER-45989
ext: zip
scons_cache_scope: shared
multiversion_platform: windows
diff --git a/jstests/noPassthroughWithMongod/logpath.js b/jstests/noPassthroughWithMongod/logpath.js
index 7f7aecd0bf6..bb39282871f 100644
--- a/jstests/noPassthroughWithMongod/logpath.js
+++ b/jstests/noPassthroughWithMongod/logpath.js
@@ -1,5 +1,4 @@
// check replica set authentication
-// @tags: [SERVER-45989]
var name = "logpath";
var token = "logpath_token";
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index c94521e3886..f1d4f64e9e3 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -112,6 +112,7 @@ baseEnv.Library(
'logv2/attributes.cpp',
'logv2/bson_formatter.cpp',
'logv2/console.cpp',
+ 'logv2/file_rotate_sink.cpp',
'logv2/json_formatter.cpp',
'logv2/log_component.cpp',
'logv2/log_component_settings.cpp',
@@ -123,6 +124,7 @@ baseEnv.Library(
'logv2/log_severity.cpp',
'logv2/log_tag.cpp',
'logv2/plain_formatter.cpp',
+ 'logv2/shared_access_fstream.cpp',
'logv2/ramlog.cpp',
'logv2/text_formatter.cpp',
'platform/decimal128.cpp',
diff --git a/src/mongo/db/commands/generic_servers.cpp b/src/mongo/db/commands/generic_servers.cpp
index 5ddd102c366..b398e6d59f2 100644
--- a/src/mongo/db/commands/generic_servers.cpp
+++ b/src/mongo/db/commands/generic_servers.cpp
@@ -196,7 +196,7 @@ public:
const std::string& ns,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
- bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate, logV2Enabled());
+ bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate);
if (didRotate)
logProcessDetailsForLogRotate(opCtx->getServiceContext());
return didRotate;
diff --git a/src/mongo/logv2/file_rotate_sink.cpp b/src/mongo/logv2/file_rotate_sink.cpp
new file mode 100644
index 00000000000..c0ca2ac91ee
--- /dev/null
+++ b/src/mongo/logv2/file_rotate_sink.cpp
@@ -0,0 +1,128 @@
+/**
+ * Copyright (C) 2020-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/logv2/file_rotate_sink.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/make_shared.hpp>
+#include <fmt/format.h>
+#include <fstream>
+
+#include "mongo/logv2/shared_access_fstream.h"
+#include "mongo/util/string_map.h"
+
+
+namespace mongo::logv2 {
+namespace {
+#if _WIN32
+using stream_t = Win32SharedAccessOfstream;
+#else
+using stream_t = std::ofstream;
+#endif
+
+StatusWith<boost::shared_ptr<stream_t>> openFile(const std::string& filename, bool append) {
+ std::ios_base::openmode mode = std::ios_base::out;
+ if (append)
+ mode |= std::ios_base::app;
+ else
+ mode |= std::ios_base::trunc;
+ auto file = boost::make_shared<stream_t>(filename, mode);
+ if (file->fail())
+ return Status(ErrorCodes::FileNotOpen, fmt::format("Failed to open {}", filename));
+ return file;
+}
+} // namespace
+
+struct FileRotateSink::Impl {
+ StringMap<boost::shared_ptr<stream_t>> files;
+};
+
+FileRotateSink::FileRotateSink() : _impl(std::make_unique<Impl>()) {}
+FileRotateSink::~FileRotateSink() {}
+
+Status FileRotateSink::addFile(const std::string& filename, bool append) {
+ auto statusWithFile = openFile(filename, append);
+ if (statusWithFile.isOK()) {
+ add_stream(statusWithFile.getValue());
+ _impl->files[filename] = statusWithFile.getValue();
+ }
+
+ return statusWithFile.getStatus();
+}
+void FileRotateSink::removeFile(const std::string& filename) {
+ auto it = _impl->files.find(filename);
+ if (it != _impl->files.cend()) {
+ remove_stream(it->second);
+ _impl->files.erase(it);
+ }
+}
+
+Status FileRotateSink::rotate(bool rename, StringData renameSuffix) {
+ for (auto& file : _impl->files) {
+ const std::string& filename = file.first;
+ if (rename) {
+ std::string renameTarget = filename + renameSuffix;
+ try {
+ if (boost::filesystem::exists(renameTarget)) {
+ return Status(
+ ErrorCodes::FileRenameFailed,
+ fmt::format("Renaming file {} to {} failed; destination already exists",
+ filename,
+ renameTarget));
+ }
+ } catch (const std::exception& e) {
+ return Status(ErrorCodes::FileRenameFailed,
+ fmt::format("Renaming file {} to {} failed; Cannot verify whether "
+ "destination already exists: {}",
+ filename,
+ renameTarget,
+ e.what()));
+ }
+
+ boost::system::error_code ec;
+ boost::filesystem::rename(filename, renameTarget, ec);
+ if (ec) {
+ return Status(
+ ErrorCodes::FileRenameFailed,
+ fmt::format(
+ "Failed to rename {} to {}: {}", filename, renameTarget, ec.message()));
+ }
+ }
+
+ auto newFile = openFile(filename, false);
+ if (newFile.isOK()) {
+ file.second = newFile.getValue();
+ }
+ return newFile.getStatus();
+ }
+
+ return Status::OK();
+}
+
+} // namespace mongo::logv2
diff --git a/src/mongo/logv2/file_rotate_sink.h b/src/mongo/logv2/file_rotate_sink.h
new file mode 100644
index 00000000000..56f12215750
--- /dev/null
+++ b/src/mongo/logv2/file_rotate_sink.h
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2020-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 <boost/log/sinks/text_ostream_backend.hpp>
+#include <memory>
+#include <string>
+
+#include "mongo/base/status.h"
+
+namespace mongo::logv2 {
+// boost::log backend sink to provide MongoDB style file rotation.
+// Uses custom stream type to open log files with shared access on Windows, somthing the built-in
+// boost file rotation sink does not do.
+class FileRotateSink : public boost::log::sinks::text_ostream_backend {
+public:
+ FileRotateSink();
+ ~FileRotateSink();
+
+ Status addFile(const std::string& filename, bool append);
+ void removeFile(const std::string& filename);
+
+ Status rotate(bool rename, StringData renameSuffix);
+
+private:
+ struct Impl;
+ std::unique_ptr<Impl> _impl;
+};
+
+} // namespace mongo::logv2
diff --git a/src/mongo/logv2/log_domain_global.cpp b/src/mongo/logv2/log_domain_global.cpp
index bc9d512f176..d80be9f65d7 100644
--- a/src/mongo/logv2/log_domain_global.cpp
+++ b/src/mongo/logv2/log_domain_global.cpp
@@ -32,9 +32,11 @@
#include "mongo/logv2/component_settings_filter.h"
#include "mongo/logv2/composite_backend.h"
#include "mongo/logv2/console.h"
+#include "mongo/logv2/file_rotate_sink.h"
#include "mongo/logv2/json_formatter.h"
#include "mongo/logv2/log_source.h"
#include "mongo/logv2/ramlog_sink.h"
+#include "mongo/logv2/shared_access_fstream.h"
#include "mongo/logv2/tagged_severity_filter.h"
#include "mongo/logv2/text_formatter.h"
@@ -45,35 +47,6 @@
namespace mongo {
namespace logv2 {
-namespace {
-
-class RotateCollector : public boost::log::sinks::file::collector {
-public:
- explicit RotateCollector(LogDomainGlobal::ConfigurationOptions const& options)
- : _mode{options._fileRotationMode} {}
-
- void store_file(boost::filesystem::path const& file) override {
- if (_mode == LogDomainGlobal::ConfigurationOptions::RotationMode::kRename) {
- 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:
- LogDomainGlobal::ConfigurationOptions::RotationMode _mode;
-};
-
-} // namespace
void LogDomainGlobal::ConfigurationOptions::makeDisabled() {
_consoleEnabled = false;
@@ -86,12 +59,11 @@ struct LogDomainGlobal::Impl {
typedef CompositeBackend<boost::log::sinks::syslog_backend, RamLogSink, RamLogSink>
SyslogBackend;
#endif
- typedef CompositeBackend<boost::log::sinks::text_file_backend, RamLogSink, RamLogSink>
- RotatableFileBackend;
+ typedef CompositeBackend<FileRotateSink, RamLogSink, RamLogSink> RotatableFileBackend;
Impl(LogDomainGlobal& parent);
Status configure(LogDomainGlobal::ConfigurationOptions const& options);
- Status rotate();
+ Status rotate(bool rename, StringData renameSuffix);
LogDomainGlobal& _parent;
LogComponentSettings _settings;
@@ -171,16 +143,16 @@ Status LogDomainGlobal::Impl::configure(LogDomainGlobal::ConfigurationOptions co
if (options._fileEnabled) {
auto backend = boost::make_shared<RotatableFileBackend>(
- boost::make_shared<boost::log::sinks::text_file_backend>(
- boost::log::keywords::file_name = options._filePath),
+ boost::make_shared<FileRotateSink>(),
boost::make_shared<RamLogSink>(RamLog::get("global")),
boost::make_shared<RamLogSink>(RamLog::get("startupWarnings")));
-
+ Status ret = backend->lockedBackend<0>()->addFile(
+ options._filePath,
+ options._fileOpenMode == ConfigurationOptions::OpenMode::kAppend ? true : false);
+ if (!ret.isOK())
+ return ret;
backend->lockedBackend<0>()->auto_flush(true);
- backend->lockedBackend<0>()->set_file_collector(
- boost::make_shared<RotateCollector>(options));
-
_rotatableFileSink =
boost::make_shared<boost::log::sinks::unlocked_sink<RotatableFileBackend>>(backend);
_rotatableFileSink->set_filter(ComponentSettingsFilter(_parent, _settings));
@@ -214,10 +186,10 @@ Status LogDomainGlobal::Impl::configure(LogDomainGlobal::ConfigurationOptions co
return Status::OK();
}
-Status LogDomainGlobal::Impl::rotate() {
+Status LogDomainGlobal::Impl::rotate(bool rename, StringData renameSuffix) {
if (_rotatableFileSink) {
auto backend = _rotatableFileSink->locked_backend()->lockedBackend<0>();
- backend->rotate_file();
+ return backend->rotate(rename, renameSuffix);
}
return Status::OK();
}
@@ -239,8 +211,8 @@ Status LogDomainGlobal::configure(LogDomainGlobal::ConfigurationOptions const& o
return _impl->configure(options);
}
-Status LogDomainGlobal::rotate() {
- return _impl->rotate();
+Status LogDomainGlobal::rotate(bool rename, StringData renameSuffix) {
+ return _impl->rotate(rename, renameSuffix);
}
LogComponentSettings& LogDomainGlobal::settings() {
diff --git a/src/mongo/logv2/log_domain_global.h b/src/mongo/logv2/log_domain_global.h
index afc943db4d3..03a09562c07 100644
--- a/src/mongo/logv2/log_domain_global.h
+++ b/src/mongo/logv2/log_domain_global.h
@@ -58,7 +58,7 @@ public:
LogSource& source() override;
Status configure(ConfigurationOptions const& options);
- Status rotate();
+ Status rotate(bool rename, StringData renameSuffix);
LogComponentSettings& settings();
diff --git a/src/mongo/logv2/shared_access_fstream.cpp b/src/mongo/logv2/shared_access_fstream.cpp
new file mode 100644
index 00000000000..2179e27fe6c
--- /dev/null
+++ b/src/mongo/logv2/shared_access_fstream.cpp
@@ -0,0 +1,296 @@
+/**
+ * Copyright (C) 2020-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/platform/basic.h"
+
+#include "mongo/logv2/shared_access_fstream.h"
+
+#if defined(_WIN32) && defined(_MSC_VER)
+
+#include <fcntl.h>
+#include <filesystem>
+#include <io.h>
+
+#include "mongo/util/text.h"
+
+namespace mongo {
+FILE* Win32SharedAccessFileDescriptor::_open(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess) {
+ const char* fdmode = nullptr;
+ int openflags = 0;
+ uint32_t desiredAccess = 0;
+ uint32_t creationDisposition = 0;
+ uint32_t shareMode = FILE_SHARE_DELETE | FILE_SHARE_READ;
+ if (sharedWriteAccess)
+ shareMode |= FILE_SHARE_WRITE;
+
+ // The combinations are taken from https://en.cppreference.com/w/cpp/io/basic_filebuf/open
+ auto modeWithoutAte = mode & ~std::ios_base::ate;
+ if (modeWithoutAte == std::ios_base::in) {
+ fdmode = "r";
+ creationDisposition = OPEN_EXISTING;
+ openflags |= _O_RDONLY;
+ } else if (modeWithoutAte == std::ios_base::out ||
+ modeWithoutAte == (std::ios_base::out | std::ios_base::trunc)) {
+ fdmode = "w";
+ creationDisposition = CREATE_ALWAYS;
+ openflags |= _O_WRONLY;
+ } else if (modeWithoutAte == std::ios_base::app ||
+ modeWithoutAte == (std::ios_base::out | std::ios_base::app)) {
+
+ fdmode = "a";
+ creationDisposition = OPEN_ALWAYS;
+ openflags |= _O_WRONLY | _O_APPEND;
+ } else if (modeWithoutAte == (std::ios_base::out | std::ios_base::in)) {
+
+ fdmode = "r+";
+ creationDisposition = OPEN_EXISTING;
+ openflags |= _O_RDWR;
+ } else if (modeWithoutAte == (std::ios_base::out | std::ios_base::in | std::ios_base::trunc)) {
+
+ fdmode = "w+";
+ creationDisposition = CREATE_ALWAYS;
+ openflags |= _O_RDWR;
+ } else if (modeWithoutAte == (std::ios_base::out | std::ios_base::in | std::ios_base::app) ||
+ modeWithoutAte == (std::ios_base::in | std::ios_base::app)) {
+ fdmode = "a+";
+ creationDisposition = OPEN_ALWAYS;
+ openflags |= _O_RDWR;
+ } else if (modeWithoutAte == (std::ios_base::binary | std::ios_base::in)) {
+
+ fdmode = "rb";
+ creationDisposition = OPEN_EXISTING;
+ openflags |= _O_RDONLY;
+ } else if (modeWithoutAte == (std::ios_base::binary | std::ios_base::out) ||
+ modeWithoutAte ==
+ (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc)) {
+
+ fdmode = "wb";
+ creationDisposition = CREATE_ALWAYS;
+ openflags |= _O_WRONLY;
+ } else if (modeWithoutAte == (std::ios_base::binary | std::ios_base::app) ||
+ modeWithoutAte ==
+ (std::ios_base::binary | std::ios_base::out | std::ios_base::app)) {
+
+ fdmode = "ab";
+ creationDisposition = OPEN_ALWAYS;
+ openflags |= _O_WRONLY;
+ } else if (modeWithoutAte == (std::ios_base::binary | std::ios_base::out | std::ios_base::in)) {
+
+ fdmode = "r+b";
+ creationDisposition = OPEN_EXISTING;
+ openflags |= _O_RDWR;
+ } else if (modeWithoutAte ==
+ (std::ios_base::binary | std::ios_base::out | std::ios_base::in |
+ std::ios_base::trunc)) {
+
+ fdmode = "w+b";
+ creationDisposition = CREATE_ALWAYS;
+ openflags |= _O_RDWR;
+ } else if (modeWithoutAte ==
+ (std::ios_base::binary | std::ios_base::out | std::ios_base::in |
+ std::ios_base::app) ||
+ modeWithoutAte == (std::ios_base::binary | std::ios_base::in | std::ios_base::app)) {
+
+ fdmode = "a+b";
+ creationDisposition = OPEN_ALWAYS;
+ openflags |= _O_RDWR;
+ } else
+ return nullptr;
+
+ if (mode & std::ios_base::in)
+ desiredAccess |= GENERIC_READ;
+ if (mode & std::ios_base::out || mode & std::ios_base::app)
+ desiredAccess |= GENERIC_WRITE;
+
+ if (mode & std::ios_base::binary)
+ openflags |= _O_BINARY;
+ else
+ openflags |= _O_U8TEXT;
+
+ if (mode & std::ios_base::trunc)
+ openflags |= _O_TRUNC;
+
+ // Open file with share access to get a Windows HANDLE
+ HANDLE handle = CreateFileW(filename, // lpFileName
+ desiredAccess, // dwDesiredAccess
+ shareMode, // dwShareMode
+ nullptr, // lpSecurityAttributes
+ creationDisposition, // dwCreationDisposition
+ FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
+ nullptr // hTemplateFile
+ );
+ if (handle == INVALID_HANDLE_VALUE) {
+ return nullptr;
+ }
+
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0LL;
+ if (mode & std::ios_base::ate ||
+ ((mode & std::ios_base::app) && (openflags & _O_APPEND) == 0)) {
+ SetFilePointerEx(handle, zero, nullptr, FILE_END);
+ }
+
+ if (mode & std::ios_base::trunc) {
+ SetEndOfFile(handle);
+ }
+
+ // Convert the HANDLE to a file descriptor
+ int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle), openflags);
+ if (fd == -1) {
+ CloseHandle(handle);
+ return nullptr;
+ }
+
+ // Open the file descriptor to get a FILE*
+ return _fdopen(fd, fdmode);
+}
+
+FILE* Win32SharedAccessFileDescriptor::_open(StringData filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess) {
+ return _open(toWideStringFromStringData(filename).c_str(), mode, sharedWriteAccess);
+}
+
+Win32SharedAccessFileDescriptor::Win32SharedAccessFileDescriptor(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : _file(_open(filename, mode, sharedWriteAccess)) {}
+Win32SharedAccessFileDescriptor::Win32SharedAccessFileDescriptor(const char* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : _file(_open(filename, mode, sharedWriteAccess)) {}
+Win32SharedAccessFileDescriptor::Win32SharedAccessFileDescriptor(const std::string& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : _file(_open(filename.c_str(), mode, sharedWriteAccess)) {}
+Win32SharedAccessFileDescriptor::Win32SharedAccessFileDescriptor(
+ const std::filesystem::path& filename, std::ios_base::openmode mode, bool sharedWriteAccess)
+ : _file(_open(filename.c_str(), mode, sharedWriteAccess)) {}
+
+Win32SharedAccessOfstream::Win32SharedAccessOfstream(const char* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ofstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessOfstream::Win32SharedAccessOfstream(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ofstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessOfstream::Win32SharedAccessOfstream(const std::string& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ofstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessOfstream::Win32SharedAccessOfstream(const std::filesystem::path& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ofstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessIfstream::Win32SharedAccessIfstream(const char* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ifstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessIfstream::Win32SharedAccessIfstream(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ifstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessIfstream::Win32SharedAccessIfstream(const std::string& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ifstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessIfstream::Win32SharedAccessIfstream(const std::filesystem::path& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::ifstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessFstream::Win32SharedAccessFstream(const char* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::fstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessFstream::Win32SharedAccessFstream(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::fstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessFstream::Win32SharedAccessFstream(const std::string& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::fstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+Win32SharedAccessFstream::Win32SharedAccessFstream(const std::filesystem::path& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess)
+ : Win32SharedAccessFileDescriptor(filename, mode, sharedWriteAccess), std::fstream(_file) {
+ if (!_file)
+ setstate(failbit);
+}
+
+} // namespace mongo
+
+#endif // _WIN32 && _MSC_VER
diff --git a/src/mongo/logv2/shared_access_fstream.h b/src/mongo/logv2/shared_access_fstream.h
new file mode 100644
index 00000000000..6157705a5be
--- /dev/null
+++ b/src/mongo/logv2/shared_access_fstream.h
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2020-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
+
+#if defined(_WIN32) && defined(_MSC_VER)
+
+#include <fstream>
+
+#include "mongo/base/string_data.h"
+
+namespace mongo {
+// Helper class to open a FILE* with shared access. Used by the stream classes below.
+class Win32SharedAccessFileDescriptor {
+protected:
+ Win32SharedAccessFileDescriptor(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess);
+ Win32SharedAccessFileDescriptor(const char* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess);
+ Win32SharedAccessFileDescriptor(const std::string& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess);
+ Win32SharedAccessFileDescriptor(const std::filesystem::path& filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess);
+
+ static FILE* _open(const wchar_t* filename,
+ std::ios_base::openmode mode,
+ bool sharedWriteAccess);
+ static FILE* _open(StringData filename, std::ios_base::openmode mode, bool sharedWriteAccess);
+
+ FILE* _file = nullptr;
+};
+
+// File stream classes that extends the regular file streams with two capabilities:
+// (1) Opens files with shared delete and read access with optional shared write access.
+// (2) Uses UTF-8 as the encoding for the filename parameter
+class Win32SharedAccessOfstream : private Win32SharedAccessFileDescriptor, public std::ofstream {
+public:
+ explicit Win32SharedAccessOfstream(const char* filename,
+ ios_base::openmode mode = ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessOfstream(const wchar_t* filename,
+ ios_base::openmode mode = ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessOfstream(const std::string& filename,
+ ios_base::openmode mode = ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessOfstream(const std::filesystem::path& filename,
+ ios_base::openmode mode = ios_base::out,
+ bool sharedWriteAccess = false);
+
+ // The Visual Studio extension that operates on FILE* does not have an open overload. Needs to
+ // open with constructor.
+ void open(const char* filename, ios_base::openmode mode) = delete;
+ void open(const wchar_t* filename, ios_base::openmode mode) = delete;
+ void open(const std::string& filename, ios_base::openmode mode) = delete;
+ void open(const std::filesystem::path& filename, ios_base::openmode mode) = delete;
+};
+
+class Win32SharedAccessIfstream : private Win32SharedAccessFileDescriptor, public std::ifstream {
+public:
+ explicit Win32SharedAccessIfstream(const char* filename,
+ ios_base::openmode mode = ios_base::in,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessIfstream(const wchar_t* filename,
+ ios_base::openmode mode = ios_base::in,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessIfstream(const std::string& filename,
+ ios_base::openmode mode = ios_base::in,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessIfstream(const std::filesystem::path& filename,
+ ios_base::openmode mode = ios_base::in,
+ bool sharedWriteAccess = false);
+
+ // The Visual Studio extension that operates on FILE* does not have an open overload. Needs to
+ // open with constructor.
+ void open(const char* filename, ios_base::openmode mode) = delete;
+ void open(const wchar_t* filename, ios_base::openmode mode) = delete;
+ void open(const std::string& filename, ios_base::openmode mode) = delete;
+ void open(const std::filesystem::path& filename, ios_base::openmode mode) = delete;
+};
+
+class Win32SharedAccessFstream : private Win32SharedAccessFileDescriptor, public std::fstream {
+public:
+ explicit Win32SharedAccessFstream(const char* filename,
+ ios_base::openmode mode = ios_base::in | ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessFstream(const wchar_t* filename,
+ ios_base::openmode mode = ios_base::in | ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessFstream(const std::string& filename,
+ ios_base::openmode mode = ios_base::in | ios_base::out,
+ bool sharedWriteAccess = false);
+ explicit Win32SharedAccessFstream(const std::filesystem::path& filename,
+ ios_base::openmode mode = ios_base::in | ios_base::out,
+ bool sharedWriteAccess = false);
+
+ // The Visual Studio extension that operates on FILE* does not have an open overload. Needs to
+ // open with constructor.
+ void open(const char* filename, ios_base::openmode mode) = delete;
+ void open(const wchar_t* filename, ios_base::openmode mode) = delete;
+ void open(const std::string& filename, ios_base::openmode mode) = delete;
+ void open(const std::filesystem::path& filename, ios_base::openmode mode) = delete;
+};
+
+} // namespace mongo
+
+#endif // _WIN32
diff --git a/src/mongo/util/log.cpp b/src/mongo/util/log.cpp
index 837f80cafd8..9a9d7099e4a 100644
--- a/src/mongo/util/log.cpp
+++ b/src/mongo/util/log.cpp
@@ -82,22 +82,24 @@ Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) {
return Status::OK();
}
-bool rotateLogs(bool renameFiles, bool useLogV2) {
- if (useLogV2) {
- log() << "Logv2 rotation initiated";
- return logv2::LogManager::global().getGlobalDomainInternal().rotate().isOK();
- }
+bool rotateLogs(bool renameFiles) {
+ // Rotate on both logv1 and logv2 so all files that need rotation gets rotated
+ log() << "Log rotation initiated";
+ std::string suffix = "." + terseCurrentTime(false);
+ Status resultv2 =
+ logv2::LogManager::global().getGlobalDomainInternal().rotate(renameFiles, suffix);
+ if (!resultv2.isOK())
+ warning() << "Log rotation failed: " << resultv2;
+
using logger::RotatableFileManager;
RotatableFileManager* manager = logger::globalRotatableFileManager();
- log() << "Log rotation initiated";
- RotatableFileManager::FileNameStatusPairVector result(
- manager->rotateAll(renameFiles, "." + terseCurrentTime(false)));
+ RotatableFileManager::FileNameStatusPairVector result(manager->rotateAll(renameFiles, suffix));
for (RotatableFileManager::FileNameStatusPairVector::iterator it = result.begin();
it != result.end();
it++) {
warning() << "Rotating log file " << it->first << " failed: " << it->second.toString();
}
- return result.empty();
+ return resultv2.isOK() && result.empty();
}
void logContext(const char* errmsg) {
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index 145b41c5a6f..cfe42dd8695 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -214,7 +214,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 useLogV2);
+bool rotateLogs(bool renameFiles);
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 47582a9ae84..20e82cbc0ea 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -215,7 +215,7 @@ void handleOneSignal(const SignalWaitResult& waited, LogRotationState* rotation)
return;
rotation->previous = now;
}
- fassert(16782, rotateLogs(serverGlobalParams.logRenameOnRotate, logV2Enabled()));
+ fassert(16782, rotateLogs(serverGlobalParams.logRenameOnRotate));
if (rotation->logFileStatus == LogFileStatus::kNeedToRotateLogFile) {
logProcessDetailsForLogRotate(getGlobalServiceContext());
}
diff --git a/src/mongo/util/text.cpp b/src/mongo/util/text.cpp
index be0e18eea3a..dccd4d3fb49 100644
--- a/src/mongo/util/text.cpp
+++ b/src/mongo/util/text.cpp
@@ -177,6 +177,29 @@ std::string toUtf8String(const std::wstring& wide) {
return "";
}
+std::wstring toWideStringFromStringData(StringData utf8String) {
+ int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String.rawData(), // Input string
+ utf8String.size(), // Count, -1 for NUL-terminated
+ nullptr, // No output buffer
+ 0 // Zero means "compute required size"
+ );
+ if (bufferSize == 0) {
+ return std::wstring();
+ }
+ std::unique_ptr<wchar_t[]> tempBuffer(new wchar_t[bufferSize]);
+ tempBuffer[0] = L'0';
+ MultiByteToWideChar(CP_UTF8, // Code page
+ 0, // Flags
+ utf8String.rawData(), // Input string
+ utf8String.size(), // Count, -1 for NUL-terminated
+ tempBuffer.get(), // UTF-16 output buffer
+ bufferSize // Buffer size in wide characters
+ );
+ return std::wstring(tempBuffer.get(), bufferSize);
+}
+
std::wstring toWideString(const char* utf8String) {
int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page
0, // Flags
diff --git a/src/mongo/util/text.h b/src/mongo/util/text.h
index 76309541d0c..40493fa9d4f 100644
--- a/src/mongo/util/text.h
+++ b/src/mongo/util/text.h
@@ -75,6 +75,7 @@ bool isValidUTF8(StringData s);
std::string toUtf8String(const std::wstring& wide);
+std::wstring toWideStringFromStringData(StringData s);
std::wstring toWideString(const char* s);
bool writeUtf8ToWindowsConsole(const char* utf8String, unsigned int utf8StringSize);