Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extra attributes for log_msg #2595

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
aa4e4c9
experimenting with attributes
adnsv Dec 6, 2022
9ab32d7
some bug fixes to attribute fork to get compilation working
bachittle Dec 21, 2022
0ca869e
attributes passed to root API
bachittle Dec 22, 2022
1eec41f
forgot the things
bachittle Dec 22, 2022
301ab18
formats log messages (at least for default)
bachittle Dec 22, 2022
07abdc6
more cleanup of unneeded code, needed to revert cmake standard to get…
bachittle Dec 22, 2022
6c16b6c
attribute example for testing purposes
bachittle Dec 22, 2022
98958cf
attributes can simulate structured logging, show example. Now works w…
bachittle Dec 22, 2022
2d79f7a
multiple kv pairs can be passed via initializer list
bachittle Dec 22, 2022
be5cc44
fixed bugs with default formatting
bachittle Dec 22, 2022
882cee1
scrambling key and value to escape ascii codes
bachittle Dec 22, 2022
f5bde10
Merge remote-tracking branch 'origin/v1.x' into attributes
bachittle Jan 3, 2023
b33301d
more well-defined definition of list instantiation using a pre-define…
bachittle Jan 4, 2023
8516010
C++11 backwards compat fixes by replacing std::string_view with built…
bachittle Jan 5, 2023
d864706
more endpoints, removed commas from logfmt
bachittle Jan 5, 2023
59da466
code breaks when fmt is external, so am using fmts implementation only
bachittle Jan 10, 2023
8f2d273
fixed errors caused by -Werror=conversion
bachittle Jan 10, 2023
7883014
experimenting with attribute formatting
bachittle Jan 11, 2023
7f24394
actually for sure fixed the -Werror=conversion, for the specific vers…
bachittle Jan 11, 2023
be3e571
another pedantic error in ci
bachittle Jan 11, 2023
785c3a5
custom pattern formatting is now functional
bachittle Jan 11, 2023
cbdcb3e
Merge branch 'attributes' into attr_format
bachittle Jan 11, 2023
3aba11d
fixed reordering error
bachittle Jan 11, 2023
82e4553
changed switch statement due to an interesting bug I found
bachittle Jan 11, 2023
3383207
default kv pairs
bachittle Jan 11, 2023
0b48d79
fixed example to include new pattern formatting
bachittle Jan 11, 2023
26a04ad
Merge pull request #1 from bachittle/attr_format
bachittle Jan 12, 2023
e7c2186
keep old range-based for loop for non-attribute code
bachittle Jan 12, 2023
d6d4c65
contextual logger attributes (#2)
bachittle Jan 12, 2023
71d2e3d
broke the utf8 code by accident
bachittle Jan 12, 2023
d6ed2f2
global contextual logger support
bachittle Jan 13, 2023
47076c9
Merge branch 'v1.x' into attributes
bachittle Jan 16, 2023
6097b84
Merge branch 'v1.x' into attributes
bachittle Jan 16, 2023
d1b28bf
attribute testing (#3)
bachittle Jan 17, 2023
7aa0ced
exception safety tests
bachittle Jan 30, 2023
7b92a6c
Merge branch 'v1.x' into p_attributes
bachittle Feb 17, 2023
6af7ea2
setting the cmake standard to 20 when using std format
bachittle Mar 21, 2023
0367289
separate std string view from std format
bachittle Mar 24, 2023
e1afb67
Merge branch 'v1.x' into seperate_std_string_view
bachittle Mar 24, 2023
96d28af
set string_view option instead of error for compat
bachittle Mar 24, 2023
fffa350
Merge branch 'seperate_std_string_view' into attributes
bachittle Mar 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ cmake-build-*/
*.user
*.sln

# vscode
.vscode

# macos
*.DS_store
*.xcodeproj/
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ endif()
# ---------------------------------------------------------------------------------------
# Compiler config
# ---------------------------------------------------------------------------------------
if(SPDLOG_USE_STD_FORMAT)
if(SPDLOG_USE_STD_FORMAT OR SPDLOG_USE_STD_STRING_VIEW)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
elseif(NOT CMAKE_CXX_STANDARD)
Expand Down Expand Up @@ -88,6 +88,7 @@ option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)
option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF)
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF)
option(SPDLOG_USE_STD_STRING_VIEW "Use std::string_view instead of the fmt implementation of string_view." OFF)
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
Expand All @@ -104,6 +105,11 @@ if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL)
message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive")
endif()

if(SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_USE_STD_STRING_VIEW)
# message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT requires SPDLOG_USE_STD_STRING_VIEW")
set(SPDLOG_USE_STD_STRING_VIEW ON CACHE BOOL "" FORCE) # automatically set SPDLOG_USE_STD_STRING_VIEW instead of error
endif()

# misc tweakme options
if(WIN32)
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
Expand Down Expand Up @@ -248,6 +254,7 @@ foreach(
SPDLOG_NO_TLS
SPDLOG_NO_ATOMIC_LEVELS
SPDLOG_DISABLE_DEFAULT_LOGGER
SPDLOG_USE_STD_STRING_VIEW
SPDLOG_USE_STD_FORMAT)
if(${SPDLOG_OPTION})
target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION})
Expand Down
35 changes: 34 additions & 1 deletion example/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ void custom_flags_example();
void file_events_example();
void replace_default_logger_example();

void attribute_example();

#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // support for loading levels from the environment variable
#include "spdlog/fmt/ostr.h" // support for user defined types
Expand Down Expand Up @@ -86,6 +88,7 @@ int main(int, char *[])
custom_flags_example();
file_events_example();
replace_default_logger_example();
attribute_example();

