Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
/*
|
|
|
|
* RocksDBLogForwarder.actor.cpp
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2022-11-02 07:09:39 +08:00
|
|
|
#ifdef SSD_ROCKSDB_EXPERIMENTAL
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
#include "fdbserver/RocksDBLogForwarder.h"
|
|
|
|
|
|
|
|
#include "flow/network.h"
|
|
|
|
#include "flow/Trace.h"
|
2022-10-25 01:44:26 +08:00
|
|
|
#include "fdbrpc/simulator.h"
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
|
|
|
|
#include "flow/actorcompiler.h" // This must be the last include file
|
|
|
|
|
|
|
|
using InfoLogLevel = rocksdb::InfoLogLevel;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
Severity getSeverityFromLogLevel(const InfoLogLevel& log_level) {
|
|
|
|
switch (log_level) {
|
|
|
|
case InfoLogLevel::DEBUG_LEVEL:
|
|
|
|
return SevDebug;
|
|
|
|
case InfoLogLevel::INFO_LEVEL:
|
|
|
|
return SevInfo;
|
|
|
|
case InfoLogLevel::WARN_LEVEL:
|
|
|
|
return SevWarn;
|
|
|
|
case InfoLogLevel::ERROR_LEVEL:
|
|
|
|
return SevError;
|
|
|
|
case InfoLogLevel::FATAL_LEVEL:
|
|
|
|
return SevError;
|
|
|
|
case InfoLogLevel::HEADER_LEVEL:
|
|
|
|
return SevVerbose;
|
|
|
|
case InfoLogLevel::NUM_INFO_LOG_LEVELS:
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace details {
|
|
|
|
|
|
|
|
void logTraceEvent(const RocksDBLogRecord& record) {
|
|
|
|
TraceEvent event = TraceEvent(record.severity, "RocksDBLogRecord", record.uid);
|
|
|
|
event.detail("RocksDBLogTime", record.logReceiveTime);
|
|
|
|
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << record.threadID;
|
2022-11-01 05:01:38 +08:00
|
|
|
event.detail("RocksDBThreadID", ss.str());
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& [k, v] : record.kvPairs) {
|
|
|
|
event.detail(k.c_str(), v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 01:27:23 +08:00
|
|
|
ACTOR Future<Void> rocksDBPeriodicallyLogger(RocksDBLogger* pRecords) {
|
|
|
|
loop choose {
|
2022-12-09 01:26:45 +08:00
|
|
|
when(wait(delay(0.1))) {
|
|
|
|
pRecords->consume();
|
|
|
|
}
|
2022-10-25 01:27:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RocksDBLogger::RocksDBLogger()
|
|
|
|
: mainThreadId(std::this_thread::get_id()), periodicLogger(rocksDBPeriodicallyLogger(this)) {}
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
|
|
|
|
void RocksDBLogger::inject(RocksDBLogRecord&& record) {
|
|
|
|
const std::thread::id threadId = std::this_thread::get_id();
|
|
|
|
if (threadId == mainThreadId) {
|
|
|
|
// In the main thread, it is *NOT* necessary to cache the record.
|
|
|
|
logTraceEvent(record);
|
|
|
|
|
|
|
|
consume();
|
|
|
|
} else {
|
|
|
|
const std::lock_guard<std::mutex> lockGuard(recordsMutex);
|
|
|
|
|
2022-11-01 05:01:38 +08:00
|
|
|
logRecords.emplace_back();
|
|
|
|
logRecords.back() = std::move(record);
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RocksDBLogger::consume() {
|
|
|
|
std::vector<RocksDBLogRecord> currentRecords;
|
|
|
|
{
|
|
|
|
const std::lock_guard<std::mutex> lockGuard(recordsMutex);
|
2022-11-01 05:01:38 +08:00
|
|
|
currentRecords.swap(logRecords);
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& record : currentRecords) {
|
|
|
|
logTraceEvent(record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace details
|
|
|
|
|
|
|
|
RocksDBLogForwarder::RocksDBLogForwarder(const UID& id_, const InfoLogLevel log_level)
|
2022-11-01 05:01:38 +08:00
|
|
|
: rocksdb::Logger(log_level), id(id_), logger() {
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
TraceEvent(SevInfo, "RocksDBLoggerStart", id);
|
|
|
|
}
|
|
|
|
|
|
|
|
RocksDBLogForwarder::~RocksDBLogForwarder() {
|
|
|
|
TraceEvent(SevInfo, "RocksDBLoggerStop", id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RocksDBLogForwarder::Logv(const char* format, va_list ap) {
|
|
|
|
Logv(InfoLogLevel::INFO_LEVEL, format, ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RocksDBLogForwarder::Logv(const InfoLogLevel log_level, const char* format, va_list ap) {
|
|
|
|
const std::thread::id threadID = std::this_thread::get_id();
|
|
|
|
|
|
|
|
// FIXME: Restrict the RocksDB log level to warn in order to prevent almost all simulation test failure. This has to
|
|
|
|
// be reconsidered.
|
|
|
|
const Severity severity = std::min(getSeverityFromLogLevel(log_level), SevWarn);
|
2022-10-25 01:27:23 +08:00
|
|
|
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
// TODO: Parse the log information into KV pairs
|
2022-10-25 01:44:26 +08:00
|
|
|
// At this stage vsnprintf is used
|
|
|
|
char buf[1024];
|
|
|
|
vsnprintf(buf, 1024, format, ap);
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
if (severity < SevError) {
|
2022-11-01 05:01:38 +08:00
|
|
|
logger.inject(details::RocksDBLogRecord{ now(), severity, id, threadID, { { "Text", std::string(buf) } } });
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
} else {
|
2022-11-01 05:01:38 +08:00
|
|
|
logger.inject(details::RocksDBLogRecord{
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
now(),
|
|
|
|
severity,
|
|
|
|
id,
|
|
|
|
threadID,
|
2022-10-25 01:44:26 +08:00
|
|
|
{ { "Text", std::string(buf) }, { "OriginalBacktrace", platform::get_backtrace() } } });
|
Redirect RocksDB Log data to FDB TraceEvent
RocksDB supports injecting a custom logger. By introducing
RocksDBLogForwarder, it is possible to retrieve RocksDB log lines and
log them as TraceEvents.
Note that RocksDB is multi-threaded while FDB is designed to be
single threaded, in the FDB event loop there are certain variables
defined as thread_local. This causes that only FDB main thread could
generate TraceEvent, since information like Machine are only available
in the main thread. The current design is to cache all log lines from
the other threads, and let the main thread report the cached log, when:
* The main thread received log
* Every some time (this should be a Knob but at this stage a magic
number is used for convenience.)
It is possible to parse the log lines into Key/Value pairs for
TraceEvent output, but at this stage only the format string is printed
out. Also, RocksDB may log some errors that are interpreted as SevError,
which will cause simulation failures. To prevent this, the maximum error
level is set to SevWarn, which should be reconsidered carefully.
The code is tested by 1) random simulations to ensure the log lines are
included in the XML files 2) force the simulator uses RocksDB and run a
10k correctness run. Both tests passed.
2022-10-25 01:11:20 +08:00
|
|
|
}
|
|
|
|
}
|
2022-11-02 07:09:39 +08:00
|
|
|
|
|
|
|
#endif // SSD_ROCKSDB_EXPERIMENTAL
|