diff --git a/bindings/libdnf5/logger.i b/bindings/libdnf5/logger.i
index 6983db3f6..9a2d51f75 100644
--- a/bindings/libdnf5/logger.i
+++ b/bindings/libdnf5/logger.i
@@ -19,7 +19,9 @@ typedef int32_t pid_t;
%{
#include "libdnf/common/weak_ptr.hpp"
#include "libdnf/logger/log_router.hpp"
+ #include "libdnf/logger/global_logger.hpp"
#include "libdnf/logger/memory_buffer_logger.hpp"
+ #include "libdnf/logger/factory.hpp"
%}
#define CV __perl_CV
@@ -44,4 +46,6 @@ wrap_unique_ptr(MemoryBufferLoggerUniquePtr, libdnf::MemoryBufferLogger);
}
%include "libdnf/logger/log_router.hpp"
+%include "libdnf/logger/global_logger.hpp"
%include "libdnf/logger/memory_buffer_logger.hpp"
+%include "libdnf/logger/factory.hpp"
diff --git a/dnf5/main.cpp b/dnf5/main.cpp
index a5e6a6b77..9fde4517f 100644
--- a/dnf5/main.cpp
+++ b/dnf5/main.cpp
@@ -54,20 +54,17 @@ along with libdnf. If not, see .
#include
#include
#include
+#include
#include
#include
-#include
#include
#include
#include
#include
#include
-#include
#include
-namespace fs = std::filesystem;
-
namespace dnf5 {
using namespace libdnf::cli;
@@ -648,21 +645,11 @@ int main(int argc, char * argv[]) try {
close(fd);
}
- auto log_dir_full_path = fs::path(base.get_config().get_installroot_option().get_value());
- log_dir_full_path += base.get_config().get_logdir_option().get_value();
- std::filesystem::create_directories(log_dir_full_path);
- auto log_file = log_dir_full_path / "dnf5.log";
- auto log_stream = std::make_unique(log_file, std::ios::app);
- if (!log_stream->is_open()) {
- throw std::runtime_error(fmt::format("Cannot open log file: {}: {}", log_file.c_str(), strerror(errno)));
- }
- // Throw exceptions if there is an error while writing to the log stream
- log_stream->exceptions(std::ios::badbit | std::ios::failbit);
- std::unique_ptr logger = std::make_unique(std::move(log_stream));
+ auto file_logger = libdnf::create_file_logger(base);
// Swap to destination stream logger (log to file)
- log_router.swap_logger(logger, 0);
+ log_router.swap_logger(file_logger, 0);
// Write messages from memory buffer logger to stream logger
- dynamic_cast(*logger).write_to_logger(log_router);
+ dynamic_cast(*file_logger).write_to_logger(log_router);
base.setup();
diff --git a/include/libdnf/logger/factory.hpp b/include/libdnf/logger/factory.hpp
new file mode 100644
index 000000000..e85186f0d
--- /dev/null
+++ b/include/libdnf/logger/factory.hpp
@@ -0,0 +1,40 @@
+/*
+Copyright Contributors to the libdnf project.
+
+This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
+
+Libdnf is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+Libdnf is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with libdnf. If not, see .
+*/
+
+#ifndef LIBDNF_LOGGER_FACTORY_HPP
+#define LIBDNF_LOGGER_FACTORY_HPP
+
+#include "logger.hpp"
+
+#include "libdnf/base/base.hpp"
+
+
+namespace libdnf {
+
+// File logger destination filename.
+constexpr const char * FILE_LOGGER_FILENAME = "dnf5.log";
+
+/// @brief Helper method for creating a file logger.
+/// @param base Reference to Base for loading the configured logger path.
+/// @return Instance of a new file logger.
+std::unique_ptr create_file_logger(libdnf::Base & base);
+
+} // namespace libdnf
+
+#endif
diff --git a/libdnf/logger/factory.cpp b/libdnf/logger/factory.cpp
new file mode 100644
index 000000000..64f52c6e0
--- /dev/null
+++ b/libdnf/logger/factory.cpp
@@ -0,0 +1,51 @@
+/*
+Copyright Contributors to the libdnf project.
+
+This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
+
+Libdnf is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+Libdnf is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with libdnf. If not, see .
+*/
+
+#include "libdnf/logger/factory.hpp"
+
+#include "libdnf/logger/stream_logger.hpp"
+
+#include
+#include
+
+
+namespace libdnf {
+
+using namespace std::filesystem;
+
+std::unique_ptr create_file_logger(Base & base) {
+ auto & config = base.get_config();
+ auto & installroot = config.get_installroot_option().get_value();
+ auto & logdir = config.get_logdir_option().get_value();
+ auto logdir_full_path = path(installroot) / path(logdir).relative_path();
+
+ create_directories(logdir_full_path);
+ auto log_file = logdir_full_path / FILE_LOGGER_FILENAME;
+ auto log_stream = std::make_unique(log_file, std::ios::app);
+ if (!log_stream->is_open()) {
+ throw std::runtime_error(fmt::format("Cannot open log file: {}: {}", log_file.c_str(), strerror(errno)));
+ }
+
+ // Throw exceptions if there is an error while writing to the log stream
+ log_stream->exceptions(std::ios::badbit | std::ios::failbit);
+
+ return std::make_unique(std::move(log_stream));
+}
+
+} // namespace libdnf
diff --git a/test/libdnf/logger/test_file_logger.cpp b/test/libdnf/logger/test_file_logger.cpp
new file mode 100644
index 000000000..1192366fb
--- /dev/null
+++ b/test/libdnf/logger/test_file_logger.cpp
@@ -0,0 +1,63 @@
+/*
+Copyright Contributors to the libdnf project.
+
+This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
+
+Libdnf is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+Libdnf is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with libdnf. If not, see .
+*/
+
+
+#include "test_file_logger.hpp"
+
+#include "libdnf/logger/factory.hpp"
+
+
+using namespace std::filesystem;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(FileLoggerTest);
+
+
+void FileLoggerTest::setUp() {
+ BaseTestCase::setUp();
+
+ auto & config = base.get_config();
+ auto & installroot = config.get_installroot_option().get_value();
+ auto & temp_logdir = "/var/log/FileLoggerTestLogDir";
+ config.get_logdir_option().set(temp_logdir);
+
+ full_log_path = path(installroot) / path(temp_logdir).relative_path() / libdnf::FILE_LOGGER_FILENAME;
+}
+
+
+void FileLoggerTest::tearDown() {
+ BaseTestCase::tearDown();
+ remove_all(full_log_path.parent_path());
+}
+
+
+void FileLoggerTest::test_file_logger_create() {
+ CPPUNIT_ASSERT(!exists(full_log_path));
+ auto file_logger = libdnf::create_file_logger(base);
+ CPPUNIT_ASSERT(exists(full_log_path));
+}
+
+
+void FileLoggerTest::test_file_logger_add() {
+ auto log_router = base.get_logger();
+ auto loggers_count_before = log_router->get_loggers_count();
+ auto file_logger = libdnf::create_file_logger(base);
+ log_router->add_logger(std::move(file_logger));
+ CPPUNIT_ASSERT_EQUAL(loggers_count_before + 1, log_router->get_loggers_count());
+}
diff --git a/test/libdnf/logger/test_file_logger.hpp b/test/libdnf/logger/test_file_logger.hpp
new file mode 100644
index 000000000..4c391d4aa
--- /dev/null
+++ b/test/libdnf/logger/test_file_logger.hpp
@@ -0,0 +1,46 @@
+/*
+Copyright Contributors to the libdnf project.
+
+This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
+
+Libdnf is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+Libdnf is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with libdnf. If not, see .
+*/
+
+
+#ifndef LIBDNF_TEST_FILE_LOGGER_HPP
+#define LIBDNF_TEST_FILE_LOGGER_HPP
+
+#include "base_test_case.hpp"
+
+#include
+#include
+
+
+class FileLoggerTest : public BaseTestCase {
+ CPPUNIT_TEST_SUITE(FileLoggerTest);
+ CPPUNIT_TEST(test_file_logger_create);
+ CPPUNIT_TEST(test_file_logger_add);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ void test_file_logger_create();
+ void test_file_logger_add();
+
+private:
+ std::filesystem::path full_log_path;
+};
+
+#endif
diff --git a/test/python3/libdnf5/logger/test_file_logger.py b/test/python3/libdnf5/logger/test_file_logger.py
new file mode 100644
index 000000000..3d86305dc
--- /dev/null
+++ b/test/python3/libdnf5/logger/test_file_logger.py
@@ -0,0 +1,60 @@
+# Copyright Contributors to the libdnf project.
+#
+# This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
+#
+# Libdnf is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# Libdnf is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with libdnf. If not, see .
+
+import libdnf5
+
+import base_test_case
+
+import os
+import shutil
+
+
+class TestFileLogger(base_test_case.BaseTestCase):
+ def setUp(self):
+ super().setUp()
+ config = self.base.get_config()
+ config.logdir = "FileLoggerTestLogDir"
+ self.full_log_path = os.path.join(config.installroot, config.logdir, libdnf5.logger.FILE_LOGGER_FILENAME)
+
+ def tearDown(self):
+ super().tearDown()
+ shutil.rmtree(os.path.dirname(self.full_log_path), ignore_errors=True)
+
+ def test_file_logger_create(self):
+ self.assertFalse(os.path.exists(self.full_log_path))
+ _ = libdnf5.logger.create_file_logger(self.base)
+ self.assertTrue(os.path.exists(self.full_log_path))
+
+ def test_file_logger_add(self):
+ log_router = self.base.get_logger()
+ loggers_count_before = log_router.get_loggers_count()
+ logger = libdnf5.logger.create_file_logger(self.base)
+ log_router.add_logger(logger)
+ self.assertEqual(loggers_count_before + 1, log_router.get_loggers_count())
+
+ def test_with_global_logger(self):
+ log_router = self.base.get_logger()
+ global_logger = libdnf5.logger.GlobalLogger()
+ global_logger.set(log_router.get(), libdnf5.logger.Logger.Level_DEBUG)
+ logger = libdnf5.logger.create_file_logger(self.base)
+ log_router.add_logger(logger)
+
+ # Run an action including librepo logging
+ self.add_repo_repomd("repomd-repo1")
+
+ with open(self.full_log_path) as logfile:
+ self.assertTrue('[librepo]' in logfile.read())