Skip to content

Commit

Permalink
Move spdlog::logger to gz-utils (#134)
Browse files Browse the repository at this point in the history
* Move spdlog::logger to gz-utils

Signed-off-by: Michael Carroll <[email protected]>
Signed-off-by: Carlos Agüero <[email protected]>
Co-authored-by: Addisu Z. Taddese <[email protected]>
  • Loading branch information
mjcarroll and azeey authored Aug 20, 2024
1 parent ed26790 commit 095659d
Show file tree
Hide file tree
Showing 13 changed files with 455 additions and 1 deletion.
1 change: 1 addition & 0 deletions .github/ci/packages.apt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
libgz-cmake4-dev
libspdlog-dev
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ if(NOT GZ_UTILS_VENDOR_CLI11)
gz_find_package(CLI11 REQUIRED_BY cli PKGCONFIG_IGNORE)
endif()

gz_find_package(
spdlog
PKGCONFIG spdlog
REQUIRED_BY log
PURPOSE "Provide logging")

#============================================================================
# Configure the build
#============================================================================
gz_configure_build(QUIT_IF_BUILD_ERRORS
COMPONENTS cli)
COMPONENTS cli log)

#============================================================================
# Create package information
Expand Down
12 changes: 12 additions & 0 deletions examples/log/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.22.1 FATAL_ERROR)
project(gz-utils-logger-demo)

# Find the Gazebo Libraries used directly by the example
find_package(gz-utils3 REQUIRED COMPONENTS log)
set(GZ_UTILS_VER ${gz-utils3_VERSION_MAJOR})

add_executable(${PROJECT_NAME} main.cc)
target_link_libraries(
${PROJECT_NAME}
gz-utils${GZ_UTILS_VER}::log
)
37 changes: 37 additions & 0 deletions examples/log/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2024 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include <filesystem>
#include <gz/utils/log/Logger.hh>

//////////////////////////////////////////////////
int main(int argc, char** argv)
{
gz::utils::log::Logger logger("my_logger");
logger.RawLogger().set_level(spdlog::level::trace);

std::filesystem::path logDir = std::filesystem::temp_directory_path();
std::filesystem::path logFile = "my_log.txt";
std::filesystem::path logPath = logDir / logFile;

logger.SetLogDestination(logPath);
logger.RawLogger().trace("trace");
logger.RawLogger().info("info");
logger.RawLogger().warn("warn");
logger.RawLogger().error("error");
logger.RawLogger().critical("critical");
}
1 change: 1 addition & 0 deletions log/include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(gz/utils)
1 change: 1 addition & 0 deletions log/include/gz/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gz_install_all_headers(COMPONENT log)
68 changes: 68 additions & 0 deletions log/include/gz/utils/log/Logger.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2024 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GZ_UTILS_LOG_LOGGER_HH_
#define GZ_UTILS_LOG_LOGGER_HH_

#include <spdlog/spdlog.h>
#include <memory>
#include <string>
#include <gz/utils/config.hh>
#include <gz/utils/ImplPtr.hh>
#include <gz/utils/log/Export.hh>

namespace gz
{
namespace utils
{
namespace log
{
inline namespace GZ_UTILS_VERSION_NAMESPACE {

/// \brief Gazebo console and file logging class.
/// This will configure spdlog with a sane set of defaults for logging to the
/// console as well as a file.
class GZ_UTILS_LOG_VISIBLE Logger
{
/// \brief Class constructor.
/// \param[in] _loggerName Logger name.
public: explicit Logger(const std::string &_loggerName);

/// \brief Set the log destination filename.
/// \param[in] _filename Log file name.
public: void SetLogDestination(const std::string &_filename);

/// \brief Get the log destination filename.
/// \return Log file name.
public: std::string LogDestination() const;

/// \brief Access the underlying spdlog logger.
/// \return The spdlog logger.
public: [[nodiscard]] spdlog::logger &RawLogger() const;

/// \brief Access the underlying spdlog logger, with ownership.
/// \return The spdlog logger.
public: [[nodiscard]] std::shared_ptr<spdlog::logger> RawLoggerPtr() const;

/// \brief Implementation Pointer.
GZ_UTILS_UNIQUE_IMPL_PTR(dataPtr)
};
} // namespace GZ_UTILS_LOG_VERSION_NAMESPACE
} // namespace log
} // namespace utils
} // namespace gz

#endif // GZ_UTILS_LOG_LOGGER_HH_
81 changes: 81 additions & 0 deletions log/include/gz/utils/log/SplitSink.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2024 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#ifndef GZ_UTILS_LOG_SPLITSINK_HH_
#define GZ_UTILS_LOG_SPLITSINK_HH_

#include <memory>
#include <string>

#include <gz/utils/config.hh>
#include <gz/utils/ImplPtr.hh>
#include <gz/utils/log/Export.hh>

#include <spdlog/details/log_msg.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>

