Commit e374ef6a authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

logging: add an initLoggingOrDie() function

Summary:
Add folly::initLoggingOrDie(), which behaves like `initLogging()` but handles
errors by printing a message to stderr and then calling `exit(1)`.

Most programs are expected to initialize logging early on during program
start-up, and will likely use a command line argument or other configuration
value as the logging settings.  If an error occurs they usually want to print
the message to stderr and exit unsuccesfully. `initLoggingOrDie()` makes it
easy to perform these steps without requiring programs to write their own
exception handlers to handle errors from `initLogging()`.

Reviewed By: chadaustin

Differential Revision: D7164830

fbshipit-source-id: d688046f1b6240c948e4aaabfc9fb24ba3d9ff89
parent dd2f2ef7
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
namespace folly { namespace folly {
void initLogging(StringPiece configString) { void initLogging(StringPiece configString) {
// Get the base logging configuration
auto* const baseConfigStr = getBaseLoggingConfig(); auto* const baseConfigStr = getBaseLoggingConfig();
// Return early if we have nothing to do // Return early if we have nothing to do
if (!baseConfigStr && configString.empty()) { if (!baseConfigStr && configString.empty()) {
...@@ -44,4 +45,23 @@ void initLogging(StringPiece configString) { ...@@ -44,4 +45,23 @@ void initLogging(StringPiece configString) {
LoggerDB::get().updateConfig(config); LoggerDB::get().updateConfig(config);
} }
void initLoggingOrDie(StringPiece configString) {
try {
initLogging(configString);
} catch (const std::exception& ex) {
// Print the error message. We intentionally use ex.what() here instead
// of folly::exceptionStr() to avoid including the exception type name in
// the output. The exceptions thrown by the logging library on error
// should have enough information to diagnose what is wrong with the
// input config string.
//
// We want the output here to be user-friendly since this will be shown
// to any user invoking a program with an error in the logging
// configuration string. This output is intended for end users rather
// than developers.
fprintf(stderr, "error parsing logging configuration: %s\n", ex.what());
exit(1);
}
}
} // namespace folly } // namespace folly
...@@ -27,18 +27,33 @@ namespace folly { ...@@ -27,18 +27,33 @@ namespace folly {
/** /**
* Initialize the logging library. * Initialize the logging library.
* *
* The input string will be parsed with parseLogConfig() and then applied to * This function performs the following steps:
* the main LoggerDB singleton. * - Call folly::getBaseLoggingConfig() to get the base logging configuration
* for your program.
* - Parse the input configString parameter with parseLogConfig(), and update
* the base configuration with the settings from this argument.
* - Apply these combined settings to the main LoggerDB singleton using
* LoggerDB::updateConfig()
* *
* This will apply the configuration using LoggerDB::updateConfig(), so the new * This function will throw an exception on error. Most errors are normally
* configuration will be merged into the existing initial configuration defined * due to invalid logging configuration strings: e.g., invalid log level names
* by initializeLoggerDB(). * or referencing undefined log handlers.
* *
* Callers that do want to completely replace the settings can call * If you are invoking this from your program's main() function it is often
* LoggerDB::resetConfig() instead of using initLogging(). * more convenient to use initLoggingOrDie() to terminate your program
* gracefully on error rather than having to handle exceptions yourself.
*/ */
void initLogging(folly::StringPiece configString = ""); void initLogging(folly::StringPiece configString = "");
/**
* Initialize the logging library, and exit the program on error.
*
* This function behaves like initLogging(), but if an error occurs processing
* the logging configuration it will print an error message to stderr and then
* call exit(1) to terminate the program.
*/
void initLoggingOrDie(folly::StringPiece configString = "");
/** /**
* folly::getBaseLoggingConfig() allows individual executables to easily * folly::getBaseLoggingConfig() allows individual executables to easily
* customize their default logging configuration. * customize their default logging configuration.
......
...@@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { ...@@ -48,7 +48,7 @@ int main(int argc, char* argv[]) {
// Call folly::init() and then initialize log levels and handlers // Call folly::init() and then initialize log levels and handlers
folly::init(&argc, &argv); folly::init(&argc, &argv);
folly::initLogging(FLAGS_logging); folly::initLoggingOrDie(FLAGS_logging);
// All XLOG() statements in this file will log to the category // All XLOG() statements in this file will log to the category
// folly.experimental.logging.example.main // folly.experimental.logging.example.main
......
...@@ -615,7 +615,7 @@ TEST(AsyncFileWriter, discard) { ...@@ -615,7 +615,7 @@ TEST(AsyncFileWriter, discard) {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
folly::init(&argc, &argv); folly::init(&argc, &argv);
folly::initLogging(FLAGS_logging); folly::initLoggingOrDie(FLAGS_logging);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }
...@@ -86,7 +86,7 @@ std::string fbLogFatalCheck() { ...@@ -86,7 +86,7 @@ std::string fbLogFatalCheck() {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Call folly::init() and then initialize log levels and handlers // Call folly::init() and then initialize log levels and handlers
folly::init(&argc, &argv); folly::init(&argc, &argv);
folly::initLogging(FLAGS_logging); folly::initLoggingOrDie(FLAGS_logging);
// Do most of the work in a separate helper function. // Do most of the work in a separate helper function.
// //
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#include <folly/experimental/logging/test/ConfigHelpers.h> #include <folly/experimental/logging/test/ConfigHelpers.h>
#include <folly/portability/GFlags.h> #include <folly/portability/GFlags.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/test/TestUtils.h>
using folly::initLogging;
using folly::LoggerDB; using folly::LoggerDB;
using folly::parseLogConfig; using folly::parseLogConfig;
...@@ -52,12 +54,28 @@ TEST(Init, checkConfig) { ...@@ -52,12 +54,28 @@ TEST(Init, checkConfig) {
// Call initLogging() // Call initLogging()
// Make sure it merges the supplied config argument with our custom // Make sure it merges the supplied config argument with our custom
// base configuration. // base configuration.
folly::initLogging(".=ERROR,folly.logging=DBG7"); initLogging(".=ERROR,folly.logging=DBG7");
EXPECT_EQ(1, getBaseLoggingConfigCalled); EXPECT_EQ(1, getBaseLoggingConfigCalled);
EXPECT_EQ( EXPECT_EQ(
parseLogConfig(".:=ERROR:default,folly=INFO:,folly.logging=DBG7:; " parseLogConfig(".:=ERROR:default,folly=INFO:,folly.logging=DBG7:; "
"default=stream:stream=stdout,async=false"), "default=stream:stream=stdout,async=false"),
LoggerDB::get().getConfig()); LoggerDB::get().getConfig());
// Test calling initLogging() with bad configuration strings, and
// configured such that it should throw an exception on error rather than
// exiting.
//
// Note that it is okay to call initLogging() multiple times (we already
// called it successfully once above), but this isn't really something to
// expect most callers to want to do.
EXPECT_THROW_RE(
initLogging(".=BOGUSLEVEL"),
folly::LogConfigParseError,
R"(invalid log level "BOGUSLEVEL")");
EXPECT_THROW_RE(
initLogging(".=ERR:undefined_handler"),
std::invalid_argument,
R"(unknown log handler "undefined_handler")");
} }
// We use our custom main() to ensure that folly::initLogging() has // We use our custom main() to ensure that folly::initLogging() has
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment