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_formatter_factory.cpp
9 * \author Andrey Semashev
10 * \date 14.07.2013
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#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
17
18#include <boost/log/detail/setup_config.hpp>
19#include <cstddef>
20#include <ctime>
21#include <boost/core/snprintf.hpp>
22#include <boost/mpl/vector.hpp>
23#include <boost/mpl/vector/vector40.hpp>
24#include <boost/preprocessor/cat.hpp>
25#include <boost/preprocessor/seq/enum.hpp>
26#include <boost/preprocessor/seq/size.hpp>
27#include <boost/date_time/special_defs.hpp>
28#include <boost/date_time/gregorian/gregorian_types.hpp>
29#include <boost/date_time/local_time/local_time_types.hpp>
30#include <boost/date_time/posix_time/posix_time_types.hpp>
31#include <boost/log/trivial.hpp>
32#include <boost/log/attributes/attribute_name.hpp>
33#include <boost/log/attributes/value_visitation.hpp>
34#include <boost/log/utility/type_dispatch/standard_types.hpp>
35#include <boost/log/utility/type_dispatch/date_time_types.hpp>
36#include <boost/log/utility/string_literal.hpp>
37#include <boost/log/utility/formatting_ostream.hpp>
38#include <boost/log/detail/code_conversion.hpp>
39#include <boost/log/detail/process_id.hpp>
40#if !defined(BOOST_LOG_NO_THREADS)
41#include <boost/log/detail/thread_id.hpp>
42#endif
43#include <boost/log/attributes/named_scope.hpp>
44#include "default_formatter_factory.hpp"
45#include <boost/log/detail/header.hpp>
46
47namespace boost {
48
49BOOST_LOG_OPEN_NAMESPACE
50
51namespace aux {
52
53#if !defined(BOOST_LOG_NO_THREADS)
54#define BOOST_LOG_AUX_THREAD_ID_TYPE() (boost::log::aux::thread::id)
55#else
56#define BOOST_LOG_AUX_THREAD_ID_TYPE()
57#endif
58
59#define BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()\
60 (boost::log::trivial::severity_level)\
61 (boost::log::attributes::named_scope_list)\
62 (boost::log::aux::process::id)\
63 BOOST_LOG_AUX_THREAD_ID_TYPE()
64
65// The list of the attribute value types supported by the default formatter. Note that we have to exclude std::time_t
66// as it is an integral type, as well as double from the native time duration types - these are part of arithmetic types already.
67#define BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()\
68 BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES()\
69 (std::tm)\
70 BOOST_LOG_BOOST_DATE_TYPES()\
71 BOOST_LOG_BOOST_TIME_DURATION_TYPES()\
72 BOOST_LOG_BOOST_TIME_PERIOD_TYPES()\
73 BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()
74
75BOOST_LOG_ANONYMOUS_NAMESPACE {
76
77//! The default formatter generated by the default formatter factory
78template< typename CharT >
79class default_formatter
80{
81public:
82 typedef void result_type;
83
84private:
85 //! Attribute value visitor
86 struct visitor
87 {
88 typedef void result_type;
89
90 explicit visitor(basic_formatting_ostream< CharT >& strm) : m_strm(strm)
91 {
92 }
93
94 template< typename T >
95 void operator() (T const& value) const
96 {
97 m_strm << value;
98 }
99
100 void operator() (std::tm const& value) const
101 {
102 char buf[32];
103 std::size_t len = std::strftime(s: buf, maxsize: sizeof(buf), format: "%Y-%m-%d %H:%M:%S", tp: &value);
104 m_strm.write(buf, len);
105 }
106
107 void operator() (boost::posix_time::ptime const& value) const
108 {
109 if (!value.is_special())
110 {
111 std::tm t = boost::posix_time::to_tm(t: value);
112 char buf[32];
113 std::size_t len = std::strftime(s: buf, maxsize: sizeof(buf), format: "%Y-%m-%d %H:%M:%S", tp: &t);
114 std::size_t size = sizeof(buf) - len;
115 int res = boost::core::snprintf(s: buf + len, maxlen: size, format: ".%.6u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000));
116 if (BOOST_UNLIKELY(res < 0))
117 buf[len] = '\0';
118 else if (static_cast< std::size_t >(res) >= size)
119 len += size - 1;
120 else
121 len += res;
122
123 m_strm.write(buf, len);
124 }
125 else
126 {
127 format_special_date_time(value);
128 }
129 }
130
131 void operator() (boost::local_time::local_date_time const& value) const
132 {
133 if (!value.is_special())
134 {
135 this->operator()(value.local_time());
136 m_strm << ' ' << value.zone_as_posix_string();
137 }
138 else
139 {
140 format_special_date_time(value);
141 }
142 }
143
144 void operator() (boost::gregorian::date const& value) const
145 {
146 if (!value.is_special())
147 {
148 std::tm t = boost::gregorian::to_tm(d: value);
149 char buf[32];
150 std::size_t len = std::strftime(s: buf, maxsize: sizeof(buf), format: "%Y-%m-%d", tp: &t);
151 m_strm.write(buf, len);
152 }
153 else
154 {
155 format_special_date_time(value.as_special());
156 }
157 }
158
159 void operator() (boost::posix_time::time_duration const& value) const
160 {
161 if (!value.is_special())
162 {
163 boost::posix_time::time_duration val = value;
164 if (val.is_negative())
165 {
166 m_strm << '-';
167 val = -val;
168 }
169 unsigned long long total_useconds = value.total_microseconds();
170 unsigned long long hours = total_useconds / (3600ull * 1000000ull);
171 unsigned int minutes = static_cast< unsigned int >(total_useconds / (60ull * 1000000ull) % 60ull);
172 unsigned int seconds = static_cast< unsigned int >(total_useconds / 1000000ull % 60ull);
173 unsigned int useconds = static_cast< unsigned int >(total_useconds % 1000000ull);
174 char buf[64];
175 int len = boost::core::snprintf(s: buf, maxlen: sizeof(buf), format: "%.2llu:%.2u:%.2u.%.6u", hours, minutes, seconds, useconds);
176 if (BOOST_LIKELY(len > 0))
177 {
178 unsigned int size = static_cast< unsigned int >(len) >= sizeof(buf) ? static_cast< unsigned int >(sizeof(buf)) : static_cast< unsigned int >(len);
179 m_strm.write(buf, size);
180 }
181 }
182 else
183 {
184 format_special_date_time(value);
185 }
186 }
187
188 void operator() (boost::gregorian::date_duration const& value) const
189 {
190 if (!value.is_special())
191 {
192 m_strm << value.get_rep().as_number();
193 }
194 else
195 {
196 format_special_date_time(value.get_rep().as_special());
197 }
198 }
199
200 template< typename PointRepT, typename DurationRepT >
201 void operator() (boost::date_time::period< PointRepT, DurationRepT > const& value) const
202 {
203 m_strm << '[';
204 this->operator()(value.begin());
205 m_strm << '/';
206 this->operator()(value.last());
207 m_strm << ']';
208 }
209
210 private:
211 template< typename T >
212 void format_special_date_time(T const& value) const
213 {
214 if (value.is_not_a_date_time())
215 m_strm << "not-a-date-time";
216 else if (value.is_pos_infinity())
217 m_strm << "+infinity";
218 else if (value.is_neg_infinity())
219 m_strm << "-infinity";
220 }
221
222 void format_special_date_time(boost::date_time::special_values value) const
223 {
224 switch (value)
225 {
226 case boost::date_time::not_a_date_time:
227 m_strm << "not-a-date-time";
228 break;
229 case boost::date_time::pos_infin:
230 m_strm << "+infinity";
231 break;
232 case boost::date_time::neg_infin:
233 m_strm << "-infinity";
234 break;
235 default:
236 break;
237 }
238 }
239
240 private:
241 basic_formatting_ostream< CharT >& m_strm;
242 };
243
244public:
245 explicit default_formatter(attribute_name name) : m_attribute_name(name)
246 {
247 }
248
249 result_type operator() (record_view const& rec, basic_formatting_ostream< CharT >& strm) const
250 {
251 typedef BOOST_PP_CAT(mpl::vector, BOOST_PP_SEQ_SIZE(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()))<
252 BOOST_PP_SEQ_ENUM(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES())
253 > value_types;
254
255 boost::log::visit< value_types >(m_attribute_name, rec, visitor(strm));
256 }
257
258private:
259 const attribute_name m_attribute_name;
260};
261
262} // namespace
263
264//! The callback for equality relation filter
265template< typename CharT >
266typename default_formatter_factory< CharT >::formatter_type
267default_formatter_factory< CharT >::create_formatter(attribute_name const& name, args_map const& args)
268{
269 // No user-defined factory, shall use the most generic formatter we can ever imagine at this point
270 return formatter_type(default_formatter< CharT >(name));
271}
272
273// Explicitly instantiate factory implementation
274#ifdef BOOST_LOG_USE_CHAR
275template class default_formatter_factory< char >;
276#endif
277#ifdef BOOST_LOG_USE_WCHAR_T
278template class default_formatter_factory< wchar_t >;
279#endif
280
281} // namespace aux
282
283BOOST_LOG_CLOSE_NAMESPACE // namespace log
284
285} // namespace boost
286
287#include <boost/log/detail/footer.hpp>
288
289#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
290

source code of boost/libs/log/src/setup/default_formatter_factory.cpp