Skip to content

Commit

Permalink
Feat: Log dumper (#445)
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Pryakhin <[email protected]>
  • Loading branch information
waldgange authored Dec 6, 2024
1 parent 09ba4f2 commit 90b398b
Show file tree
Hide file tree
Showing 7 changed files with 773 additions and 263 deletions.
196 changes: 23 additions & 173 deletions src/groups/bmq/bmqtsk/bmqtsk_logcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ LogControllerConfig::LogControllerConfig(bslma::Allocator* allocator)
, d_syslogAppName("")
, d_syslogVerbosity(ball::Severity::ERROR)
, d_categories(allocator)
, d_recordBufferSizeBytes(32 * 1024) // 32 KB
, d_recordingVerbosity(ball::Severity::OFF)
, d_triggerVerbosity(ball::Severity::OFF)
{
// NOTHING
}
Expand All @@ -167,6 +170,9 @@ LogControllerConfig::LogControllerConfig(const LogControllerConfig& other,
, d_syslogAppName(other.d_syslogAppName, allocator)
, d_syslogVerbosity(other.d_syslogVerbosity)
, d_categories(other.d_categories, allocator)
, d_recordBufferSizeBytes(other.d_recordBufferSizeBytes)
, d_recordingVerbosity(other.d_recordingVerbosity)
, d_triggerVerbosity(other.d_triggerVerbosity)
{
// NOTHING
}
Expand All @@ -189,6 +195,9 @@ LogControllerConfig::operator=(const LogControllerConfig& rhs)
d_syslogAppName = rhs.d_syslogAppName;
d_syslogVerbosity = rhs.d_syslogVerbosity;
d_categories = rhs.d_categories;
d_recordBufferSizeBytes = rhs.d_recordBufferSizeBytes;
d_recordingVerbosity = rhs.d_recordingVerbosity;
d_triggerVerbosity = rhs.d_triggerVerbosity;
}

return *this;
Expand Down Expand Up @@ -229,169 +238,6 @@ void LogControllerConfig::clearCategoriesProperties()
d_categories.clear();
}

