stdout_sinks-inl.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. #pragma once
  4. #ifndef SPDLOG_HEADER_ONLY
  5. #include <spdlog/sinks/stdout_sinks.h>
  6. #endif
  7. #include <memory>
  8. #include <spdlog/details/console_globals.h>
  9. #include <spdlog/pattern_formatter.h>
  10. #ifdef _WIN32
  11. // under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675)
  12. // so instead we use ::FileWrite
  13. #include <spdlog/details/windows_include.h>
  14. #ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp
  15. #include <fileapi.h> // WriteFile (..)
  16. #endif
  17. #include <io.h> // _get_osfhandle(..)
  18. #include <stdio.h> // _fileno(..)
  19. #endif // WIN32
  20. namespace spdlog {
  21. namespace sinks {
  22. template <typename ConsoleMutex>
  23. SPDLOG_INLINE stdout_sink_base<ConsoleMutex>::stdout_sink_base(FILE *file)
  24. : mutex_(ConsoleMutex::mutex()),
  25. file_(file),
  26. formatter_(details::make_unique<spdlog::pattern_formatter>()) {
  27. #ifdef _WIN32
  28. // get windows handle from the FILE* object
  29. handle_ = reinterpret_cast<HANDLE>(::_get_osfhandle(::_fileno(file_)));
  30. // don't throw to support cases where no console is attached,
  31. // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE).
  32. // throw only if non stdout/stderr target is requested (probably regular file and not console).
  33. if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) {
  34. throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno);
  35. }
  36. #endif // WIN32
  37. }
  38. template <typename ConsoleMutex>
  39. SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &msg) {
  40. #ifdef _WIN32
  41. if (handle_ == INVALID_HANDLE_VALUE) {
  42. return;
  43. }
  44. std::lock_guard<mutex_t> lock(mutex_);
  45. memory_buf_t formatted;
  46. formatter_->format(msg, formatted);
  47. auto size = static_cast<DWORD>(formatted.size());
  48. DWORD bytes_written = 0;
  49. bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0;
  50. if (!ok) {
  51. throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " +
  52. std::to_string(::GetLastError()));
  53. }
  54. #else
  55. std::lock_guard<mutex_t> lock(mutex_);
  56. memory_buf_t formatted;
  57. formatter_->format(msg, formatted);
  58. ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
  59. #endif // WIN32
  60. ::fflush(file_); // flush every line to terminal
  61. }
  62. template <typename ConsoleMutex>
  63. SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::flush() {
  64. std::lock_guard<mutex_t> lock(mutex_);
  65. fflush(file_);
  66. }
  67. template <typename ConsoleMutex>
  68. SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::set_pattern(const std::string &pattern) {
  69. std::lock_guard<mutex_t> lock(mutex_);
  70. formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
  71. }
  72. template <typename ConsoleMutex>
  73. SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::set_formatter(
  74. std::unique_ptr<spdlog::formatter> sink_formatter) {
  75. std::lock_guard<mutex_t> lock(mutex_);
  76. formatter_ = std::move(sink_formatter);
  77. }
  78. // stdout sink
  79. template <typename ConsoleMutex>
  80. SPDLOG_INLINE stdout_sink<ConsoleMutex>::stdout_sink()
  81. : stdout_sink_base<ConsoleMutex>(stdout) {}
  82. // stderr sink
  83. template <typename ConsoleMutex>
  84. SPDLOG_INLINE stderr_sink<ConsoleMutex>::stderr_sink()
  85. : stdout_sink_base<ConsoleMutex>(stderr) {}
  86. } // namespace sinks
  87. // factory methods
  88. template <typename Factory>
  89. SPDLOG_INLINE std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name) {
  90. return Factory::template create<sinks::stdout_sink_mt>(logger_name);
  91. }
  92. template <typename Factory>
  93. SPDLOG_INLINE std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name) {
  94. return Factory::template create<sinks::stdout_sink_st>(logger_name);
  95. }
  96. template <typename Factory>
  97. SPDLOG_INLINE std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name) {
  98. return Factory::template create<sinks::stderr_sink_mt>(logger_name);
  99. }
  100. template <typename Factory>
  101. SPDLOG_INLINE std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name) {
  102. return Factory::template create<sinks::stderr_sink_st>(logger_name);
  103. }
  104. } // namespace spdlog