diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b85080a7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "files.associations": { + "span": "cpp", + "string": "cpp", + "xstring": "cpp", + "array": "cpp", + "chrono": "cpp", + "filesystem": "cpp", + "format": "cpp", + "forward_list": "cpp", + "initializer_list": "cpp", + "list": "cpp", + "vector": "cpp", + "xhash": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "xtr1common": "cpp" + } +} \ No newline at end of file diff --git a/include/spdlog/details/attr_composer.h b/include/spdlog/details/attr_composer.h new file mode 100644 index 00000000..fff26b12 --- /dev/null +++ b/include/spdlog/details/attr_composer.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include + +namespace spdlog { +namespace detail { + +template +requires std::integral +auto to_string(T const& v, T const& base) -> std::string +{ + // make sure we have enough to cover: negative base 2 + static constexpr std::size_t nbytes = sizeof(T) * 8 + 1 * std::is_signed_v(T); + std::array buf; + auto [p, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), v); + return std::string(buf.data(), std::size_t(p - buf.data())); +} + +inline void scramble(std::string& dst, std::string_view s) +{ + if (s.empty()) + return; + + auto start = s.data(); + auto const end = s.data() + s.size(); + auto cursor = start; + + dst.reserve(dst.size() + s.size()); + + auto replace = [&](std::string_view with) { + dst.append(start, size_t(cursor - start)); + ++cursor; + start = cursor; + dst.append(with); + }; + + while (cursor != end) { + auto c = static_cast(*cursor); + + switch (c) { + case '\b': + replace("\\b"); + break; + case '\f': + replace("\\f"); + break; + case '\n': + replace("\\n"); + break; + case '\r': + replace("\\r"); + break; + case '\t': + replace("\\t"); + break; + case '\\': + replace("\\\\"); + break; + case '"': + replace("\\\""); + break; + default: + if (c <= '\x0f') { + char buf[] = "\\u0000"; + buf[5] += c; + if (c >= '\x0a') + buf[5] += 'a' - ':'; + replace(buf); + } + else if (c <= '\x1f' || c == 0x7f) { + char buf[] = "\\u0010"; + buf[5] += c - 16; + if (c >= '\x1a') + buf[5] += 'a' - ':'; + replace(buf); + } + else + ++cursor; + } + } + if (cursor != start) + dst.append({start, size_t(cursor - start)}); +} + +inline auto compose_prefix(std::string_view k, std::size_t value_bytes) -> std::string +{ + auto dst = std::string{}; + dst.reserve(6 + k.size() + value_bytes); + dst += ','; + dst += '"'; + dst += k; + dst += '"'; + dst += ':'; + dst += '"'; +} + +auto compose(std::string_view k, std::string_view const& v) -> std::string +{ + auto dst = compose_prefix(k, v.size()); + scramble(dst, std::string_view{v}); + dst += '"'; + return dst; +} +inline auto compose(std::string_view k, bool v) -> std::string +{ + auto dst = compose_prefix(k, 4 + !v); + dst += v ? "true\"" : "false\""; + return dst; +} + +template + requires(std::integral || std::floating_point) +auto compose(std::string_view k, T const& v) -> std::string +{ + auto dst = compose_prefix(k, 1); + dst += std::to_string(v); + dst += '"'; + return dst; +} + +template + requires std::integral +auto compose(std::string_view k, T const& v, int base) -> std::string +{ + auto dst = compose_prefix(k, 1); + dst += to_string(v, base); + dst += '"'; + return dst; +} +} +} \ No newline at end of file diff --git a/include/spdlog/details/log_attr.h b/include/spdlog/details/log_attr.h new file mode 100644 index 00000000..f30ab7ec --- /dev/null +++ b/include/spdlog/details/log_attr.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +namespace spdlog { +namespace details { + +//template +//concept composable = std::same_as || std::integral || std::floating_point || std::convertible_to; + +struct attr +{ + std::string key; + std::string value; + +public: + attr(std::string_view k, bool v) + : key{k} + , value{v ? "true" : "false"} + {} + + attr(std::string_view k, std::string_view v) + : key{k} + , value{v} + {} + + template + attr(std::string_view k, T const &v) + : key + , value{std::to_string(v)} + {} +}; + +} // namespace details +} // namespace spdlog \ No newline at end of file diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index fed51abd..f4820494 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -5,6 +5,7 @@ #include #include +#include "log_attr.h" namespace spdlog { namespace details { @@ -28,6 +29,7 @@ struct SPDLOG_API log_msg source_loc source; string_view_t payload; + std::vector attributes; }; } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/log_msg_buffer-inl.h b/include/spdlog/details/log_msg_buffer-inl.h index 21f5ee4d..b4c8a1f4 100644 --- a/include/spdlog/details/log_msg_buffer-inl.h +++ b/include/spdlog/details/log_msg_buffer-inl.h @@ -12,6 +12,7 @@ namespace details { SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) : log_msg{orig_msg} + , attributes{orig_msg.attributes} { buffer.append(logger_name.data(), logger_name.data() + logger_name.size()); buffer.append(payload.data(), payload.data() + payload.size()); @@ -20,13 +21,15 @@ SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) : log_msg{other} + , attributes{orig_msg.attributes} { buffer.append(logger_name.data(), logger_name.data() + logger_name.size()); buffer.append(payload.data(), payload.data() + payload.size()); update_string_views(); } -SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT + : log_msg{other}, buffer{std::move(other.buffer)}, attributes{std::move(other.attributes)} { update_string_views(); } @@ -44,6 +47,7 @@ SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) { log_msg::operator=(other); buffer = std::move(other.buffer); + attributes = std::move(other.attributes); update_string_views(); return *this; }