• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/mpl/vector.hpp>
22 #include <boost/mpl/vector/vector40.hpp>
23 #include <boost/preprocessor/cat.hpp>
24 #include <boost/preprocessor/seq/enum.hpp>
25 #include <boost/preprocessor/seq/size.hpp>
26 #include <boost/date_time/special_defs.hpp>
27 #include <boost/date_time/gregorian/gregorian_types.hpp>
28 #include <boost/date_time/local_time/local_time_types.hpp>
29 #include <boost/date_time/posix_time/posix_time_types.hpp>
30 #include <boost/log/trivial.hpp>
31 #include <boost/log/attributes/attribute_name.hpp>
32 #include <boost/log/attributes/value_visitation.hpp>
33 #include <boost/log/utility/type_dispatch/standard_types.hpp>
34 #include <boost/log/utility/type_dispatch/date_time_types.hpp>
35 #include <boost/log/utility/string_literal.hpp>
36 #include <boost/log/utility/formatting_ostream.hpp>
37 #include <boost/log/detail/code_conversion.hpp>
38 #include <boost/log/detail/snprintf.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 
47 namespace boost {
48 
49 BOOST_LOG_OPEN_NAMESPACE
50 
51 namespace 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 
75 BOOST_LOG_ANONYMOUS_NAMESPACE {
76 
77 //! The default formatter generated by the default formatter factory
78 template< typename CharT >
79 class default_formatter
80 {
81 public:
82     typedef void result_type;
83 
84 private:
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(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &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(value);
112                 char buf[32];
113                 std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
114                 std::size_t size = sizeof(buf) - len;
115                 int res = boost::log::aux::snprintf(buf + len, size, ".%.6u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000));
116                 if (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(value);
149                 char buf[32];
150                 std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d", &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::log::aux::snprintf(buf, sizeof(buf), "%.2llu:%.2u:%.2u.%.6u", hours, minutes, seconds, useconds);
176                 if (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 
244 public:
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 
258 private:
259     const attribute_name m_attribute_name;
260 };
261 
262 } // namespace
263 
264 //! The callback for equality relation filter
265 template< typename CharT >
266 typename default_formatter_factory< CharT >::formatter_type
267 default_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
275 template class default_formatter_factory< char >;
276 #endif
277 #ifdef BOOST_LOG_USE_WCHAR_T
278 template class default_formatter_factory< wchar_t >;
279 #endif
280 
281 } // namespace aux
282 
283 BOOST_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