summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Caimano <ben.caimano@10gen.com>2018-03-13 17:34:50 -0400
committerBen Caimano <ben.caimano@10gen.com>2018-03-16 16:46:13 -0400
commit044c0d7d67e3b47e50282b7d9c4509313a6c8db0 (patch)
treef701064c8a4a938a46e7edf2ab5a65a222404237
parente85ca2d097655626e1178ba41cfe9863e1ba1c8d (diff)
downloadmongo-044c0d7d67e3b47e50282b7d9c4509313a6c8db0.tar.gz
SERVER-33758 Remove logUserIds
Removed unused `--logUserIds` flag, consolidated logger encoding
-rw-r--r--jstests/auth/log_user_basic.js260
-rw-r--r--src/mongo/SConscript1
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/initialize_server_global_state.cpp4
-rw-r--r--src/mongo/db/server_extra_log_context.cpp88
-rw-r--r--src/mongo/logger/max_log_size.cpp57
-rw-r--r--src/mongo/logger/max_log_size.h46
-rw-r--r--src/mongo/logger/message_event_utf8_encoder.cpp42
-rw-r--r--src/mongo/logger/message_event_utf8_encoder.h39
9 files changed, 75 insertions, 463 deletions
diff --git a/jstests/auth/log_user_basic.js b/jstests/auth/log_user_basic.js
deleted file mode 100644
index dbfe90c25da..00000000000
--- a/jstests/auth/log_user_basic.js
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * This file tests that "user:<username>@<db>" shows up in the logs.
- * @tags: [requires_sharding]
- */
-
-// TODO(schwerin) Re-enable this test after resolving corresponding TODO in mongo/util/log.cpp.
-if (0) {
- /**
- * Extracts information from a mongod/mongos log entry.
- *
- * @param line {string} a single line of log.
- *
- * @return {Object} format:
- *
- * {
- * id: <string>, // thread id of the log line.
- * // list of users logged in. Can be empty.
- * users: <Object> // map of db name to user name
- * }
- */
- var parseLog = function(line) {
- var THREAD_ID_PATTERN = / [012]?\d:\d\d:\d\d\.\d\d\d \[(.+)\] /;
- var ID_USER_PATTERN = new RegExp(THREAD_ID_PATTERN.source + 'user:([^ ]*) ');
- var res = THREAD_ID_PATTERN.exec(line);
-
- if (res == null) {
- return null;
- }
-
- var logInfo = {id: res[1], users: {}};
-
- var userLog = null;
- res = ID_USER_PATTERN.exec(line);
-
- if (res != null) {
- userLog = res[2];
- // should not have trailing commas
- assert.neq(',', userLog[userLog.length - 1], 'Bad user log list format: ' + line);
-
- userLog.split(',').forEach(function(userData) {
- var userAndDB = userData.split('@');
- assert.eq(2,
- userAndDB.length,
- 'Bad user db pair format: ' + userData + ' from line: ' + line);
- logInfo.users[userAndDB[1]] = userAndDB[0];
- });
- }
-
- return logInfo;
- };
-
- /**
- * Performs a series of test on user id logging.
- *
- * @param conn1 {Mongo} the connection object to use for logging in users.
- * @param conn2 {Mongo} another connection object different from conn1.
- */
- var doTest = function(conn1, conn2) {
- var connInfo1 = {
- id: null, // thread id of this connection
- mongo: conn1, // connection object
- users: {} // contains authenticated users represented as a map of db to user names.
- };
-
- var connInfo2 = {id: null, mongo: conn2, users: {}};
-
- var conn1Auth =
- [{user: 'foo', pwd: 'bar', db: 'test'}, {user: 'chun', pwd: 'li', db: 'sf'}];
-
- var conn2Auth =
- [{user: 'root', pwd: 'ugat', db: 'admin'}, {user: 'elbow', pwd: 'freeze', db: 'bboy'}];
-
- var loginUser = function(connInfo, connAuth) {
- var db = connInfo.mongo.getDB(connAuth.db);
- db.createUser({user: connAuth.user, pwd: connAuth.pwd, roles: jsTest.adminUserRoles});
- db.auth(connAuth.user, connAuth.pwd);
- connInfo.users[connAuth.db] = connAuth.user;
- };
-
- var logoutUser = function(connInfo, connAuth) {
- var db = connInfo.mongo.getDB(connAuth.db);
- db.runCommand({logout: 1});
- delete connInfo.users[connAuth.db];
- };
-
- /**
- * Performs a couple of test to make sure that the format of the log is correct.
- * Also checks that whether the right users show up in the logs.
- *
- * @param log {Array.<string>} list of log lines to check.
- * @param connInfo {Object}
- */
- var checkLogs = function(log, connInfo) {
- var foundOne = false;
-
- /**
- * @return true if the logInfo contains the same users as connIfo.
- */
- var checkUsers = function(logInfo) {
- for (var db in logInfo.users) {
- if (logInfo.users.hasOwnProperty(db) &&
- logInfo.users[db] != connInfo.users[db]) {
- return false;
- }
- }
-
- for (db in connInfo.users) {
- if (connInfo.users.hasOwnProperty(db) &&
- logInfo.users[db] != connInfo.users[db]) {
- return false;
- }
- }
-
- return true;
- };
-
- var hasUser = function(logInfo) {
- for (var db in logInfo.users) {
- if (logInfo.users.hasOwnProperty(db)) {
- return true;
- }
- }
-
- return false;
- };
-
- log.forEach(function(line) {
- var logInfo = parseLog(line);
-
- if (logInfo == null)
- return;
- if (connInfo.id == null) {
- if (checkUsers(logInfo)) {
- connInfo.id = logInfo.id;
- foundOne = true;
- }
-
- return;
- }
-
- if (logInfo.id == connInfo.id) {
- foundOne = true;
- assert(checkUsers(logInfo),
- 'logged users does not match [' + tojson(connInfo.users) + '], log: ' +
- line);
- } else if (hasUser(logInfo)) {
- assert(!checkUsers(logInfo), 'Unexpected user log on another thread: ' + line);
- }
- });
-
- assert(foundOne, 'User log not found in: ' + tojson(log));
- };
-
- var testDB1 = connInfo1.mongo.getDB('test');
- var testDB2 = connInfo2.mongo.getDB('test');
-
- // Note: The succeeding tests should not be re-ordered.
- (function() {
- jsTest.log('Test single user on 1 connection.');
- loginUser(connInfo1, conn1Auth[0]);
- testDB1.runCommand({dbStats: 1});
- var log = testDB1.adminCommand({getLog: 'global'});
- checkLogs(log.log, connInfo1);
- })();
-
- (function() {
- jsTest.log('Test multiple conn with 1 user each');
- loginUser(connInfo2, conn2Auth[0]);
- testDB2.runCommand({dbStats: 1});
- var log = testDB1.adminCommand({getLog: 'global'});
- checkLogs(log.log, connInfo2);
- })();
-
- (function() {
- jsTest.log('Test multiple conn with 1 multiple user');
- loginUser(connInfo1, conn1Auth[1]);
- var log = testDB1.adminCommand({getLog: 'global'});
- var lastLogLine = log.log.pop(); // Used for trimming out logs before this point.
- testDB1.runCommand({dbStats: 1});
- log = testDB1.adminCommand({getLog: 'global'});
-
- // Remove old log entries.
- while (log.log.shift() != lastLogLine) {
- }
- assert(log.log.length > 0);
- checkLogs(log.log, connInfo1);
- })();
-
- (function() {
- jsTest.log('Test multiple conn with multiple users each');
- loginUser(connInfo2, conn2Auth[1]);
- var log = testDB2.adminCommand({getLog: 'global'});
- var lastLogLine = log.log.pop(); // Used for trimming out logs before this point.
- testDB1.runCommand({dbStats: 1});
- log = testDB2.adminCommand({getLog: 'global'});
-
- // Remove old log entries.
- while (log.log.shift() != lastLogLine) {
- }
- assert(log.log.length > 0);
- checkLogs(log.log, connInfo2);
- })();
-
- (function() {
- // Case for logout older user first.
- jsTest.log('Test log line will not show foo');
- logoutUser(connInfo1, conn1Auth[0]);
- var log = testDB1.adminCommand({getLog: 'global'});
- var lastLogLine = log.log.pop(); // Used for trimming out logs before this point.
- testDB1.runCommand({dbStats: 1});
- log = testDB1.adminCommand({getLog: 'global'});
-
- // Remove old log entries.
- while (log.log.shift() != lastLogLine) {
- }
- assert(log.log.length > 0);
- checkLogs(log.log, connInfo1);
- })();
-
- (function() {
- jsTest.log('Test that log for conn1 will not show \'user:\'');
- logoutUser(connInfo1, conn1Auth[1]);
- var log = testDB1.adminCommand({getLog: 'global'});
- var lastLogLine = log.log.pop(); // Used for trimming out logs before this point.
- testDB1.runCommand({dbStats: 1});
- log = testDB1.adminCommand({getLog: 'global'});
-
- // Remove old log entries.
- while (log.log.shift() != lastLogLine) {
- }
- assert(log.log.length > 0);
- checkLogs(log.log, connInfo1);
- })();
-
- (function() {
- // Case for logout newer user first.
- jsTest.log('Test log line will not show elbow');
- logoutUser(connInfo2, conn2Auth[1]);
- var log = testDB2.adminCommand({getLog: 'global'});
- var lastLogLine = log.log.pop(); // Used for trimming out logs before this point.
- testDB1.runCommand({dbStats: 1});
- log = testDB2.adminCommand({getLog: 'global'});
-
- // Remove old log entries.
- while (log.log.shift() != lastLogLine) {
- }
- assert(log.log.length > 0);
- checkLogs(log.log, connInfo2);
- })();
- };
-
- var conn = MongoRunner.runMongod({verbose: 5, setParameter: 'logUserIds=1'});
- doTest(conn, new Mongo(conn.host));
- MongoRunner.stopMongod(conn);
-
- var st = new ShardingTest(
- {shards: 1, verbose: 5, other: {mongosOptions: {setParameter: 'logUserIds=1'}}});
- doTest(st.s, new Mongo(st.s.host));
- st.stop();
-}
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 6abf24572fe..3d4fb782bd9 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -92,7 +92,6 @@ env.Library(
'logger/log_severity.cpp',
'logger/logger.cpp',
'logger/logstream_builder.cpp',
- 'logger/max_log_size.cpp',
'logger/message_event_utf8_encoder.cpp',
'logger/message_log_domain.cpp',
'logger/ramlog.cpp',
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index edc113ead36..91344e17244 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -401,7 +401,6 @@ env.Library(
target="mongodandmongos",
source=[
"initialize_server_global_state.cpp",
- "server_extra_log_context.cpp",
"server_options_init.cpp",
],
LIBDEPS=[
diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp
index 7d757f930dd..87d378727f3 100644
--- a/src/mongo/db/initialize_server_global_state.cpp
+++ b/src/mongo/db/initialize_server_global_state.cpp
@@ -212,6 +212,7 @@ void forkServerOrDie() {
quickExit(EXIT_FAILURE);
}
+MONGO_EXPORT_SERVER_PARAMETER(maxLogSizeKB, int, logger::LogContext::kDefaultMaxLogSizeKB);
MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
("GlobalLogManager", "EndStartupOptionHandling", "ForkServer"),
("default"))
@@ -224,6 +225,9 @@ MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
using logger::RotatableFileAppender;
using logger::StatusWithRotatableFileWriter;
+ // Hook up this global into our logging encoder
+ MessageEventDetailsEncoder::setMaxLogSizeKBSource(maxLogSizeKB);
+
if (serverGlobalParams.logWithSyslog) {
#ifdef _WIN32
return Status(ErrorCodes::InternalError,
diff --git a/src/mongo/db/server_extra_log_context.cpp b/src/mongo/db/server_extra_log_context.cpp
deleted file mode 100644
index f557ae34051..00000000000
--- a/src/mongo/db/server_extra_log_context.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
-* Copyright (C) 2012 10gen Inc.
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License, version 3,
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*
-* As a special exception, the copyright holders give permission to link the
-* code of portions of this program with the OpenSSL library under certain
-* conditions as described in each individual source file and distribute
-* linked combinations including the program with the OpenSSL library. You
-* must comply with the GNU Affero General Public License in all respects for
-* all of the code used other than as permitted herein. If you modify file(s)
-* with this exception, you may extend this exception to your version of the
-* file(s), but you are not obligated to do so. If you do not wish to do so,
-* delete this exception statement from your version. If you delete this
-* exception statement from all source files in the program, then also delete
-* it in the license file.
-*/
-
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/base/init.h"
-#include "mongo/bson/util/builder.h"
-#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/auth/user_set.h"
-#include "mongo/db/client.h"
-#include "mongo/db/server_parameters.h"
-#include "mongo/logger/max_log_size.h"
-#include "mongo/util/log.h"
-
-namespace mongo {
-namespace {
-
-// Server parameter controlling whether or not user ids are included in log entries.
-MONGO_EXPORT_STARTUP_SERVER_PARAMETER(logUserIds, bool, false);
-MONGO_EXPORT_SERVER_PARAMETER(maxLogSizeKB, int, 10);
-
-/**
- * Note: When appending new strings to the builder, make sure to pass false to the
- * includeEndingNull parameter.
- */
-void appendServerExtraLogContext(BufBuilder& builder) {
- Client* client = Client::getCurrent();
- if (!client)
- return;
- if (!AuthorizationSession::exists(client))
- return;
-
- UserNameIterator users = AuthorizationSession::get(client)->getAuthenticatedUserNames();
-
- if (!users.more())
- return;
-
- builder.appendStr("user:", false);
- builder.appendStr(users.next().toString(), false);
- while (users.more()) {
- builder.appendChar(',');
- builder.appendStr(users.next().toString(), false);
- }
- builder.appendChar(' ');
-}
-
-int getMaxLogSizeKB() {
- return maxLogSizeKB.load();
-}
-
-MONGO_INITIALIZER(SetServerLogContextFunction)(InitializerContext*) {
- logger::MaxLogSizeKB::setGetter(getMaxLogSizeKB);
-
- if (!logUserIds)
- return Status::OK();
-
- return logger::registerExtraLogContextFn(appendServerExtraLogContext);
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/logger/max_log_size.cpp b/src/mongo/logger/max_log_size.cpp
deleted file mode 100644
index 1a767924020..00000000000
--- a/src/mongo/logger/max_log_size.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright (C) 2016 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/logger/max_log_size.h"
-
-#include "mongo/stdx/functional.h"
-
-namespace mongo {
-namespace logger {
-
-namespace {
-
-stdx::function<int()>& getGetterFunction() {
- static stdx::function<int()> instance;
- return instance;
-}
-
-} // namespace
-
-int MaxLogSizeKB::get() {
- auto& getter = getGetterFunction();
- return !getter ? 10 : getter();
-}
-
-void MaxLogSizeKB::setGetter(stdx::function<int()> getter) {
- getGetterFunction() = std::move(getter);
-}
-
-} // namespace logger
-} // namespace mongo
diff --git a/src/mongo/logger/max_log_size.h b/src/mongo/logger/max_log_size.h
deleted file mode 100644
index c254fe2fd10..00000000000
--- a/src/mongo/logger/max_log_size.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright (C) 2016 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include "mongo/stdx/functional.h"
-
-namespace mongo {
-namespace logger {
-
-class MaxLogSizeKB {
-public:
- static int get();
- static void setGetter(stdx::function<int()> getter);
-
-private:
- static stdx::function<int()> _getter;
-};
-
-} // namespace logger
-} // namespace mongo
diff --git a/src/mongo/logger/message_event_utf8_encoder.cpp b/src/mongo/logger/message_event_utf8_encoder.cpp
index 8a412e855c8..e616d3402a3 100644
--- a/src/mongo/logger/message_event_utf8_encoder.cpp
+++ b/src/mongo/logger/message_event_utf8_encoder.cpp
@@ -31,21 +31,45 @@
#include <iostream>
-#include "mongo/logger/max_log_size.h"
#include "mongo/util/time_support.h"
namespace mongo {
namespace logger {
-static MessageEventDetailsEncoder::DateFormatter _dateFormatter = outputDateAsISOStringLocal;
+const int LogContext::kDefaultMaxLogSizeKB;
+
+LogContext::LogContext()
+ : _dateFormatter{outputDateAsISOStringLocal}, _maxLogSizeSource{nullptr} {};
+
+LogContext& MessageEventDetailsEncoder::getGlobalLogContext() {
+ static LogContext context;
+ return context;
+}
+
+void MessageEventDetailsEncoder::setMaxLogSizeKBSource(const AtomicWord<int>& source) {
+ invariant(getGlobalLogContext()._maxLogSizeSource == nullptr);
+ getGlobalLogContext()._maxLogSizeSource = &source;
+}
+
+int MessageEventDetailsEncoder::getMaxLogSizeKB() {
+ auto* source = getGlobalLogContext()._maxLogSizeSource;
+
+ // If not initialized, use the default
+ if (source == nullptr)
+ return LogContext::kDefaultMaxLogSizeKB;
+
+ // If initialized, use the reference
+ // TODO: This seems like a CST seq'd load we don't need. `loadRelaxed()`?
+ return source->load();
+}
void MessageEventDetailsEncoder::setDateFormatter(DateFormatter dateFormatter) {
- _dateFormatter = dateFormatter;
+ getGlobalLogContext()._dateFormatter = dateFormatter;
}
-MessageEventDetailsEncoder::DateFormatter MessageEventDetailsEncoder::getDateFormatter() {
- return _dateFormatter;
+DateFormatter MessageEventDetailsEncoder::getDateFormatter() {
+ return getGlobalLogContext()._dateFormatter;
}
namespace {
@@ -59,9 +83,11 @@ constexpr auto kEOL = "\n"_sd;
MessageEventDetailsEncoder::~MessageEventDetailsEncoder() {}
std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& event,
std::ostream& os) {
- const size_t maxLogSize = MaxLogSizeKB::get() * 1024;
+ const auto maxLogSizeKB = getMaxLogSizeKB();
+
+ const size_t maxLogSize = maxLogSizeKB * 1024;
- _dateFormatter(os, event.getDate());
+ getDateFormatter()(os, event.getDate());
os << ' ';
os << event.getSeverity().toChar();
@@ -99,7 +125,7 @@ std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& ev
if (event.isTruncatable() && msg.size() > maxLogSize) {
os << "warning: log line attempted (" << msg.size() / 1024 << "kB) over max size ("
- << MaxLogSizeKB::get() << "kB), printing beginning and end ... ";
+ << maxLogSizeKB << "kB), printing beginning and end ... ";
os << msg.substr(0, maxLogSize / 3);
os << " .......... ";
os << msg.substr(msg.size() - (maxLogSize / 3));
diff --git a/src/mongo/logger/message_event_utf8_encoder.h b/src/mongo/logger/message_event_utf8_encoder.h
index 914bc302f35..4b85d99d783 100644
--- a/src/mongo/logger/message_event_utf8_encoder.h
+++ b/src/mongo/logger/message_event_utf8_encoder.h
@@ -36,13 +36,26 @@
namespace mongo {
namespace logger {
+typedef void (*DateFormatter)(std::ostream&, Date_t);
+
+/**
+ * This is the logging context for the MessageEventDetailsEncoder below. It actively controls how
+ * the output is encoded. As of now, there can be only one.
+ */
+struct LogContext {
+ static constexpr int kDefaultMaxLogSizeKB = 10;
+
+ LogContext();
+
+ DateFormatter _dateFormatter;
+ const AtomicWord<int>* _maxLogSizeSource;
+};
+
/**
* Encoder that writes log messages of the style that MongoDB writes to console and files.
*/
class MessageEventDetailsEncoder : public Encoder<MessageEventEphemeral> {
public:
- typedef void (*DateFormatter)(std::ostream&, Date_t);
-
/**
* Sets the date formatter function for all instances of MessageEventDetailsEncoder.
*
@@ -58,8 +71,30 @@ public:
*/
static DateFormatter getDateFormatter();
+ /**
+ * Sets a static wrapper to track an atomic variable reference
+ *
+ * Only safe to call once during single-threaded execution, as in during start-up
+ * initialization.
+ */
+ static void setMaxLogSizeKBSource(const AtomicWord<int>& source);
+
+ /**
+ * Loads a max log size from the reference set above. If no reference has been set, it returns
+ * the default. Note that this has to be an atomic operation, cache values when possible.
+ *
+ * Always safe to call.
+ */
+ static int getMaxLogSizeKB();
+
virtual ~MessageEventDetailsEncoder();
virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os);
+
+private:
+ /**
+ * Grab the singleton LogContext
+ */
+ static LogContext& getGlobalLogContext();
};
/**