// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) #pragma once #ifndef SPDLOG_HEADER_ONLY #include #endif #include #include #include #ifdef _WIN32 // under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675) // so instead we use ::FileWrite #include #include // WriteFile (..) #include // _get_osfhandle(..) #include // _fileno(..) #endif // WIN32 namespace spdlog { namespace sinks { template SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) : mutex_(ConsoleMutex::mutex()) , file_(file) , formatter_(details::make_unique()) { #ifdef _WIN32 // get windows handle from the FILE* object handle_ = (HANDLE)::_get_osfhandle(::_fileno(file_)); // don't throw to support cases where no console is attached, // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). // throw only if non stdout/stderr target is requested (probably regular file and not console). if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) { throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); } #endif // WIN32 } template SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) { #ifdef _WIN32 if (handle_ == INVALID_HANDLE_VALUE) { return; } std::lock_guard lock(mutex_); memory_buf_t formatted; formatter_->format(msg, formatted); ::fflush(file_); // flush in case there is somthing in this file_ already auto size = static_cast(formatted.size()); DWORD bytes_written = 0; bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; if (!ok) { throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError())); } #else std::lock_guard lock(mutex_); memory_buf_t formatted; formatter_->format(msg, formatted); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); ::fflush(file_); // flush every line to terminal #endif // WIN32 } template SPDLOG_INLINE void stdout_sink_base::flush() { std::lock_guard lock(mutex_); fflush(file_); } template SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) { std::lock_guard lock(mutex_); formatter_ = std::unique_ptr(new pattern_formatter(pattern)); } template SPDLOG_INLINE void stdout_sink_base::set_formatter(std::unique_ptr sink_formatter) { std::lock_guard lock(mutex_); formatter_ = std::move(sink_formatter); } // stdout sink template SPDLOG_INLINE stdout_sink::stdout_sink() : stdout_sink_base(stdout) {} // stderr sink template SPDLOG_INLINE stderr_sink::stderr_sink() : stdout_sink_base(stderr) {} } // namespace sinks // factory methods template SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) { return Factory::template create(logger_name); } template SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) { return Factory::template create(logger_name); } template SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) { return Factory::template create(logger_name); } template SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) { return Factory::template create(logger_name); } } // namespace spdlog