| // Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <lib/syslog/cpp/log_settings.h> | |
| #include <lib/syslog/cpp/logging_backend.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <string> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "src/lib/files/file.h" | |
| #include "src/lib/files/scoped_temp_dir.h" | |
| #ifdef __Fuchsia__ | |
| #include <lib/syslog/global.h> | |
| #include <lib/syslog/logger.h> | |
| #include <lib/syslog/wire_format.h> | |
| #include <lib/zx/socket.h> | |
| #endif | |
| namespace syslog { | |
| namespace { | |
| class LoggingFixture : public ::testing::Test { | |
| public: | |
| LoggingFixture() : old_severity_(GetMinLogLevel()), old_stderr_(dup(STDERR_FILENO)) {} | |
| ~LoggingFixture() { | |
| SetLogSettings({.min_log_level = old_severity_}); | |
| #ifdef __Fuchsia__ | |
| // Go back to using STDERR. | |
| fx_logger_t* logger = fx_log_get_logger(); | |
| fx_logger_activate_fallback(logger, -1); | |
| #else | |
| dup2(old_stderr_, STDERR_FILENO); | |
| #endif | |
| } | |
| private: | |
| LogSeverity old_severity_; | |
| int old_stderr_; | |
| }; | |
| using LoggingFixtureDeathTest = LoggingFixture; | |
| TEST_F(LoggingFixture, Log) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| int error_line = __LINE__ + 1; | |
| FX_LOGS(ERROR) << "something at error"; | |
| int info_line = __LINE__ + 1; | |
| FX_LOGS(INFO) << "and some other at info level"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| #ifdef __Fuchsia__ | |
| EXPECT_THAT(log, testing::HasSubstr("ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(error_line) + ")] something at error")); | |
| EXPECT_THAT(log, testing::HasSubstr("INFO: [logging_unittest.cc(" + std::to_string(info_line) + | |
| ")] and some other at info level")); | |
| #else | |
| EXPECT_THAT(log, testing::HasSubstr("[ERROR:sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(error_line) + ")] something at error")); | |
| EXPECT_THAT(log, testing::HasSubstr("[INFO:logging_unittest.cc(" + std::to_string(info_line) + | |
| ")] and some other at info level")); | |
| #endif | |
| } | |
| TEST_F(LoggingFixture, LogFirstN) { | |
| constexpr int kLimit = 5; | |
| constexpr int kCycles = 20; | |
| constexpr const char* kLogMessage = "Hello"; | |
| static_assert(kCycles > kLimit); | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| for (int i = 0; i < kCycles; ++i) { | |
| FX_LOGS_FIRST_N(ERROR, kLimit) << kLogMessage; | |
| } | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| int count = 0; | |
| size_t pos = 0; | |
| while ((pos = log.find(kLogMessage, pos)) != std::string::npos) { | |
| ++count; | |
| ++pos; | |
| } | |
| EXPECT_EQ(kLimit, count); | |
| } | |
| TEST_F(LoggingFixture, LogT) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| int error_line = __LINE__ + 1; | |
| FX_LOGST(ERROR, "first") << "something at error"; | |
| int info_line = __LINE__ + 1; | |
| FX_LOGST(INFO, "second") << "and some other at info level"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| #ifdef __Fuchsia__ | |
| EXPECT_THAT(log, testing::HasSubstr("first] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(error_line) + ")] something at error")); | |
| EXPECT_THAT(log, | |
| testing::HasSubstr("second] INFO: [logging_unittest.cc(" + std::to_string(info_line) + | |
| ")] and some other at info level")); | |
| #else | |
| EXPECT_THAT(log, testing::HasSubstr("[first] [ERROR:sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(error_line) + ")] something at error")); | |
| EXPECT_THAT(log, | |
| testing::HasSubstr("[second] [INFO:logging_unittest.cc(" + std::to_string(info_line) + | |
| ")] and some other at info level")); | |
| #endif | |
| } | |
| TEST_F(LoggingFixture, VLogT) { | |
| LogSettings new_settings; | |
| new_settings.min_log_level = (LOG_INFO - 2); // verbosity = 2 | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings, {}); | |
| int line = __LINE__ + 1; | |
| FX_VLOGST(1, "first") << "First message"; | |
| FX_VLOGST(2, "second") << "ABCD"; | |
| FX_VLOGST(3, "third") << "EFGH"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_THAT(log, testing::HasSubstr("[first] VLOG(1): [logging_unittest.cc(" + | |
| std::to_string(line) + ")] First message")); | |
| EXPECT_THAT(log, testing::HasSubstr("second")); | |
| EXPECT_THAT(log, testing::HasSubstr("ABCD")); | |
| EXPECT_THAT(log, testing::Not(testing::HasSubstr("third"))); | |
| EXPECT_THAT(log, testing::Not(testing::HasSubstr("EFGH"))); | |
| } | |
| TEST_F(LoggingFixture, VlogVerbosity) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| EXPECT_EQ(0, GetVlogVerbosity()); | |
| new_settings.min_log_level = LOG_INFO - 1; | |
| SetLogSettings(new_settings); | |
| EXPECT_EQ(1, GetVlogVerbosity()); | |
| new_settings.min_log_level = LOG_INFO - 15; | |
| SetLogSettings(new_settings); | |
| EXPECT_EQ(15, GetVlogVerbosity()); | |
| new_settings.min_log_level = LOG_DEBUG; | |
| SetLogSettings(new_settings); | |
| EXPECT_EQ(0, GetVlogVerbosity()); | |
| } | |
| TEST_F(LoggingFixture, DVLogNoMinLevel) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| FX_DVLOGS(1) << "hello"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_EQ(log, ""); | |
| } | |
| TEST_F(LoggingFixture, DVLogWithMinLevel) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| new_settings.min_log_level = (LOG_INFO - 1); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| FX_DVLOGS(1) << "hello"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| #if defined(NDEBUG) | |
| EXPECT_EQ(log, ""); | |
| #else | |
| EXPECT_THAT(log, testing::HasSubstr("hello")); | |
| #endif | |
| } | |
| TEST_F(LoggingFixtureDeathTest, CheckFailed) { ASSERT_DEATH(FX_CHECK(false), ""); } | |
| #if defined(__Fuchsia__) | |
| TEST_F(LoggingFixture, Plog) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| FX_PLOGS(ERROR, ZX_OK) << "should be ok"; | |
| FX_PLOGS(ERROR, ZX_ERR_ACCESS_DENIED) << "got access denied"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_THAT(log, testing::HasSubstr("should be ok: 0 (ZX_OK)")); | |
| EXPECT_THAT(log, testing::HasSubstr("got access denied: -30 (ZX_ERR_ACCESS_DENIED)")); | |
| } | |
| TEST_F(LoggingFixture, PlogT) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| int line1 = __LINE__ + 1; | |
| FX_PLOGST(ERROR, "abcd", ZX_OK) << "should be ok"; | |
| int line2 = __LINE__ + 1; | |
| FX_PLOGST(ERROR, "qwerty", ZX_ERR_ACCESS_DENIED) << "got access denied"; | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_THAT(log, testing::HasSubstr("abcd] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line1) + ")] should be ok: 0 (ZX_OK)")); | |
| EXPECT_THAT(log, testing::HasSubstr("qwerty] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line2) + | |
| ")] got access denied: -30 (ZX_ERR_ACCESS_DENIED)")); | |
| } | |
| #endif // defined(__Fuchsia__) | |
| TEST_F(LoggingFixture, SLog) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| int line1 = __LINE__ + 1; | |
| FX_SLOG(ERROR)("tag", "String log"); | |
| int line2 = __LINE__ + 1; | |
| FX_SLOG(ERROR)("tag", 42); | |
| int line3 = __LINE__ + 1; | |
| FX_SLOG(ERROR)("tag", {42, "string"}); | |
| int line4 = __LINE__ + 1; | |
| FX_SLOG(ERROR)("tag", {"first"_k = 42, "second"_k = "string"}); | |
| int line5 = __LINE__ + 1; | |
| FX_SLOG(ERROR)("String log"); | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_THAT(log, testing::HasSubstr("tag] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line1) + ")] String log")); | |
| EXPECT_THAT(log, testing::HasSubstr("tag] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line2) + ")] 42")); | |
| EXPECT_THAT(log, testing::HasSubstr("tag] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line3) + ")] [42, \"string\"]")); | |
| EXPECT_THAT(log, testing::HasSubstr("tag] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line4) + | |
| ")] {\"first\": 42, \"second\": \"string\"}")); | |
| EXPECT_THAT(log, | |
| testing::HasSubstr("String log] ERROR: [sdk/lib/syslog/cpp/logging_unittest.cc(" + | |
| std::to_string(line5) + ")]")); | |
| } | |
| TEST_F(LoggingFixture, BackendDirect) { | |
| LogSettings new_settings; | |
| EXPECT_EQ(LOG_INFO, new_settings.min_log_level); | |
| files::ScopedTempDir temp_dir; | |
| ASSERT_TRUE(temp_dir.NewTempFile(&new_settings.log_file)); | |
| SetLogSettings(new_settings); | |
| syslog_backend::WriteLog(syslog::LOG_ERROR, "foo.cc", 42, "fake tag", "condition", "Log message"); | |
| syslog_backend::WriteLogValue(syslog::LOG_ERROR, "foo.cc", 42, "fake tag", "condition", | |
| {"foo"_k = 42}); | |
| std::string log; | |
| ASSERT_TRUE(files::ReadFileToString(new_settings.log_file, &log)); | |
| EXPECT_THAT(log, | |
| testing::HasSubstr("ERROR: [foo.cc(42)] Check failed: condition. Log message\n")); | |
| EXPECT_THAT(log, | |
| testing::HasSubstr("ERROR: [foo.cc(42)] Check failed: condition. {\"foo\": 42}\n")); | |
| } | |
| } // namespace | |
| } // namespace syslog |