From 15ed06e6065e3b83ecd2199562b7b6d2591f5cbb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 23 Feb 2014 21:04:22 +0400 Subject: [PATCH] Added support for bare filename and function name extraction in the named scope formatter. Function name does not work yet if function types are present in the scope (function) signature. --- src/named_scope_format_parser.cpp | 75 ++++++- test/run/form_named_scope.cpp | 324 +++++++++++++++++++++++++++--- 2 files changed, 372 insertions(+), 27 deletions(-) diff --git a/src/named_scope_format_parser.cpp b/src/named_scope_format_parser.cpp index efd8f2b..26f21a1 100644 --- a/src/named_scope_format_parser.cpp +++ b/src/named_scope_format_parser.cpp @@ -13,6 +13,8 @@ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. */ +#include +#include #include #include #include @@ -76,7 +78,39 @@ public: } }; - struct file_name + template< bool OmitScopeV > + struct function_name + { + typedef void result_type; + + result_type operator() (stream_type& strm, value_type const& value) const + { + const char* const begin = value.scope_name.c_str(); + const char* const paren = std::strchr(begin, '('); + if (paren) + { + const char* p = paren; + for (; p != begin; --p) + { + const char c = *(p - 1); + if (OmitScopeV && c == ':') + break; + if (c == ' ') + break; + } + + if (p != begin && p != paren) + { + strm.write(p, paren - p); + return; + } + } + + strm << value.scope_name; + } + }; + + struct full_file_name { typedef void result_type; @@ -86,6 +120,27 @@ public: } }; + struct file_name + { + typedef void result_type; + + result_type operator() (stream_type& strm, value_type const& value) const + { + std::size_t n = value.file_name.size(), i = n; + for (; i > 0; --i) + { + const char c = value.file_name[i - 1]; +#if defined(BOOST_WINDOWS) + if (c == '\\') + break; +#endif + if (c == '/') + break; + } + strm.write(value.file_name.c_str() + i, n - i); + } + }; + struct line_number { typedef void result_type; @@ -182,7 +237,25 @@ do_parse_named_scope_format(const CharT* begin, const CharT* end) fmt.add_formatter(typename formatter_type::scope_name()); break; + case 'c': + if (!literal.empty()) + fmt.add_formatter(typename formatter_type::literal(literal)); + fmt.add_formatter(typename formatter_type::BOOST_NESTED_TEMPLATE function_name< false >()); + break; + + case 'C': + if (!literal.empty()) + fmt.add_formatter(typename formatter_type::literal(literal)); + fmt.add_formatter(typename formatter_type::BOOST_NESTED_TEMPLATE function_name< true >()); + break; + case 'f': + if (!literal.empty()) + fmt.add_formatter(typename formatter_type::literal(literal)); + fmt.add_formatter(typename formatter_type::full_file_name()); + break; + + case 'F': if (!literal.empty()) fmt.add_formatter(typename formatter_type::literal(literal)); fmt.add_formatter(typename formatter_type::file_name()); diff --git a/test/run/form_named_scope.cpp b/test/run/form_named_scope.cpp index e759d94..e9df8b5 100644 --- a/test/run/form_named_scope.cpp +++ b/test/run/form_named_scope.cpp @@ -15,6 +15,7 @@ #define BOOST_TEST_MODULE form_named_scope #include +#include #include #include #include @@ -37,36 +38,71 @@ namespace { template< typename CharT > struct named_scope_test_data; + struct named_scope_test_data_base + { + static logging::string_literal scope1() { return logging::str_literal("scope1"); } + static logging::string_literal scope2() { return logging::str_literal("scope2"); } + + static logging::string_literal function_name1() { return logging::str_literal("int main(int, char *[])"); } + static logging::string_literal function_name2() { return logging::str_literal("int __cdecl main(int, char *[])"); } + static logging::string_literal function_name3() { return logging::str_literal("namespace_name::type foo()"); } + static logging::string_literal function_name4() { return logging::str_literal("namespace_name::type& foo::bar(int[], std::string const&)"); } + static logging::string_literal function_name5() { return logging::str_literal("void* namespc::foo::bar()"); } + static logging::string_literal function_name6() { return logging::str_literal("void* namespc::foo::bar(int) const"); } + static logging::string_literal function_name7() { return logging::str_literal("void (*)() namespc::foo::bar(int (my_class::*)(float*), my_class*) const volatile"); } + static logging::string_literal function_name8() { return logging::str_literal("void (*)(const int (&)[]) namespc::foo::bar(int (my_class::*)(float*), my_class*)"); } + + static logging::string_literal file() { return logging::str_literal(__FILE__); } + static logging::string_literal posix_file() { return logging::str_literal("/home/user/posix_file.cpp"); } + static logging::string_literal windows_file1() { return logging::str_literal("C:\\user\\windows_file1.cpp"); } + static logging::string_literal windows_file2() { return logging::str_literal("C:/user/windows_file2.cpp"); } + }; + #ifdef BOOST_LOG_USE_CHAR template< > struct named_scope_test_data< char > : - public test_data< char > + public test_data< char >, + public named_scope_test_data_base { static logging::string_literal default_format() { return logging::str_literal("%n"); } static logging::string_literal full_format() { return logging::str_literal("%n (%f:%l)"); } + static logging::string_literal short_filename_format() { return logging::str_literal("%n (%F:%l)"); } + static logging::string_literal scope_function_name_format() { return logging::str_literal("%c"); } + static logging::string_literal function_name_format() { return logging::str_literal("%C"); } static logging::string_literal delimiter1() { return logging::str_literal("|"); } - - static logging::string_literal scope1() { return logging::str_literal("scope1"); } - static logging::string_literal scope2() { return logging::str_literal("scope2"); } - static logging::string_literal file() { return logging::str_literal(__FILE__); } }; #endif // BOOST_LOG_USE_CHAR #ifdef BOOST_LOG_USE_WCHAR_T template< > struct named_scope_test_data< wchar_t > : - public test_data< wchar_t > + public test_data< wchar_t >, + public named_scope_test_data_base { static logging::wstring_literal default_format() { return logging::str_literal(L"%n"); } static logging::wstring_literal full_format() { return logging::str_literal(L"%n (%f:%l)"); } + static logging::wstring_literal short_filename_format() { return logging::str_literal(L"%n (%F:%l)"); } + static logging::wstring_literal scope_function_name_format() { return logging::str_literal(L"%c"); } + static logging::wstring_literal function_name_format() { return logging::str_literal(L"%C"); } static logging::wstring_literal delimiter1() { return logging::str_literal(L"|"); } - - static logging::string_literal scope1() { return logging::str_literal("scope1"); } - static logging::string_literal scope2() { return logging::str_literal("scope2"); } - static logging::string_literal file() { return logging::str_literal(__FILE__); } }; #endif // BOOST_LOG_USE_WCHAR_T + template< typename CharT > + inline bool check_formatting(logging::basic_string_literal< CharT > const& format, logging::record_view const& rec, std::basic_string< CharT > const& expected) + { + typedef logging::basic_formatter< CharT > formatter; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef named_scope_test_data< CharT > data; + + string str; + osstream strm(str); + formatter f = expr::stream << expr::format_named_scope(data::attr1(), keywords::format = format.c_str()); + f(rec, strm); + return equal_strings(strm.str(), expected); + } + } // namespace // The test checks that named scopes stack formatting works @@ -80,8 +116,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_formatting, CharT, char_types) typedef logging::attribute_set attr_set; typedef std::basic_string< CharT > string; typedef logging::basic_formatting_ostream< CharT > osstream; - typedef logging::record_view record_view; typedef logging::basic_formatter< CharT > formatter; + typedef logging::record_view record_view; typedef named_scope_test_data< CharT > data; named_scope attr; @@ -99,24 +135,18 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_formatting, CharT, char_types) // Default format { - string str1, str2; - osstream strm1(str1), strm2(str2); - formatter f = expr::stream << expr::format_named_scope(data::attr1(), - keywords::format = data::default_format().c_str()); - f(rec, strm1); - strm2 << data::scope1() << "->" << data::scope2(); - BOOST_CHECK(equal_strings(strm1.str(), strm2.str())); + string str; + osstream strm(str); + strm << data::scope1() << "->" << data::scope2(); + BOOST_CHECK(check_formatting(data::default_format(), rec, strm.str())); } // Full format { - string str1, str2; - osstream strm1(str1), strm2(str2); - formatter f = expr::stream << expr::format_named_scope(data::attr1(), - keywords::format = data::full_format().c_str()); - f(rec, strm1); - strm2 << data::scope1() << " (" << data::file() << ":" << line1 << ")->" - << data::scope2() << " (" << data::file() << ":" << line2 << ")"; - BOOST_CHECK(equal_strings(strm1.str(), strm2.str())); + string str; + osstream strm(str); + strm << data::scope1() << " (" << data::file() << ":" << line1 << ")->" + << data::scope2() << " (" << data::file() << ":" << line2 << ")"; + BOOST_CHECK(check_formatting(data::full_format(), rec, strm.str())); } // Different delimiter { @@ -197,3 +227,245 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_formatting, CharT, char_types) BOOST_CHECK(equal_strings(strm1.str(), strm2.str())); } } + +BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_posix, CharT, char_types) +{ + typedef attrs::named_scope named_scope; + typedef named_scope::sentry sentry; + typedef attrs::named_scope_list scopes; + typedef attrs::named_scope_entry scope; + + typedef logging::attribute_set attr_set; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef logging::record_view record_view; + typedef logging::basic_formatter< CharT > formatter; + typedef named_scope_test_data< CharT > data; + + named_scope attr; + + // First scope + const unsigned int line1 = __LINE__; + sentry scope1(data::scope1(), data::posix_file(), line1); + + attr_set set1; + set1[data::attr1()] = attr; + + record_view rec = make_record_view(set1); + + // File names without the full path + { + string str; + osstream strm(str); + strm << data::scope1() << " (posix_file.cpp:" << line1 << ")"; + BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str())); + } +} + +#if defined(BOOST_WINDOWS) + +BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_windows, CharT, char_types) +{ + typedef attrs::named_scope named_scope; + typedef named_scope::sentry sentry; + typedef attrs::named_scope_list scopes; + typedef attrs::named_scope_entry scope; + + typedef logging::attribute_set attr_set; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef logging::record_view record_view; + typedef logging::basic_formatter< CharT > formatter; + typedef named_scope_test_data< CharT > data; + + named_scope attr; + + // First scope + const unsigned int line1 = __LINE__; + sentry scope1(data::scope1(), data::windows_file1(), line1); + const unsigned int line2 = __LINE__; + sentry scope2(data::scope2(), data::windows_file2(), line2); + + attr_set set1; + set1[data::attr1()] = attr; + + record_view rec = make_record_view(set1); + + // File names without the full path + { + string str; + osstream strm(str); + strm << data::scope1() << " (windows_file1.cpp:" << line1 << ")->" + << data::scope2() << " (windows_file2.cpp:" << line2 << ")"; + BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str())); + } +} + +#endif // defined(BOOST_WINDOWS) + +// Function name formatting +BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_scope_function_name_formatting, CharT, char_types) +{ + typedef attrs::named_scope named_scope; + typedef named_scope::sentry sentry; + typedef attrs::named_scope_list scopes; + typedef attrs::named_scope_entry scope; + + typedef logging::attribute_set attr_set; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef logging::record_view record_view; + typedef named_scope_test_data< CharT > data; + + named_scope attr; + + // First scope + const unsigned int line1 = __LINE__; + + attr_set set1; + set1[data::attr1()] = attr; + + record_view rec = make_record_view(set1); + + // File names without the full path + { + sentry scope1(data::function_name1(), data::file(), line1); + string str; + osstream strm(str); + strm << "main"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name2(), data::file(), line1); + string str; + osstream strm(str); + strm << "main"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name3(), data::file(), line1); + string str; + osstream strm(str); + strm << "foo"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name4(), data::file(), line1); + string str; + osstream strm(str); + strm << "foo::bar"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name5(), data::file(), line1); + string str; + osstream strm(str); + strm << "namespc::foo::bar"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name6(), data::file(), line1); + string str; + osstream strm(str); + strm << "namespc::foo::bar"; + BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); + } +// { +// sentry scope1(data::function_name7(), data::file(), line1); +// string str; +// osstream strm(str); +// strm << "namespc::foo::bar"; +// BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); +// } +// { +// sentry scope1(data::function_name8(), data::file(), line1); +// string str; +// osstream strm(str); +// strm << "namespc::foo::bar"; +// BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str())); +// } +} + +// Function name without scope formatting +BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_function_name_formatting, CharT, char_types) +{ + typedef attrs::named_scope named_scope; + typedef named_scope::sentry sentry; + typedef attrs::named_scope_list scopes; + typedef attrs::named_scope_entry scope; + + typedef logging::attribute_set attr_set; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef logging::record_view record_view; + typedef named_scope_test_data< CharT > data; + + named_scope attr; + + // First scope + const unsigned int line1 = __LINE__; + + attr_set set1; + set1[data::attr1()] = attr; + + record_view rec = make_record_view(set1); + + // File names without the full path + { + sentry scope1(data::function_name1(), data::file(), line1); + string str; + osstream strm(str); + strm << "main"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name2(), data::file(), line1); + string str; + osstream strm(str); + strm << "main"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name3(), data::file(), line1); + string str; + osstream strm(str); + strm << "foo"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name4(), data::file(), line1); + string str; + osstream strm(str); + strm << "bar"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name5(), data::file(), line1); + string str; + osstream strm(str); + strm << "bar"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } + { + sentry scope1(data::function_name6(), data::file(), line1); + string str; + osstream strm(str); + strm << "bar"; + BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); + } +// { +// sentry scope1(data::function_name7(), data::file(), line1); +// string str; +// osstream strm(str); +// strm << "bar"; +// BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); +// } +// { +// sentry scope1(data::function_name8(), data::file(), line1); +// string str; +// osstream strm(str); +// strm << "bar"; +// BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str())); +// } +} +