150 lines
4.1 KiB
C++
150 lines
4.1 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef SSD_ROCKSDB_EXPERIMENTAL
|
|
#include "fdbserver/RocksDBLogForwarder.h"
|
|
|
|
#include "flow/network.h"
|
|
#include "flow/Trace.h"
|
|
#include "fdbrpc/simulator.h"
|
|
|
|
#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;
|
|
event.detail("RocksDBThreadID", ss.str());
|
|
}
|
|
|
|
for (const auto& [k, v] : record.kvPairs) {
|
|
event.detail(k.c_str(), v);
|
|
}
|
|
}
|
|
|
|
ACTOR Future<Void> rocksDBPeriodicallyLogger(RocksDBLogger* pRecords) {
|
|
loop choose {
|
|
when(wait(delay(0.1))) {
|
|
pRecords->consume();
|
|
}
|
|
}
|
|
}
|
|
|
|
RocksDBLogger::RocksDBLogger()
|
|
: mainThreadId(std::this_thread::get_id()), periodicLogger(rocksDBPeriodicallyLogger(this)) {}
|
|
|
|
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);
|
|
|
|
logRecords.emplace_back();
|
|
logRecords.back() = std::move(record);
|
|
}
|
|
}
|
|
|
|
void RocksDBLogger::consume() {
|
|
std::vector<RocksDBLogRecord> currentRecords;
|
|
{
|
|
const std::lock_guard<std::mutex> lockGuard(recordsMutex);
|
|
currentRecords.swap(logRecords);
|
|
}
|
|
|
|
for (const auto& record : currentRecords) {
|
|
logTraceEvent(record);
|
|
}
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
RocksDBLogForwarder::RocksDBLogForwarder(const UID& id_, const InfoLogLevel log_level)
|
|
: rocksdb::Logger(log_level), id(id_), logger() {
|
|
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);
|
|
|
|
// TODO: Parse the log information into KV pairs
|
|
// At this stage vsnprintf is used
|
|
char buf[1024];
|
|
vsnprintf(buf, 1024, format, ap);
|
|
if (severity < SevError) {
|
|
logger.inject(details::RocksDBLogRecord{ now(), severity, id, threadID, { { "Text", std::string(buf) } } });
|
|
} else {
|
|
logger.inject(details::RocksDBLogRecord{
|
|
now(),
|
|
severity,
|
|
id,
|
|
threadID,
|
|
{ { "Text", std::string(buf) }, { "OriginalBacktrace", platform::get_backtrace() } } });
|
|
}
|
|
}
|
|
|
|
#endif // SSD_ROCKSDB_EXPERIMENTAL
|