diff --git a/fpsdk_common/include/fpsdk_common/logging.hpp b/fpsdk_common/include/fpsdk_common/logging.hpp index 6e564fb..b4079c7 100644 --- a/fpsdk_common/include/fpsdk_common/logging.hpp +++ b/fpsdk_common/include/fpsdk_common/logging.hpp @@ -359,6 +359,50 @@ void LoggingPrint(const LoggingLevel level, const std::size_t repeat, const char void LoggingHexdump(const LoggingLevel level, const uint8_t* data, const std::size_t size, const char* prefix, const char* fmt, ...) PRINTF_ATTR(5); +/** + * @brief Utility to create a std::ostream that prints through the logging system + * + * For example: + * + * @code{cpp} + * auto w = LoggingOstream(LoggingLevel::WARNING); + * *w << "Hello world!" << std::endl; // This should print: Warning: Hello world! + * @endcode + * + * @note Flushing the stream is required for the log message to be printed. Typically, std::endl flushes. Otherwise + * explicitly flush using std::flush when appropriate. + */ +class LoggingOstream +{ + public: + /** + * @brief Constructor + * + * @param[in] level The logging level to use + */ + LoggingOstream(const LoggingLevel level); + + /** + * @brief Get stream handle + * + * @returns the stream handle + */ + std::ostream& operator*() + { + return str_; + } + + private: + //! Helper buffer that prints through logging + struct StrBuf : public std::stringbuf + { + virtual int sync(); //!< Print function implementation + LoggingLevel level_; //!< Logging level + }; + StrBuf buf_; //!< Helper buffer + std::ostream str_; //!< Stream handle +}; + // Helper macros #ifndef _DOXYGEN_ # define _FPSDK_LOGGING_LOG(_level_, ...) \ diff --git a/fpsdk_common/src/logging.cpp b/fpsdk_common/src/logging.cpp index ac72237..123c609 100644 --- a/fpsdk_common/src/logging.cpp +++ b/fpsdk_common/src/logging.cpp @@ -360,6 +360,34 @@ void LoggingHexdump( } } +// --------------------------------------------------------------------------------------------------------------------- + +LoggingOstream::LoggingOstream(const LoggingLevel level) : str_{ &buf_ } +{ + buf_.level_ = level; +} + +int LoggingOstream::StrBuf::sync() +{ + // Print each line + const auto s = this->str(); + std::size_t offs = 0; + std::size_t pos = 0; + while ((pos = s.find("\n", offs)) != std::string::npos) { + switch (level_) { // clang-format off + case LoggingLevel::FATAL: FATAL( "%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::ERROR: ERROR( "%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::WARNING: WARNING("%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::NOTICE: NOTICE( "%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::INFO: INFO( "%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::DEBUG: DEBUG( "%s", s.substr(offs, pos).c_str()); break; + case LoggingLevel::TRACE: TRACE( "%s", s.substr(offs, pos).c_str()); break; + } // clang-format on + offs = pos + 1; + } + return 0; +} + /* ****************************************************************************************************************** */ } // namespace logging } // namespace common