From a7b3af69ea629995ff89695622b3121457f969b6 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Wed, 25 Mar 2020 17:04:16 -0400 Subject: SERVER-46801 stacktrace logging cleanup/consolidation --- src/mongo/SConscript | 2 +- src/mongo/util/stacktrace.cpp | 116 ++++++++++++++++++++++++++++++++++ src/mongo/util/stacktrace.h | 56 ++++++++++++++++ src/mongo/util/stacktrace_json.cpp | 92 --------------------------- src/mongo/util/stacktrace_json.h | 90 -------------------------- src/mongo/util/stacktrace_posix.cpp | 30 +-------- src/mongo/util/stacktrace_test.cpp | 1 - src/mongo/util/stacktrace_threads.cpp | 1 - src/mongo/util/stacktrace_windows.cpp | 33 ++-------- 9 files changed, 180 insertions(+), 241 deletions(-) create mode 100644 src/mongo/util/stacktrace.cpp delete mode 100644 src/mongo/util/stacktrace_json.cpp delete mode 100644 src/mongo/util/stacktrace_json.h diff --git a/src/mongo/SConscript b/src/mongo/SConscript index c1f03448b1a..3242cd1fbb5 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -157,8 +157,8 @@ baseEnv.Library( 'util/platform_init.cpp', 'util/shell_exec.cpp', 'util/signal_handlers_synchronous.cpp', + 'util/stacktrace.cpp', 'util/stacktrace_${TARGET_OS_FAMILY}.cpp', - 'util/stacktrace_json.cpp', 'util/stacktrace_somap.cpp', 'util/stacktrace_threads.cpp', 'util/str.cpp', diff --git a/src/mongo/util/stacktrace.cpp b/src/mongo/util/stacktrace.cpp new file mode 100644 index 00000000000..2725d40d200 --- /dev/null +++ b/src/mongo/util/stacktrace.cpp @@ -0,0 +1,116 @@ +/** + * 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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl + +#include "mongo/util/stacktrace.h" + +#include + +#include "mongo/bson/bsonobj.h" +#include "mongo/bson/json.h" +#include "mongo/logv2/log.h" +#include "mongo/util/assert_util.h" + +namespace mongo::stack_trace_detail { +namespace { + +template +StringData kDigits; +template <> +constexpr StringData kDigits<16> = "0123456789ABCDEF"_sd; +template <> +constexpr StringData kDigits<10> = "0123456789"_sd; + +template +StringData toNumericBase(uint64_t x, Buf& buf, bool showBase) { + auto it = buf.rbegin(); + if (!x) { + *it++ = '0'; + } else { + for (; x; ++it) { + *it = kDigits[x % base]; + x /= base; + } + // base is prepended only when x is nonzero (matching printf) + if (base == 16 && showBase) { + static const auto kPrefix = "0x"_sd; + it = std::reverse_copy(kPrefix.begin(), kPrefix.end(), it); + } + } + size_t n = std::distance(it.base(), buf.end()); + const char* p = buf.data() + buf.size() - n; + return StringData(p, n); +} + +} // namespace + +StringData Dec::toDec(uint64_t x, Buf& buf) { + return toNumericBase<10>(x, buf, false); +} + +StringData Hex::toHex(uint64_t x, Buf& buf, bool showBase) { + return toNumericBase<16>(x, buf, showBase); +} + +uint64_t Hex::fromHex(StringData s) { + uint64_t x = 0; + for (char c : s) { + char uc = std::toupper(static_cast(c)); + if (size_t pos = kDigits<16>.find(uc); pos == std::string::npos) { + return x; + } else { + x <<= 4; + x += pos; + } + } + return x; +} + +void logBacktraceObject(const BSONObj& bt, StackTraceSink* sink, bool withHumanReadable) { + if (sink) { + *sink << fmt::format(FMT_STRING("BACKTRACE: {}"), tojson(bt, ExtendedRelaxedV2_0_0)); + } else { + LOGV2_OPTIONS(31380, {logv2::LogTruncation::Disabled}, "BACKTRACE", "bt"_attr = bt); + } + if (withHumanReadable) { + if (auto elem = bt.getField("backtrace"); !elem.eoo()) { + for (const auto& fe : elem.Obj()) { + BSONObj frame = fe.Obj(); + if (sink) { + *sink << fmt::format("\n Frame: {}", tojson(frame, ExtendedRelaxedV2_0_0)); + } else { + LOGV2(31445, "Frame", "frame"_attr = frame); + } + } + } + } +} + +} // namespace mongo::stack_trace_detail diff --git a/src/mongo/util/stacktrace.h b/src/mongo/util/stacktrace.h index 535199862c3..e36a0aea03b 100644 --- a/src/mongo/util/stacktrace.h +++ b/src/mongo/util/stacktrace.h @@ -32,10 +32,12 @@ */ #pragma once +#include #include #include #include "mongo/base/string_data.h" +#include "mongo/bson/bsonobj.h" #include "mongo/config.h" /** @@ -89,6 +91,60 @@ private: std::string& _s; }; +namespace stack_trace_detail { +/** + * A utility for uint64_t <=> uppercase hex string conversions. It + * can be used to produce a StringData. + * + * sink << Hex(x); // as a temporary + * + * Hex hx(x); + * StringData sd = hx; // sd storage is in `hx`. + */ +class Hex { +public: + using Buf = std::array; // 64/4 hex digits plus potential "0x" + + static StringData toHex(uint64_t x, Buf& buf, bool showBase = false); + + static uint64_t fromHex(StringData s); + + explicit Hex(uint64_t x, bool showBase = false) : _str{toHex(x, _buf, showBase)} {} + explicit Hex(const void* x, bool showBase = false) + : Hex{reinterpret_cast(x), showBase} {} + + operator StringData() const { + return _str; + } + +private: + Buf _buf; + StringData _str; +}; + +class Dec { +public: + using Buf = std::array; // ceil(64*log10(2)) + + static StringData toDec(uint64_t x, Buf& buf); + + static uint64_t fromDec(StringData s); + + explicit Dec(uint64_t x) : _str(toDec(x, _buf)) {} + + operator StringData() const { + return _str; + } + +private: + Buf _buf; + StringData _str; +}; + +void logBacktraceObject(const BSONObj& bt, StackTraceSink* sink, bool withHumanReadable); + +} // namespace stack_trace_detail + #ifndef _WIN32 /** * Metadata about an instruction address. diff --git a/src/mongo/util/stacktrace_json.cpp b/src/mongo/util/stacktrace_json.cpp deleted file mode 100644 index 12f2b06268e..00000000000 --- a/src/mongo/util/stacktrace_json.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * 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. - */ - -#include "mongo/util/stacktrace_json.h" - -#include - -#include "mongo/bson/bsonobj.h" -#include "mongo/util/assert_util.h" - -namespace mongo::stack_trace_detail { -namespace { - -template -StringData kDigits; -template <> -constexpr StringData kDigits<16> = "0123456789ABCDEF"_sd; -template <> -constexpr StringData kDigits<10> = "0123456789"_sd; - -template -StringData toNumericBase(uint64_t x, Buf& buf, bool showBase) { - auto it = buf.rbegin(); - if (!x) { - *it++ = '0'; - } else { - for (; x; ++it) { - *it = kDigits[x % base]; - x /= base; - } - // base is prepended only when x is nonzero (matching printf) - if (base == 16 && showBase) { - static const auto kPrefix = "0x"_sd; - it = std::reverse_copy(kPrefix.begin(), kPrefix.end(), it); - } - } - size_t n = std::distance(it.base(), buf.end()); - const char* p = buf.data() + buf.size() - n; - return StringData(p, n); -} - -} // namespace - -StringData Dec::toDec(uint64_t x, Buf& buf) { - return toNumericBase<10>(x, buf, false); -} - -StringData Hex::toHex(uint64_t x, Buf& buf, bool showBase) { - return toNumericBase<16>(x, buf, showBase); -} - -uint64_t Hex::fromHex(StringData s) { - uint64_t x = 0; - for (char c : s) { - char uc = std::toupper(static_cast(c)); - if (size_t pos = kDigits<16>.find(uc); pos == std::string::npos) { - return x; - } else { - x <<= 4; - x += pos; - } - } - return x; -} - -} // namespace mongo::stack_trace_detail diff --git a/src/mongo/util/stacktrace_json.h b/src/mongo/util/stacktrace_json.h deleted file mode 100644 index 554b1a66537..00000000000 --- a/src/mongo/util/stacktrace_json.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * 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 -#include - -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/util/stacktrace.h" - -namespace mongo::stack_trace_detail { - -/** - * A utility for uint64_t <=> uppercase hex string conversions. It - * can be used to produce a StringData. - * - * sink << Hex(x); // as a temporary - * - * Hex hx(x); - * StringData sd = hx; // sd storage is in `hx`. - */ -class Hex { -public: - using Buf = std::array; // 64/4 hex digits plus potential "0x" - - static StringData toHex(uint64_t x, Buf& buf, bool showBase = false); - - static uint64_t fromHex(StringData s); - - explicit Hex(uint64_t x, bool showBase = false) : _str{toHex(x, _buf, showBase)} {} - explicit Hex(const void* x, bool showBase = false) - : Hex{reinterpret_cast(x), showBase} {} - - operator StringData() const { - return _str; - } - -private: - Buf _buf; - StringData _str; -}; - -class Dec { -public: - using Buf = std::array; // ceil(64*log10(2)) - - static StringData toDec(uint64_t x, Buf& buf); - - static uint64_t fromDec(StringData s); - - explicit Dec(uint64_t x) : _str(toDec(x, _buf)) {} - - operator StringData() const { - return _str; - } - -private: - Buf _buf; - StringData _str; -}; - -} // namespace mongo::stack_trace_detail diff --git a/src/mongo/util/stacktrace_posix.cpp b/src/mongo/util/stacktrace_posix.cpp index 531e21bdc24..9d27ca1af25 100644 --- a/src/mongo/util/stacktrace_posix.cpp +++ b/src/mongo/util/stacktrace_posix.cpp @@ -48,7 +48,6 @@ #include "mongo/logv2/log.h" #include "mongo/platform/compiler_gcc.h" #include "mongo/util/scopeguard.h" -#include "mongo/util/stacktrace_json.h" #include "mongo/util/stacktrace_somap.h" #include "mongo/util/version.h" @@ -426,38 +425,15 @@ void printStackTraceImpl(const Options& options, StackTraceSink* sink = nullptr) appendStackTraceObject(&bob, iteration, options); #endif - BSONObj obj = bob.done(); if (!err.empty()) { - static constexpr char fmtErr[] = "Error collecting stack trace: {err}"; if (sink) { - *sink << fmt::format(fmtErr, "err"_a = err); + *sink << fmt::format(FMT_STRING("Error collecting stack trace: {}"), err); } else { - LOGV2(31430, fmtErr, "err"_attr = err); + LOGV2(31430, "Error collecting stack trace", "error"_attr = err); } return; } - static constexpr char fmtBt[] = "BACKTRACE: {bt}"; - if (sink) { - *sink << fmt::format(fmtBt, "bt"_a = tojson(obj, ExtendedRelaxedV2_0_0)); - } else { - LOGV2_OPTIONS(31431, {logv2::LogTruncation::Disabled}, fmtBt, "bt"_attr = obj); - } - - if (options.withHumanReadable) { - if (auto elem = obj.getField("backtrace"); !elem.eoo()) { - for (const auto& fe : elem.embeddedObject()) { - BSONObj frame = fe.embeddedObject(); - static constexpr char fmtFrame[] = " Frame: {frame}"; - if (sink) { - *sink << "\n" - << fmt::format(fmtFrame, - "frame"_a = tojson(frame, ExtendedRelaxedV2_0_0)); - } else { - LOGV2(31427, fmtFrame, "frame"_attr = frame); - } - } - } - } + stack_trace_detail::logBacktraceObject(bob.done(), sink, options.withHumanReadable); } diff --git a/src/mongo/util/stacktrace_test.cpp b/src/mongo/util/stacktrace_test.cpp index 4de985fde00..e5978736041 100644 --- a/src/mongo/util/stacktrace_test.cpp +++ b/src/mongo/util/stacktrace_test.cpp @@ -55,7 +55,6 @@ #include "mongo/stdx/thread.h" #include "mongo/unittest/unittest.h" #include "mongo/util/stacktrace.h" -#include "mongo/util/stacktrace_json.h" /** `sigaltstack` was introduced in glibc-2.12 in 2010. */ #if !defined(_WIN32) diff --git a/src/mongo/util/stacktrace_threads.cpp b/src/mongo/util/stacktrace_threads.cpp index d2d8e38539e..62fe41898a2 100644 --- a/src/mongo/util/stacktrace_threads.cpp +++ b/src/mongo/util/stacktrace_threads.cpp @@ -60,7 +60,6 @@ #include "mongo/stdx/thread.h" #include "mongo/stdx/unordered_map.h" #include "mongo/util/signal_handlers_synchronous.h" -#include "mongo/util/stacktrace_json.h" #include "mongo/util/stacktrace_somap.h" namespace mongo { diff --git a/src/mongo/util/stacktrace_windows.cpp b/src/mongo/util/stacktrace_windows.cpp index 14f00b58f25..c95911d112c 100644 --- a/src/mongo/util/stacktrace_windows.cpp +++ b/src/mongo/util/stacktrace_windows.cpp @@ -59,7 +59,6 @@ #include "mongo/stdx/mutex.h" #include "mongo/util/assert_util.h" #include "mongo/util/concurrency/mutex.h" -#include "mongo/util/stacktrace_json.h" #include "mongo/util/text.h" namespace mongo { @@ -96,9 +95,8 @@ public: const auto symbolPath = symbolPathBuilder.str(); if (!SymInitializeW(handle, symbolPath.c_str(), TRUE)) { - LOGV2_ERROR(31443, - "Stack trace initialization failed, SymInitialize failed with error {err}", - "err"_attr = errnoWithDescription()); + LOGV2_ERROR( + 31443, "Stack trace initialization failed", "error"_attr = errnoWithDescription()); return; } @@ -244,7 +242,7 @@ std::vector makeTraceList(CONTEXT& context) { stdx::lock_guard lk(symbolHandler); if (!symbolHandler) { - LOGV2_ERROR(31444, "Stack trace failed, symbol handler returned an invalid handle."); + LOGV2_ERROR(31444, "Stack trace failed, symbol handler returned an invalid handle"); return traceList; } @@ -307,30 +305,7 @@ void printTraceList(const std::vector& traceList, return; BSONObjBuilder bob; appendTrace(&bob, traceList, options); - const BSONObj bt = bob.done(); - - static constexpr char fmtBt[] = "BACKTRACE: {bt}"; - if (sink) { - *sink << fmt::format(fmtBt, "bt"_a = tojson(bt, ExtendedRelaxedV2_0_0)); - } else { - LOGV2_OPTIONS(31380, {logv2::LogTruncation::Disabled}, fmtBt, "bt"_attr = bt); - } - - if (options.withHumanReadable) { - if (auto elem = bt.getField("backtrace"); !elem.eoo()) { - for (const auto& fe : elem.Obj()) { - BSONObj frame = fe.Obj(); - static constexpr char fmtFrame[] = " Frame: {frame}"; - if (sink) { - *sink << "\n" - << fmt::format(fmtFrame, - "frame"_a = tojson(frame, ExtendedRelaxedV2_0_0)); - } else { - LOGV2(31445, fmtFrame, "frame"_attr = frame); - } - } - } - } + stack_trace_detail::logBacktraceObject(bob.done(), sink, options.withHumanReadable); } /** `sink` can be nullptr to emit structured logs instead of writing to a sink. */ -- cgit v1.2.1