contextual logger attributes (#2)

* init fixed attribute, currently having issues with the factory

* using the much simpler api already defined: no factory, just define the sinks yourself

* async logger fixed attribute support

* fixed missing fixed attributes in default log calls

* forgot some spots, all cases were found?

* potential fix for illegal vector iterators

* kept up to date with attributes branch

* cleaner fixed logger api

* less function overloads, just add and remove context when needed

* fixed example to use new api

* added append function for nested context

* pushing and popping contexts for nested loggers

* fixed error due to implicit conversion

* fixed sign conversion error

* better attribute example with optional json example

Co-authored-by: Bailey Chittle <baileyc@tessonics.com>
pull/2687/head
Bailey Chittle 3 years ago committed by Bailey Chittle
parent f34970334b
commit 59a4dab260

@ -394,15 +394,33 @@ void replace_default_logger_example()
}
void attribute_example() {
spdlog::default_logger_raw()->warn("EXPERIMENTAL: log with attributes", {{"attribute_key", "attribute value"}});
// logfmt structured logging using attributes
// auto logfmt_logger = spdlog::basic_logger_mt("logfmt_logger", "logs/mylog.txt");
auto logfmt_logger = spdlog::stdout_color_mt("logfmt_logger");
std::string logfmt_pattern = "time=%Y-%m-%dT%H:%M:%S.%f%z name=%n level=%^%l%$ process=%P thread=%t message=\"%v\"%( %K=\"%V\"%)";
logfmt_logger->set_pattern(logfmt_pattern);
logfmt_logger->info("logfmt structured logging", spdlog::attribute_list{{"key\n1", "value\n1"}, {"key\r\n2", "value\r\n2"}});
auto custom_logger = spdlog::stdout_color_mt("custom_logger");
custom_logger->push_context(spdlog::attribute_list{{"attribute_key", "attribute value"}});
custom_logger->warn("EXPERIMENTAL: log with attributes");
custom_logger->clear_context();
// structured logging using attributes
// auto s_logger = spdlog::basic_logger_mt("structured logger", "logs/mylog.txt");
auto s_logger = spdlog::stdout_color_mt("structured logger");
#if 0
std::string json_pattern = "{\"time\":\"%Y-%m-%dT%H:%M:%S.%e%z\",\"name\":\"%n\",\"level\":\"%l\",\"message\":\"%v\"%(,\"%K\":\"%V\"%)}";
s_logger->set_pattern(std::move(json_pattern));
#endif
#if 1
std::string logfmt_pattern = "time=%Y-%m-%dT%H:%M:%S.%f%z name=\"%n\" level=%^%l%$ process=%P thread=%t message=\"%v\"%( %K=\"%V\"%)";
s_logger->set_pattern(std::move(logfmt_pattern));
#endif
s_logger->push_context(spdlog::attribute_list{{"key\n1", "value\n1"}});
s_logger->info("structured logging: test 1");
s_logger->push_context(spdlog::attribute_list{{"key\n2", "value\n2"}});
s_logger->info("structured logging: test 2");
s_logger->pop_context();
s_logger->info("structured logging: test 3");
s_logger->pop_context();
s_logger->info("structured logging: test 4");
s_logger->clear_context();
}

@ -77,6 +77,7 @@ public:
: logger(std::move(name), sinks.begin(), sinks.end())
{}
virtual ~logger() = default;
logger(const logger &other);
@ -84,10 +85,25 @@ public:
logger &operator=(logger other) SPDLOG_NOEXCEPT;
void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
template <typename T>
void log(level::level_enum lvl, const T &msg, attribute_list attrs)
{
log(source_loc{}, lvl, msg, attrs);
void push_context(attribute_list attrs) {
attributes.insert(attributes.end(), attrs.begin(), attrs.end());
attr_stack.push_back(static_cast<long>(attributes.size()));
}
void pop_context() {
if (attr_stack.size() > 1) {
attributes.erase(attributes.begin() + attr_stack[attr_stack.size() - 2], attributes.begin() + attr_stack[attr_stack.size() - 1]);
attr_stack.pop_back();
} else {
// is first element in stack, or empty. Delete the whole thing.
clear_context();
}
}
// removes context on loggers by clearing the attribute list
void clear_context() {
attributes.clear();
attr_stack.clear();
}
template<typename... Args>
@ -125,23 +141,10 @@ public:
}
details::log_msg log_msg(log_time, loc, name_, lvl, msg);
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
void log(source_loc loc, level::level_enum lvl, string_view_t msg, attribute_list attrs)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
details::log_msg log_msg(loc, name_, lvl, msg);
// log_msg.attributes.push_back(attrs);
log_msg.attributes.insert(log_msg.attributes.end(), attrs.begin(), attrs.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
void log(source_loc loc, level::level_enum lvl, string_view_t msg)
{
bool log_enabled = should_log(lvl);
@ -152,6 +155,7 @@ public:
}
details::log_msg log_msg(loc, name_, lvl, msg);
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
@ -221,6 +225,7 @@ public:
memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
@ -236,6 +241,7 @@ public:
memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
@ -281,43 +287,6 @@ public:
}
#endif
// attributes endpoint
template<typename T>
void trace(const T &msg, attribute_list attrs)
{
log(level::trace, msg, attrs);
}
template<typename T>
void debug(const T &msg, attribute_list attrs)
{
log(level::debug, msg, attrs);
}
template<typename T>
void info(const T &msg, attribute_list attrs)
{
log(level::info, msg, attrs);
}
template<typename T>
void warn(const T &msg, attribute_list attrs)
{
log(level::warn, msg, attrs);
}
template<typename T>
void error(const T &msg, attribute_list attrs)
{
log(level::err, msg, attrs);
}
template<typename T>
void critical(const T &msg, attribute_list attrs)
{
log(level::critical, msg, attrs);
}
// default endpoint
template<typename T>
void trace(const T &msg)
@ -413,6 +382,9 @@ protected:
err_handler custom_err_handler_{nullptr};
details::backtracer tracer_;
attribute_list attributes;
std::vector<long> attr_stack; // used to push/pop nested contexts
// common implementation for after templated public api has been resolved
template<typename... Args>
void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&... args)
@ -433,6 +405,7 @@ protected:
#endif
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_it_(log_msg, log_enabled, traceback_enabled);
}
SPDLOG_LOGGER_CATCH(loc)
@ -458,7 +431,8 @@ protected:
memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
log_msg.attributes.insert(log_msg.attributes.end(), attributes.begin(), attributes.end());
log_og_msg, log_enabled, traceback_enabled);
}
SPDLOG_LOGGER_CATCH(loc)
}

@ -1145,8 +1145,8 @@ SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory
f->format(msg, cached_tm_, dest);
}
} else {
// ugly formatter iterator, due to needing to go back to previous iterators to repeat kv pairs
auto it_end = formatters_.begin();
// ugly formatter iterator, due to needing to go back to previous iterators to repeat kv pairs
for (auto it = formatters_.begin(); it != formatters_.end(); ++it)
{
if ((*it)->flag_ == details::attr_flags::start) {

Loading…
Cancel
Save