log_utils.hpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* Copyright (c) 2018-2025 Marcelo Zimbres Silva (mzimbres@gmail.com)
  2. *
  3. * Distributed under the Boost Software License, Version 1.0. (See
  4. * accompanying file LICENSE.txt)
  5. */
  6. #ifndef BOOST_REDIS_LOG_UTILS_HPP
  7. #define BOOST_REDIS_LOG_UTILS_HPP
  8. #include <boost/redis/logger.hpp>
  9. #include <boost/core/ignore_unused.hpp>
  10. #include <boost/system/error_code.hpp>
  11. #include <cstddef>
  12. #include <string>
  13. #include <string_view>
  14. #include <type_traits>
  15. namespace boost::redis::detail {
  16. // Internal trait that defines how to log different types.
  17. // The base template applies to types convertible to string_view
  18. template <class T>
  19. struct log_traits {
  20. // log should convert the input value to string and append it to the supplied buffer
  21. static inline void log(std::string& to, std::string_view value) { to += value; }
  22. };
  23. // Formatting size_t and error codes is shared between almost all FSMs, so it's defined here.
  24. // Support for types used only in one FSM should be added in the relevant FSM file.
  25. template <>
  26. struct log_traits<std::size_t> {
  27. static inline void log(std::string& to, std::size_t value) { to += std::to_string(value); }
  28. };
  29. template <>
  30. struct log_traits<system::error_code> {
  31. static inline void log(std::string& to, system::error_code value)
  32. {
  33. // Using error_code::what() includes any source code info
  34. // that the error may contain, making the messages too long.
  35. // This implementation was taken from error_code::what()
  36. to += value.message();
  37. to += " [";
  38. to += value.to_string();
  39. to += ']';
  40. }
  41. };
  42. template <class... Args>
  43. void format_log_args(std::string& to, const Args&... args)
  44. {
  45. auto dummy = {(log_traits<Args>::log(to, args), 0)...};
  46. ignore_unused(dummy);
  47. }
  48. // Logs a message with the specified severity to the logger.
  49. // Formatting won't be performed if the logger's level is inferior to lvl.
  50. // args are stringized using log_traits, and concatenated.
  51. template <class Arg0, class... Rest>
  52. void log(buffered_logger& to, logger::level lvl, const Arg0& arg0, const Rest&... arg_rest)
  53. {
  54. // Severity check
  55. if (to.lgr.lvl < lvl)
  56. return;
  57. // Optimization: if we get passed a single string, don't copy it to the buffer
  58. if constexpr (sizeof...(Rest) == 0u && std::is_convertible_v<Arg0, std::string_view>) {
  59. to.lgr.fn(lvl, arg0);
  60. } else {
  61. to.buffer.clear();
  62. format_log_args(to.buffer, arg0, arg_rest...);
  63. to.lgr.fn(lvl, to.buffer);
  64. }
  65. }
  66. // Shorthand for each log level we use
  67. template <class... Args>
  68. void log_debug(buffered_logger& to, const Args&... args)
  69. {
  70. log(to, logger::level::debug, args...);
  71. }
  72. template <class... Args>
  73. void log_info(buffered_logger& to, const Args&... args)
  74. {
  75. log(to, logger::level::info, args...);
  76. }
  77. template <class... Args>
  78. void log_err(buffered_logger& to, const Args&... args)
  79. {
  80. log(to, logger::level::err, args...);
  81. }
  82. } // namespace boost::redis::detail
  83. #endif // BOOST_REDIS_LOGGER_HPP