handler_ = make_shared<TestLogHandler>();
category->addHandler(handler_);
- category->setLevel(LogLevel::DEBUG, true);
+ category->setLevel(LogLevel::DBG, true);
}
static StringPiece pathBasename(StringPiece path) {
// Log from a sub-category.
Logger subLogger{&db_, "test.foo.bar"};
auto expectedLine = __LINE__ + 1;
- FB_LOG(subLogger, ERROR, "sub-category\nlog message");
+ FB_LOG(subLogger, ERR, "sub-category\nlog message");
auto& messages = handler_->getMessages();
ASSERT_EQ(1, messages.size());
EXPECT_EQ("sub-category\nlog message", messages[0].first.getMessage());
EXPECT_EQ("LoggerTest.cpp", pathBasename(messages[0].first.getFileName()));
EXPECT_EQ(expectedLine, messages[0].first.getLineNumber());
- EXPECT_EQ(LogLevel::ERROR, messages[0].first.getLevel());
+ EXPECT_EQ(LogLevel::ERR, messages[0].first.getLevel());
EXPECT_TRUE(messages[0].first.containsNewlines());
EXPECT_EQ(subLogger.getCategory(), messages[0].first.getCategory());
EXPECT_EQ(logger_.getCategory(), messages[0].second);
EXPECT_EQ(
"error formatting log message: "
"invalid format argument {:6.3f}: invalid specifier 'f'; "
- "format string: \"param1: {:06d}, param2: {:6.3f}\"",
+ "format string: \"param1: {:06d}, param2: {:6.3f}\", "
+ "arguments: (int: 1234), (char [13]: hello world!)",
messages[0].first.getMessage());
EXPECT_EQ("LoggerTest.cpp", pathBasename(messages[0].first.getFileName()));
EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
}
class ToStringFailure {};
+class FormattableButNoToString {};
[[noreturn]] void toAppend(
const ToStringFailure& /* arg */,
"error converting ToStringFailure object to a string");
}
+namespace folly {
+template <>
+class FormatValue<ToStringFailure> {
+ public:
+ explicit FormatValue(ToStringFailure) {}
+
+ template <class FormatCallback>
+ void format(FormatArg& arg, FormatCallback& cb) const {
+ FormatValue<std::string>("ToStringFailure").format(arg, cb);
+ }
+};
+
+template <>
+class FormatValue<FormattableButNoToString> {
+ public:
+ explicit FormatValue(FormattableButNoToString) {}
+
+ template <class FormatCallback>
+ void format(FormatArg&, FormatCallback&) const {
+ throw std::runtime_error("test");
+ }
+};
+} // namespace folly
+
TEST_F(LoggerTest, toStringError) {
// Use the folly::to<string> log API, with an object that will throw
// an exception when we try to convert it to a string.
EXPECT_EQ(logger_.getCategory(), messages[0].second);
}
+TEST_F(LoggerTest, formatFallbackError) {
+ // Check the behavior if logf() fails, and toAppend() also fails.
+ ToStringFailure obj;
+ FB_LOGF(logger_, WARN, "param1: {}, param2: {}, {}", 1234, obj);
+
+ auto& messages = handler_->getMessages();
+ ASSERT_EQ(1, messages.size());
+ EXPECT_EQ(
+ "error formatting log message: "
+ "invalid format argument {}: argument index out of range, max=2; "
+ "format string: \"param1: {}, param2: {}, {}\", "
+ "arguments: (int: 1234), (ToStringFailure: <error_converting_to_string>)",
+ messages[0].first.getMessage());
+ EXPECT_EQ("LoggerTest.cpp", pathBasename(messages[0].first.getFileName()));
+ EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
+ EXPECT_FALSE(messages[0].first.containsNewlines());
+ EXPECT_EQ(logger_.getCategory(), messages[0].first.getCategory());
+ EXPECT_EQ(logger_.getCategory(), messages[0].second);
+}
+
+TEST_F(LoggerTest, formatFallbackUnsupported) {
+ // Check the behavior if logf() fails, and toAppend() also fails.
+ FormattableButNoToString obj;
+ FB_LOGF(logger_, WARN, "param1: {}, param2: {}", 1234, obj);
+
+ auto& messages = handler_->getMessages();
+ ASSERT_EQ(1, messages.size());
+ EXPECT_EQ(
+ "error formatting log message: "
+ "test; "
+ "format string: \"param1: {}, param2: {}\", "
+ "arguments: (int: 1234), "
+ "(FormattableButNoToString: <no_string_conversion>)",
+ messages[0].first.getMessage());
+ EXPECT_EQ("LoggerTest.cpp", pathBasename(messages[0].first.getFileName()));
+ EXPECT_EQ(LogLevel::WARN, messages[0].first.getLevel());
+ EXPECT_FALSE(messages[0].first.containsNewlines());
+ EXPECT_EQ(logger_.getCategory(), messages[0].first.getCategory());
+ EXPECT_EQ(logger_.getCategory(), messages[0].second);
+}
+
TEST_F(LoggerTest, streamingArgs) {
auto& messages = handler_->getMessages();
Logger footest{&db_, "test.foo.test"};
Logger footest1234{&db_, "test.foo.test.1234"};
Logger other{&db_, "test.other"};
- db_.setLevel("test", LogLevel::ERROR);
+ db_.setLevel("test", LogLevel::ERR);
db_.setLevel("test.foo", LogLevel::DBG2);
db_.setLevel("test.foo.test", LogLevel::DBG7);
auto& messages = handler_->getMessages();
- // test.other's effective level should be ERROR, so a warning
+ // test.other's effective level should be ERR, so a warning
// message to it should be discarded
FB_LOG(other, WARN, "this should be discarded");
ASSERT_EQ(0, messages.size());
messages.clear();
// Bad format arguments should not throw
- FB_LOGF(footest1234, ERROR, "whoops: {}, {}", getValue());
+ FB_LOGF(footest1234, ERR, "whoops: {}, {}", getValue());
ASSERT_EQ(1, messages.size());
EXPECT_EQ(
"error formatting log message: "
"invalid format argument {}: argument index out of range, max=1; "
- "format string: \"whoops: {}, {}\"",
+ "format string: \"whoops: {}, {}\", "
+ "arguments: (int: 5)",
messages[0].first.getMessage());
messages.clear();
}