int LogControllerConfig::fromDatum(bsl::ostream& errorDescription,
const bdld::Datum& datum)
{
enum RcEnum {
// Value for the various RC error categories
rc_SUCCESS = 0,
rc_INVALID_DATUM = -1,
rc_INVALID_KEY_TYPE = -2,
rc_INVALID_KEY_VALUE = -3,
rc_UNSET_VALUE = -4,
rc_UNKNOWN_KEY = -5
};

if (!datum.isMap()) {
errorDescription << "The specified datum must be a map";
return rc_INVALID_DATUM; // RETURN
}

#define PARSE_ENTRY(ENTRY, FIELD, TYPE, KEY_STR, KEY_PATH) \
if (bdlb::String::areEqualCaseless(ENTRY.key(), KEY_STR)) { \
if (!ENTRY.value().is##TYPE()) { \
errorDescription << "Key '" << #KEY_PATH << "' type must be a " \
<< #TYPE; \
return rc_INVALID_KEY_TYPE; \
} \
FIELD = ENTRY.value().the##TYPE(); \
continue; \
}

#define PARSE_CONF(FIELD, TYPE, KEY_STR) \
PARSE_ENTRY(entry, FIELD, TYPE, KEY_STR, KEY_STR)

#define PARSE_SYSLOG(FIELD, TYPE, KEY_STR) \
PARSE_ENTRY(syslog, FIELD, TYPE, KEY_STR, "syslog/" + KEY_STR)

double fileMaxAgeDays = -1;
double rotationBytes = -1;
bsl::string loggingVerbosityStr;
bsl::string bslsLogSeverityStr;
bsl::string consoleSeverityStr;
bsl::string syslogVerbosityStr;

// Iterate over each keys of the datum map..
for (bsl::size_t i = 0; i < datum.theMap().size(); ++i) {
const bdld::DatumMapEntry& entry = datum.theMap().data()[i];
PARSE_CONF(d_fileName, String, "fileName");
PARSE_CONF(fileMaxAgeDays, Double, "fileMaxAgeDays");
PARSE_CONF(rotationBytes, Double, "rotationBytes");
PARSE_CONF(d_logfileFormat, String, "logfileFormat");
PARSE_CONF(d_consoleFormat, String, "consoleFormat");
PARSE_CONF(loggingVerbosityStr, String, "loggingVerbosity");
PARSE_CONF(bslsLogSeverityStr, String, "bslsLogSeverityThreshold");
PARSE_CONF(consoleSeverityStr, String, "consoleSeverityThreshold");

if (bdlb::String::areEqualCaseless(entry.key(), "categories")) {
if (!entry.value().isArray()) {
errorDescription << "Key 'categories' must be an array";
return rc_INVALID_KEY_TYPE; // RETURN
}
bdld::DatumArrayRef array = entry.value().theArray();
for (bsls::Types::size_type idx = 0; idx < array.length(); ++idx) {
if (!array[idx].isString()) {
errorDescription << "Invalid type for categories[" << idx
<< "]: must be a string";
return rc_INVALID_KEY_TYPE; // RETURN
}
int rc = addCategoryProperties(array[idx].theString());
if (rc != 0) {
errorDescription << "Invalid string format for categories"
<< "[" << idx << "] [rc: " << rc << "]";
return rc_INVALID_KEY_VALUE; // RETURN
}
}
continue; // CONTINUE
}

if (bdlb::String::areEqualCaseless(entry.key(), "syslog")) {
if (!entry.value().isMap()) {
errorDescription << "Key 'syslog' must be a map";
return rc_INVALID_KEY_TYPE; // RETURN
}

bdld::DatumMapRef syslogConfig = entry.value().theMap();
for (bsl::size_t j = 0; j < syslogConfig.size(); ++j) {
const bdld::DatumMapEntry& syslog = syslogConfig.data()[j];

PARSE_SYSLOG(d_syslogEnabled, Boolean, "enabled");
PARSE_SYSLOG(d_syslogFormat, String, "logFormat");
PARSE_SYSLOG(d_syslogAppName, String, "appName");
PARSE_SYSLOG(syslogVerbosityStr, String, "verbosity");

// In a normal workflow should just 'continue'
errorDescription << "Unknown key 'syslog/" << syslog.key()
<< "'";
return rc_UNKNOWN_KEY; // RETURN
}

continue; // CONTINUE
}

// In a normal workflow should just 'continue'
errorDescription << "Unknown key '" << entry.key() << "'";
return rc_UNKNOWN_KEY; // RETURN
}

#undef PARSE_SYSLOG
#undef PARSE_CONF
#undef PARSE_ENTRY

if (fileMaxAgeDays <= 0) {
errorDescription << "Unset key 'fileMaxAgeDays'";
return rc_UNSET_VALUE; // RETURN
}
else {
d_fileMaxAgeDays = static_cast<int>(fileMaxAgeDays);
}

if (rotationBytes <= 0) {
errorDescription << "Unset key 'rotationBytes'";
return rc_UNSET_VALUE; // RETURN
}
else {
d_rotationBytes = static_cast<int>(rotationBytes);
}

if (ball::SeverityUtil::fromAsciiCaseless(&d_loggingVerbosity,
loggingVerbosityStr.c_str()) !=
0) {
errorDescription << "Invalid value for 'loggingVerbosity' ('"
<< loggingVerbosityStr << "')";
return rc_INVALID_KEY_VALUE; // RETURN
}

ball::Severity::Level bslsSeverityAsBal;
if (ball::SeverityUtil::fromAsciiCaseless(&bslsSeverityAsBal,
bslsLogSeverityStr.c_str()) !=
0) {
errorDescription << "Invalid value for 'bslsLogSeverityThreshold' ('"
<< bslsLogSeverityStr << "')";
return rc_INVALID_KEY_VALUE; // RETURN
}
d_bslsLogSeverityThreshold = LogControllerConfig::balToBslsLogLevel(
bslsSeverityAsBal);

if (ball::SeverityUtil::fromAsciiCaseless(&d_consoleSeverityThreshold,
consoleSeverityStr.c_str()) !=
0) {
errorDescription << "Invalid value for 'consoleSeverityThreshold' ('"
<< consoleSeverityStr << "')";
return rc_INVALID_KEY_VALUE; // RETURN
}

if (d_syslogEnabled && ball::SeverityUtil::fromAsciiCaseless(
&d_syslogVerbosity,
syslogVerbosityStr.c_str()) != 0) {
errorDescription << "Invalid value for 'syslog/verbosity' ('"
<< syslogVerbosityStr << "')";
return rc_INVALID_KEY_VALUE; // RETURN
}

return rc_SUCCESS;
}