namespace gz
{
namespace utils
{
namespace log
{
inline namespace GZ_UTILS_VERSION_NAMESPACE {

/// \brief Logging sink for spdlog that logs in Gazebo-conventions.
///
/// This will route messages with severity (warn, err, critical) to stderr,
/// and all other levels (info, debug, trace) to stdout.
class GZ_UTILS_LOG_VISIBLE SplitConsoleSink : public spdlog::sinks::sink
{
/// \brief Class constructor.
public: SplitConsoleSink();

/// \brief Class destructor.
public: ~SplitConsoleSink() override = default;

/// \brief Log a message.
/// \param[in] _msg The message to log.
public: void log(const spdlog::details::log_msg &_msg) override;

/// \brief Flush messages.
public: void flush() override;

/// \brief Set the logging pattern.
/// \param[in] _pattern The logging pattern.
public: void set_pattern(const std::string &_pattern) override;

/// \brief Set the new formatter.
/// \param[in] _sinkFormatter The formatter.
public: void set_formatter(std::unique_ptr<spdlog::formatter> _sinkFormatter)
override;

/// \brief Set the color mode.
/// \param[in] _mode Color mode.
public: void set_color_mode(spdlog::color_mode _mode);

/// \brief Implementation Pointer.
GZ_UTILS_UNIQUE_IMPL_PTR(dataPtr)
};
} // namespace GZ_UTILS_LOG_VERSION_NAMESPACE
} // namespace log
} // namespace utils
} // namespace gz

#endif // GZ_UTILS_LOG_SPLITSINK_HH__
15 changes: 15 additions & 0 deletions log/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
gz_get_libsources_and_unittests(sources gtest_sources)

gz_add_component(log
SOURCES ${sources}
INDEPENDENT_FROM_PROJECT_LIB
GET_TARGET_NAME gz_utils_log_target_name)

target_link_libraries(${gz_utils_log_target_name}
PUBLIC
spdlog::spdlog)

gz_build_tests(TYPE UNIT
SOURCES ${gtest_sources}
LIB_DEPS ${gz_utils_log_target_name}
)
104 changes: 104 additions & 0 deletions log/src/Logger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2024 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <memory>
#include <string>

#include <gz/utils/log/Logger.hh>
#include <gz/utils/log/SplitSink.hh>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/dist_sink.h>
#include <spdlog/spdlog.h>

namespace gz::utils::log
{
/// \brief Private data for the Logger class.
class Logger::Implementation
{
/// \brief Constructor.
/// \param[in] _loggerName Logger name.
public: explicit Implementation(const std::string &_loggerName)
: consoleSink(std::make_shared<SplitConsoleSink>()),
sinks(std::make_shared<spdlog::sinks::dist_sink_mt>()),
logger(std::make_shared<spdlog::logger>(_loggerName, sinks))
{
}

/// \brief The console sink with stdout and stderr.
std::shared_ptr<SplitConsoleSink> consoleSink;

/// \brief The file sink for logging into a file.
std::shared_ptr<spdlog::sinks::basic_file_sink_mt> fileSink {nullptr};

/// \brief A sink distribution storing multiple sinks.
std::shared_ptr<spdlog::sinks::dist_sink_mt> sinks {nullptr};

/// \brief The underlying spdlog logger.
std::shared_ptr<spdlog::logger> logger {nullptr};
};

/////////////////////////////////////////////////
Logger::Logger(const std::string &_loggerName)
: dataPtr(gz::utils::MakeUniqueImpl<Implementation>(_loggerName))
{
// Add the console sink by default.
this->dataPtr->sinks->add_sink(this->dataPtr->consoleSink);

// Configure the logger.
this->dataPtr->logger->set_level(spdlog::level::err);
this->dataPtr->logger->flush_on(spdlog::level::err);

spdlog::flush_every(std::chrono::seconds(5));
spdlog::register_logger(this->dataPtr->logger);
}

/////////////////////////////////////////////////
void Logger::SetLogDestination(const std::string &_filename)
{
if (this->dataPtr->fileSink)
this->dataPtr->sinks->remove_sink(this->dataPtr->fileSink);

if (!_filename.empty())
{
this->dataPtr->fileSink =
std::make_shared<spdlog::sinks::basic_file_sink_mt>(_filename, true);
this->dataPtr->sinks->add_sink(this->dataPtr->fileSink);
}
}

/////////////////////////////////////////////////
std::string Logger::LogDestination() const
{
std::string logPath = "";
if (this->dataPtr->fileSink)
logPath = this->dataPtr->fileSink->filename();

return logPath;
}

/////////////////////////////////////////////////
spdlog::logger &Logger::RawLogger() const
{
return *this->dataPtr->logger;
}

/////////////////////////////////////////////////
std::shared_ptr<spdlog::logger> Logger::RawLoggerPtr() const
{
return this->dataPtr->logger;
}

} // namespace gz::utils::log
Loading

0 comments on commit 095659d

Please sign in to comment.