1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   default_sink.cpp
9  * \author Andrey Semashev
10  * \date   19.04.2007
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <boost/log/detail/config.hpp>
17 #include <cstdio>
18 #include <boost/optional/optional.hpp>
19 #if !defined(BOOST_LOG_NO_THREADS)
20 #include <boost/thread/locks.hpp>
21 #include <boost/log/detail/thread_id.hpp>
22 #endif
23 #include <boost/log/detail/default_attribute_names.hpp>
24 #include <boost/date_time/microsec_time_clock.hpp>
25 #include <boost/date_time/time_resolution_traits.hpp>
26 #include <boost/date_time/gregorian/gregorian_types.hpp>
27 #include "default_sink.hpp"
28 #include <boost/log/detail/header.hpp>
29 
30 namespace boost {
31 
32 BOOST_LOG_OPEN_NAMESPACE
33 
34 #if !defined(BOOST_LOG_NO_THREADS)
35 
36 namespace aux {
37 
38 // Defined in thread_id.cpp
39 void format_thread_id(char* buf, std::size_t size, thread::id tid);
40 
41 } // namespace aux
42 
43 #endif // !defined(BOOST_LOG_NO_THREADS)
44 
45 namespace sinks {
46 
47 namespace aux {
48 
49 BOOST_LOG_ANONYMOUS_NAMESPACE {
50 
51 //! A special time point type that contains decomposed date and time to avoid excessive calculations
52 struct decomposed_time_point
53 {
54     struct date_type :
55         public gregorian::greg_year_month_day
56     {
57         date_type(year_type y, month_type m, day_type d) :
58             gregorian::greg_year_month_day(y, m, d)
59         {
60         }
61     };
62 
63     struct time_duration_type :
64         public date_time::micro_res
65     {
66         typedef date_time::micro_res rep_type;
67 
68         hour_type hours;
69         min_type minutes;
70         sec_type seconds;
71         fractional_seconds_type useconds;
72 
73         time_duration_type(hour_type h, min_type m, sec_type s, fractional_seconds_type u) :
74             hours(h),
75             minutes(m),
76             seconds(s),
77             useconds(u)
78         {
79         }
80     };
81 
82     date_type date;
83     time_duration_type time;
84 
85     decomposed_time_point(date_type const& d, time_duration_type const& t) :
86         date(d),
87         time(t)
88     {
89     }
90 };
91 
92 inline const char* severity_level_to_string(boost::log::trivial::severity_level lvl)
93 {
94     switch (lvl)
95     {
96     case boost::log::trivial::trace:
97         return "[trace]  ";
98     case boost::log::trivial::debug:
99         return "[debug]  ";
100     case boost::log::trivial::info:
101         return "[info]   ";
102     case boost::log::trivial::warning:
103         return "[warning]";
104     case boost::log::trivial::error:
105         return "[error]  ";
106     case boost::log::trivial::fatal:
107         return "[fatal]  ";
108     default:
109         return "[-]      ";
110     }
111 }
112 
113 struct message_printer
114 {
115     typedef void result_type;
116 
117     explicit message_printer(boost::log::trivial::severity_level lvl) : m_level(lvl)
118     {
119     }
120 
121 #ifdef BOOST_LOG_USE_CHAR
122 
123     result_type operator() (std::string const& msg) const
124     {
125 #if !defined(BOOST_LOG_NO_THREADS)
126         char thread_id_buf[64];
127         boost::log::aux::format_thread_id(thread_id_buf, sizeof(thread_id_buf), boost::log::aux::this_thread::get_id());
128 #endif
129 
130         const decomposed_time_point now = date_time::microsec_clock< decomposed_time_point >::local_time();
131 
132         std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%06u] "
133 #if !defined(BOOST_LOG_NO_THREADS)
134                     "[%s] "
135 #endif
136                     "%s %s\n",
137             static_cast< unsigned int >(now.date.year),
138             static_cast< unsigned int >(now.date.month),
139             static_cast< unsigned int >(now.date.day),
140             static_cast< unsigned int >(now.time.hours),
141             static_cast< unsigned int >(now.time.minutes),
142             static_cast< unsigned int >(now.time.seconds),
143             static_cast< unsigned int >(now.time.useconds),
144 #if !defined(BOOST_LOG_NO_THREADS)
145             thread_id_buf,
146 #endif
147             severity_level_to_string(m_level),
148             msg.c_str());
149     }
150 
151 #endif
152 
153 #ifdef BOOST_LOG_USE_WCHAR_T
154 
155     result_type operator() (std::wstring const& msg) const
156     {
157 #if !defined(BOOST_LOG_NO_THREADS)
158         char thread_id_buf[64];
159         boost::log::aux::format_thread_id(thread_id_buf, sizeof(thread_id_buf), boost::log::aux::this_thread::get_id());
160 #endif
161 
162         const decomposed_time_point now = date_time::microsec_clock< decomposed_time_point >::local_time();
163 
164         std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%06u] "
165 #if !defined(BOOST_LOG_NO_THREADS)
166                     "[%s] "
167 #endif
168                     "%s %ls\n",
169             static_cast< unsigned int >(now.date.year),
170             static_cast< unsigned int >(now.date.month),
171             static_cast< unsigned int >(now.date.day),
172             static_cast< unsigned int >(now.time.hours),
173             static_cast< unsigned int >(now.time.minutes),
174             static_cast< unsigned int >(now.time.seconds),
175             static_cast< unsigned int >(now.time.useconds),
176 #if !defined(BOOST_LOG_NO_THREADS)
177             thread_id_buf,
178 #endif
179             severity_level_to_string(m_level),
180             msg.c_str());
181     }
182 
183 #endif
184 
185 private:
186     const boost::log::trivial::severity_level m_level;
187 };
188 
189 } // namespace
190 
191 default_sink::default_sink() :
192     sink(false),
193     m_severity_name(boost::log::aux::default_attribute_names::severity()),
194     m_message_name(boost::log::aux::default_attribute_names::message()),
195     m_severity_extractor(boost::log::trivial::info)
196 {
197 }
198 
~default_sink()199 default_sink::~default_sink()
200 {
201 }
202 
will_consume(attribute_value_set const &)203 bool default_sink::will_consume(attribute_value_set const&)
204 {
205     return true;
206 }
207 
consume(record_view const & rec)208 void default_sink::consume(record_view const& rec)
209 {
210     BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);)
211     m_message_visitor(m_message_name, rec.attribute_values(), message_printer(m_severity_extractor(m_severity_name, rec).get()));
212 }
213 
flush()214 void default_sink::flush()
215 {
216     BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);)
217     std::fflush(stdout);
218 }
219 
220 } // namespace aux
221 
222 } // namespace sinks
223 
224 BOOST_LOG_CLOSE_NAMESPACE // namespace log
225 
226 } // namespace boost
227 
228 #include <boost/log/detail/footer.hpp>
229