// Flush all *registered* loggers using a worker thread every 3 seconds.
// note: registered loggers *must* be thread safe for this to work correctly!
Expand Down Expand Up @@ -279,7 +282,7 @@ struct fmt::formatter<my_type> : fmt::formatter<std::string>
{
auto format(my_type my, format_context &ctx) -> decltype(ctx.out())
{
return format_to(ctx.out(), "[my_type i={}]", my.i);
return fmt::format_to(ctx.out(), "[my_type i={}]", my.i);
}
};

Expand Down Expand Up @@ -389,3 +392,33 @@ void replace_default_logger_example()

spdlog::set_default_logger(old_logger);
}

void attribute_example() {
spdlog::push_context(spdlog::attribute_list{{"attribute_key", "attribute value"}});
spdlog::warn("EXPERIMENTAL: log with attributes");
spdlog::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();
}
17 changes: 14 additions & 3 deletions include/spdlog/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,15 @@ using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
#ifdef SPDLOG_USE_STD_STRING_VIEW
using string_view_t = std::string_view;
#else
using string_view_t = fmt::basic_string_view<char>;
#endif

#ifdef SPDLOG_USE_STD_FORMAT
namespace fmt_lib = std;

using string_view_t = std::string_view;
using memory_buf_t = std::string;

template<typename... Args>
Expand Down Expand Up @@ -164,7 +169,6 @@ using wformat_string_t = std::wstring_view;
#else // use fmt lib instead of std::format
namespace fmt_lib = fmt;

using string_view_t = fmt::basic_string_view<char>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;

template<typename... Args>
Expand Down Expand Up @@ -360,7 +364,7 @@ SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view
}
#endif

#ifndef SPDLOG_USE_STD_FORMAT
#if !defined(SPDLOG_USE_STD_STRING_VIEW) && !defined(SPDLOG_USE_STD_FORMAT)
template<typename T, typename... Args>
inline fmt::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt)
{
Expand All @@ -372,6 +376,13 @@ SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(std::basic_format
{
return fmt.get();
}
#elif defined(SPDLOG_USE_STD_STRING_VIEW) && !defined(SPDLOG_USE_STD_FORMAT)
template<typename T, typename... Args>
SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt) SPDLOG_NOEXCEPT
{
auto tmp = fmt::basic_string_view<T>{fmt};
return std::string_view{tmp.data(), tmp.size()};
}
#endif

// make_unique support for pre c++14
Expand Down
77 changes: 77 additions & 0 deletions include/spdlog/details/attr_composer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include <string>
#include <spdlog/common.h>

namespace spdlog {
namespace details {

inline void scramble(std::string& dst, string_view_t s)
{
if (s.size() == 0)
return;

auto start = s.data();
auto const end = s.data() + s.size();
auto cursor = start;

dst.reserve(dst.size() + s.size());

auto replace = [&](string_view_t with) {
dst.append(start, size_t(cursor - start));
++cursor;
start = cursor;
// dst.append(with);
dst.append(with.data(), with.size());
};

while (cursor != end) {
auto c = static_cast<unsigned char>(*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] = (char)(buf[5] + c);
if (c >= '\x0a')
buf[5] = (char)(buf[5] + ('a' - ':'));
replace(buf);
}
else if (c <= '\x1f' || c == 0x7f) {
char buf[] = "\\u0010";
buf[5] = (char)(buf[5] + (c - 16));
if (c >= '\x1a')
buf[5] = (char)(buf[5] + ('a' - ':'));
replace(buf);
}
else
++cursor;
}
}
if (cursor != start)
dst.append({start, size_t(cursor - start)});
}

}
}
53 changes: 53 additions & 0 deletions include/spdlog/details/log_attr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <string>
#include <vector>
#include "attr_composer.h"
#include <spdlog/common.h>

namespace spdlog {
namespace details {

//template<typename T>
//concept composable = std::same_as<T, bool> || std::integral<T> || std::floating_point<T> || std::convertible_to<T, std::string_view>;

struct attr
{
std::string key;
std::string value;

public:
attr(std::initializer_list<string_view_t> l) {
if (l.size() != 2) return; // throw exception if not kv pair?

scramble(key, *l.begin());
scramble(value, *(l.begin()+1));
}

attr(string_view_t k, bool v)
: value{v ? "true" : "false"}
{
key = std::string{k.data(), k.size()};
}

attr(string_view_t k, string_view_t v)
{
key = std::string{k.data(), k.size()};
value = std::string{v.data(), v.size()};
}

attr(std::string k, std::string v) : key{k}, value{v} {}

template <typename T>
attr(string_view_t k, T const &v)
: value{std::to_string(v)}
{
key = std::string{k.data(), k.size()};
}
};

} // namespace details

using attribute_list = std::vector<details::attr>;

} // namespace spdlog
2 changes: 2 additions & 0 deletions include/spdlog/details/log_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <spdlog/common.h>
#include <string>
#include "log_attr.h"

namespace spdlog {
namespace details {
Expand All @@ -28,6 +29,7 @@ struct SPDLOG_API log_msg

source_loc source;
string_view_t payload;
attribute_list attributes;
};
} // namespace details
} // namespace spdlog
Expand Down
11 changes: 6 additions & 5 deletions include/spdlog/details/log_msg_buffer-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ namespace details {
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
: log_msg{orig_msg}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
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(const log_msg_buffer &other)
: log_msg{other}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
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)}
{
update_string_views();
}
Expand Down
Loading