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