// -------------------
// class LogController
// -------------------
Expand Down Expand Up @@ -642,7 +488,7 @@ int LogController::initialize(bsl::ostream& errorDescription,
// -------------
// LoggerManager
ball::LoggerManagerConfiguration lmc;
lmc.setLogOrder(ball::LoggerManagerConfiguration::LIFO);
lmc.setLogOrder(ball::LoggerManagerConfiguration::FIFO);
lmc.setDefaultThresholdLevelsCallback(bdlf::BindUtil::bind(
&ball::LoggerFunctorPayloads::loadParentCategoryThresholdValues,
bdlf::PlaceHolders::_1,
Expand All @@ -651,7 +497,7 @@ int LogController::initialize(bsl::ostream& errorDescription,
bdlf::PlaceHolders::_4,
bdlf::PlaceHolders::_5,
'.'));
rc = lmc.setDefaultRecordBufferSizeIfValid(32768);
rc = lmc.setDefaultRecordBufferSizeIfValid(config.recordBufferSizeBytes());
if (rc != 0) {
errorDescription << "Unable to set default record buffer size on lmc "
<< "[rc: " << rc << "]";
Expand Down Expand Up @@ -740,7 +586,9 @@ int LogController::initialize(bsl::ostream& errorDescription,

// -------------
// Configuration
setVerbosityLevel(config.loggingVerbosity());
setVerbosityLevel(config.loggingVerbosity(),
config.recordingVerbosity(),
config.triggerVerbosity());

const LogControllerConfig::CategoryPropertiesMap& categories =
config.categoriesProperties();
Expand Down Expand Up @@ -828,18 +676,20 @@ void LogController::shutdown()
d_isInitialized = false;
}

void LogController::setVerbosityLevel(ball::Severity::Level verbosity)
void LogController::setVerbosityLevel(ball::Severity::Level passVerbosity,
ball::Severity::Level recordVerbosity,
ball::Severity::Level triggerVerbosity)
{
ball::Administration::setDefaultThresholdLevels(
ball::Severity::OFF, // recording level
verbosity, // passthrough level
ball::Severity::OFF, // trigger level
recordVerbosity, // recording level
passVerbosity, // passthrough level
triggerVerbosity, // trigger level
ball::Severity::OFF); // triggerAll level
ball::Administration::setThresholdLevels(
"*",
ball::Severity::OFF, // recording level
verbosity, // passthrough level
ball::Severity::OFF, // trigger level
recordVerbosity, // recording level
passVerbosity, // passthrough level
triggerVerbosity, // trigger level
ball::Severity::OFF); // triggerAll level
}

Expand Down
72 changes: 56 additions & 16 deletions src/groups/bmq/bmqtsk/bmqtsk_logcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,20 @@ class LogControllerConfig {
CategoryPropertiesMap d_categories;
// Map of category properties

int d_recordBufferSizeBytes;
// Size in bytes of the logger's record buffer

ball::Severity::Level d_recordingVerbosity;
// If the severity level of the record is at least as severe as the
// d_recordingVerbosity, then the record will be stored by the logger in
// its log record buffer (i.e., it will be recorded).

ball::Severity::Level d_triggerVerbosity;
// If the severity of the record is at least as severe as the
// d_triggerVerbosity, then the record will cause immediate publication
// of that record and any records in the logger's log record buffer (i.e.,
// this record will trigger a log record dump).

private:
/// Convert specified BALL severity `level` to the corresponding
/// BSLS_LOG severity level.
Expand Down Expand Up @@ -269,6 +283,7 @@ class LogControllerConfig {
LogControllerConfig& setSyslogEnabled(bool value);
LogControllerConfig& setSyslogFormat(const bslstl::StringRef& value);
LogControllerConfig& setSyslogAppName(const bslstl::StringRef& value);
LogControllerConfig& setRecordBufferSize(int value);

/// Set the corresponding attribute to the specified `value` and return
/// a reference offering modifiable access to this object.
Expand All @@ -283,16 +298,6 @@ class LogControllerConfig {
/// Clear the registered list of category properties.
void clearCategoriesProperties();

/// Populate members of this object from the corresponding fields in the
/// specified `datum`. Return 0 on success, or a non-zero return code
/// on error, populating the specified `errorDescription` with a
/// description of the error. Note that in case of error, some of the
/// values from `datum` may have already been applied and so this object
/// might be partially altered. Refer to the component level
/// documentation (section: "LogControllerConfig: Datum format") for the
/// expected format of the `datum`.
int fromDatum(bsl::ostream& errorDescription, const bdld::Datum& datum);

/// Populate members of this object from the corresponding fields in the
/// specified `obj` (which should be of a type compatible with one
/// generated from a schema as described at the top in the component
Expand All @@ -316,6 +321,9 @@ class LogControllerConfig {
const bsl::string& syslogFormat() const;
const bsl::string& syslogAppName() const;
ball::Severity::Level syslogVerbosity() const;
int recordBufferSizeBytes() const;
ball::Severity::Level recordingVerbosity() const;
ball::Severity::Level triggerVerbosity() const;

/// Return the value of the corresponding attribute.
const CategoryPropertiesMap& categoriesProperties() const;
Expand Down Expand Up @@ -456,11 +464,18 @@ class LogController {
/// will no longer be available.
void shutdown();

/// Change the logging severity threshold to the specified `verbosity`:
/// any record with a severity of at least `verbosity` will be printed
/// to the log file, and eventually to the console if the configured
/// console severity threshold allows it.
void setVerbosityLevel(ball::Severity::Level verbosity);
/// Change the logging severity threshold to the specified verbosity
/// levels: any record with a severity of at least `passVerbosity` will
/// be printed immediately to the log file, and eventually to the
/// console if the configured console severity threshold allows it.
/// any record with a severity of at least `recordingVerbosity` will be
/// stored by the logger in its log record buffer. Any record with a
/// severity of at least `triggerVerbosity` will cause immediate
/// publication of that record and any records in the logger's buffer.
void setVerbosityLevel(
ball::Severity::Level passVerbosity,
ball::Severity::Level recordVerbosity = ball::Severity::OFF,
ball::Severity::Level triggerVerbosity = ball::Severity::OFF);

/// Change the verbosity of the specified `category` to the specified
/// `verbosity`. `category` can be an expression, with a terminating
Expand Down Expand Up @@ -512,7 +527,8 @@ int LogControllerConfig::fromObj(bsl::ostream& errorDescription,
.setConsoleFormat(obj.consoleFormat())
.setSyslogEnabled(obj.syslog().enabled())
.setSyslogAppName(obj.syslog().appName())
.setSyslogFormat(obj.syslog().logFormat());
.setSyslogFormat(obj.syslog().logFormat())
.setRecordBufferSize(32768);

if (ball::SeverityUtil::fromAsciiCaseless(
&d_loggingVerbosity,
Expand All @@ -522,6 +538,9 @@ int LogControllerConfig::fromObj(bsl::ostream& errorDescription,
return -1; // RETURN
}

d_recordingVerbosity = ball::Severity::OFF;
d_triggerVerbosity = ball::Severity::OFF;

ball::Severity::Level bslsSeverityAsBal = ball::Severity::e_ERROR;
// TODO: enforcing 'obj' to have 'bslsLogSeverityThreshold' accessor is a
// backward incompatible change from build perspective, and will require a
Expand Down Expand Up @@ -651,6 +670,12 @@ LogControllerConfig::setSyslogAppName(const bslstl::StringRef& value)
return *this;
}

inline LogControllerConfig& LogControllerConfig::setRecordBufferSize(int value)
{
d_recordBufferSizeBytes = value;
return *this;
}

inline LogControllerConfig&
LogControllerConfig::setSyslogVerbosity(ball::Severity::Level value)
{
Expand Down Expand Up @@ -725,6 +750,21 @@ inline ball::Severity::Level LogControllerConfig::syslogVerbosity() const
return d_syslogVerbosity;
}

inline int LogControllerConfig::recordBufferSizeBytes() const
{
return d_recordBufferSizeBytes;
}

inline ball::Severity::Level LogControllerConfig::recordingVerbosity() const
{
return d_recordingVerbosity;
}

inline ball::Severity::Level LogControllerConfig::triggerVerbosity() const
{
return d_triggerVerbosity;
}

inline const LogControllerConfig::CategoryPropertiesMap&
LogControllerConfig::categoriesProperties() const
{
Expand Down
Loading

0 comments on commit 90b398b

Please sign in to comment.