Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Log dumper #445

Merged
merged 6 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being deleted?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use it anywhere since 2019. We use 'fromObj()' method to parse the broker config instead


/// 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
Loading