1// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3
4#pragma once
5
6#ifndef SPDLOG_HEADER_ONLY
7# include <spdlog/sinks/ansicolor_sink.h>
8#endif
9
10#include <spdlog/pattern_formatter.h>
11#include <spdlog/details/os.h>
12
13namespace spdlog {
14namespace sinks {
15
16template<typename ConsoleMutex>
17SPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, color_mode mode)
18 : target_file_(target_file)
19 , mutex_(ConsoleMutex::mutex())
20 , formatter_(details::make_unique<spdlog::pattern_formatter>())
21
22{
23 set_color_mode(mode);
24 colors_[level::trace] = to_string_(white);
25 colors_[level::debug] = to_string_(cyan);
26 colors_[level::info] = to_string_(green);
27 colors_[level::warn] = to_string_(yellow_bold);
28 colors_[level::err] = to_string_(red_bold);
29 colors_[level::critical] = to_string_(bold_on_red);
30 colors_[level::off] = to_string_(reset);
31}
32
33template<typename ConsoleMutex>
34SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color)
35{
36 std::lock_guard<mutex_t> lock(mutex_);
37 colors_[static_cast<size_t>(color_level)] = to_string_(color);
38}
39
40template<typename ConsoleMutex>
41SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
42{
43 // Wrap the originally formatted message in color codes.
44 // If color is not supported in the terminal, log as is instead.
45 std::lock_guard<mutex_t> lock(mutex_);
46 msg.color_range_start = 0;
47 msg.color_range_end = 0;
48 memory_buf_t formatted;
49 formatter_->format(msg, formatted);
50 if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
51 {
52 // before color range
53 print_range_(formatted, 0, msg.color_range_start);
54 // in color range
55 print_ccode_(colors_[static_cast<size_t>(msg.level)]);
56 print_range_(formatted, msg.color_range_start, msg.color_range_end);
57 print_ccode_(reset);
58 // after color range
59 print_range_(formatted, msg.color_range_end, formatted.size());
60 }
61 else // no color
62 {
63 print_range_(formatted, 0, formatted.size());
64 }
65 fflush(target_file_);
66}
67
68template<typename ConsoleMutex>
69SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::flush()
70{
71 std::lock_guard<mutex_t> lock(mutex_);
72 fflush(target_file_);
73}
74
75template<typename ConsoleMutex>
76SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern)
77{
78 std::lock_guard<mutex_t> lock(mutex_);
79 formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
80}
81
82template<typename ConsoleMutex>
83SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)
84{
85 std::lock_guard<mutex_t> lock(mutex_);
86 formatter_ = std::move(sink_formatter);
87}
88
89template<typename ConsoleMutex>
90SPDLOG_INLINE bool ansicolor_sink<ConsoleMutex>::should_color()
91{
92 return should_do_colors_;
93}
94
95template<typename ConsoleMutex>
96SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
97{
98 switch (mode)
99 {
100 case color_mode::always:
101 should_do_colors_ = true;
102 return;
103 case color_mode::automatic:
104 should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
105 return;
106 case color_mode::never:
107 should_do_colors_ = false;
108 return;
109 default:
110 should_do_colors_ = false;
111 }
112}
113
114template<typename ConsoleMutex>
115SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code)
116{
117 fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
118}
119
120template<typename ConsoleMutex>
121SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end)
122{
123 fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);
124}
125
126template<typename ConsoleMutex>
127SPDLOG_INLINE std::string ansicolor_sink<ConsoleMutex>::to_string_(const string_view_t &sv)
128{
129 return std::string(sv.data(), sv.size());
130}
131
132// ansicolor_stdout_sink
133template<typename ConsoleMutex>
134SPDLOG_INLINE ansicolor_stdout_sink<ConsoleMutex>::ansicolor_stdout_sink(color_mode mode)
135 : ansicolor_sink<ConsoleMutex>(stdout, mode)
136{}
137
138// ansicolor_stderr_sink
139template<typename ConsoleMutex>
140SPDLOG_INLINE ansicolor_stderr_sink<ConsoleMutex>::ansicolor_stderr_sink(color_mode mode)
141 : ansicolor_sink<ConsoleMutex>(stderr, mode)
142{}
143
144} // namespace sinks
145} // namespace spdlog
146