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

Custom fields #374

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- [v3.5.0](#v350)
- [v3.4.1](#v341)
- [v3.4.0](#v340)
- [v3.3.1](#v331)
Expand Down Expand Up @@ -52,6 +53,15 @@
- [v1.1.0](#v110)
- [v1.0.0](#v100)

## v3.5.0

- Fixed `LOG_TRACE_CFORMAT` macros.
- Added support for compile-time custom tags in `quill::MacroMetadata` to enhance message filtering and incorporate
static information. New log macros suffixed with `_WITH_TAGS` introduced for this feature.
Additionally, `%(custom_tags)` parameter added
to `PatternFormatter`. ([#349](https://github.com/odygrd/quill/issues/349))
See [example_custom_tags.cpp](https://github.com/odygrd/quill/blob/master/examples/example_custom_tags.cpp)

## v3.4.1

- Reduce backend worker unnecessary allocation. ([#368](https://github.com/odygrd/quill/issues/368))
Expand Down
6 changes: 5 additions & 1 deletion benchmarks/hot_path_latency/hot_path_bench.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
#include <random>
#include <thread>

#include <x86intrin.h>
#if defined(_WIN32)
#include <intrin.h>
#else
#include <x86intrin.h>
#endif

// Instead of sleep
inline void wait(std::chrono::nanoseconds min, std::chrono::nanoseconds max)
Expand Down
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ target_link_libraries(quill_example_custom_formatter_thread_name quill)
add_executable(quill_example_custom_handler example_custom_handler.cpp)
target_link_libraries(quill_example_custom_handler quill)

add_executable(quill_example_custom_tags example_custom_tags.cpp)
target_link_libraries(quill_example_custom_tags quill)

add_executable(quill_example_daily_file_rotation example_daily_file_rotation.cpp)
target_link_libraries(quill_example_daily_file_rotation quill)

Expand Down
53 changes: 53 additions & 0 deletions examples/example_custom_tags.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "quill/Quill.h"

#include <chrono>
#include <thread>

// Define a CustomTags class
class MyCustomTags : public quill::CustomTags
{
public:
constexpr MyCustomTags(char const* tag_a, uint32_t tag_b) : _tag_a(tag_a), _tag_b(tag_b) {}

void format(std::string& out) const override { out = fmtquill::format("{}:{}", _tag_a, _tag_b); }

private:
char const* _tag_a;
uint32_t _tag_b;
};

static constexpr MyCustomTags custom_tags_a{"CUSTOM_TAG_12", 12};
static constexpr MyCustomTags custom_tags_b{"CUSTOM_TAG_23", 23};

int main()
{
// Set a custom formatter for stdout that prints the tags
std::shared_ptr<quill::Handler> stdout_handler = quill::stdout_handler();

stdout_handler->set_pattern(
"%(ascii_time) [%(thread)] %(fileline:<28) %(level_name) %(logger_name:<16) - [%(custom_tags)] "
"%(message)", // format
"%Y-%m-%d %H:%M:%S.%Qms", // timestamp format
quill::Timezone::GmtTime); // timestamp's timezone

// Register the handler as default
quill::Config cfg;
cfg.default_handlers.emplace_back(stdout_handler);

// Apply the configuration
quill::configure(cfg);
quill::start();

quill::Logger* logger = quill::get_logger();
logger->set_log_level(quill::LogLevel::TraceL3);

LOG_TRACE_L3_WITH_TAGS(logger, custom_tags_a, "TraceL3 with custom tags");
LOG_TRACE_L2_WITH_TAGS(logger, custom_tags_b, "TraceL2 with custom tags");
LOG_TRACE_L1_WITH_TAGS(logger, custom_tags_b, "TraceL1 with custom tags");
LOG_DEBUG_WITH_TAGS(logger, custom_tags_a, "Debug with custom tags");
LOG_INFO_WITH_TAGS(logger, custom_tags_a, "Info with custom tags");
LOG_WARNING_WITH_TAGS(logger, custom_tags_b, "Warning with custom tags");
LOG_ERROR_WITH_TAGS(logger, custom_tags_a, "Error with custom tags");
LOG_CRITICAL_WITH_TAGS(logger, custom_tags_b, "Critical with custom tags");
LOG_CRITICAL(logger, "Critical without custom tags");
}
4 changes: 2 additions & 2 deletions examples/example_trivial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ int main()
char_arrays.mid_0);

// Using a dynamic runtime log level
std::array<quill::LogLevel, 4> const runtime_log_levels = {
std::array<quill::LogLevel, 4> constexpr runtime_log_levels = {
quill::LogLevel::Debug, quill::LogLevel::Info, quill::LogLevel::Warning, quill::LogLevel::Error};

for (auto const& log_level : runtime_log_levels)
Expand Down Expand Up @@ -123,7 +123,7 @@ int main()
LOG_CRITICAL(logger_1, "This is never logged");

// Get all created loggers
std::unordered_map<std::string, quill::Logger*> created_loggers = quill::get_all_loggers();
std::unordered_map<std::string, quill::Logger*> const created_loggers = quill::get_all_loggers();
std::vector<std::string> logger_names;
for (auto const& elem : created_loggers)
{
Expand Down
2 changes: 2 additions & 0 deletions quill/include/quill/Clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/

#pragma once

#include "quill/detail/LogManager.h"
#include "quill/detail/misc/Attributes.h"
#include "quill/detail/misc/Rdtsc.h"
Expand Down
32 changes: 16 additions & 16 deletions quill/include/quill/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
* fundamental types.
* This is the fastest way possible to log
* @note This function is thread-safe.
* @param dynamic_log_level dynamic log level
* @param format_string format
* @param fmt_args arguments
*/
Expand Down Expand Up @@ -179,10 +180,10 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
size_t total_size = sizeof(detail::Header) + alignof(detail::Header) +
detail::get_args_sizes<0>(c_string_sizes, fmt_args...);

if constexpr (macro_metadata.level() == quill::LogLevel::Dynamic)
if constexpr (macro_metadata.level() == LogLevel::Dynamic)
{
// For the dynamic log level we want to add to the total size to store the dynamic log level
total_size += sizeof(quill::LogLevel);
total_size += sizeof(LogLevel);
}

// request this size from the queue
Expand Down Expand Up @@ -231,15 +232,15 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
// look up their types to deserialize them

// Note: The metadata variable here is created during program init time,
std::byte* const write_begin = write_buffer;
std::byte const* const write_begin = write_buffer;
write_buffer = detail::align_pointer<alignof(detail::Header), std::byte>(write_buffer);

constexpr bool is_printf_format = macro_metadata.is_printf_format();

new (write_buffer) detail::Header(
detail::get_metadata_and_format_fn<is_printf_format, TMacroMetadata, FmtArgs...>,
std::addressof(_logger_details),
(_logger_details.timestamp_clock_type() == TimestampClockType::Tsc) ? quill::detail::rdtsc()
(_logger_details.timestamp_clock_type() == TimestampClockType::Tsc) ? detail::rdtsc()
: (_logger_details.timestamp_clock_type() == TimestampClockType::System)
? static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch())
Expand All @@ -251,11 +252,11 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
// encode remaining arguments
write_buffer = detail::encode_args<0>(c_string_sizes, write_buffer, std::forward<FmtArgs>(fmt_args)...);

if constexpr (macro_metadata.level() == quill::LogLevel::Dynamic)
if constexpr (macro_metadata.level() == LogLevel::Dynamic)
{
// write the dynamic log level
std::memcpy(write_buffer, &dynamic_log_level, sizeof(quill::LogLevel));
write_buffer += sizeof(quill::LogLevel);
std::memcpy(write_buffer, &dynamic_log_level, sizeof(LogLevel));
write_buffer += sizeof(LogLevel);
}

assert(total_size >= (static_cast<uint32_t>(write_buffer - write_begin)) &&
Expand All @@ -281,17 +282,16 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
// we do not care about the other fields, except quill::MacroMetadata::Event::InitBacktrace
struct
{
constexpr quill::MacroMetadata operator()() const noexcept
constexpr MacroMetadata operator()() const noexcept
{
return quill::MacroMetadata{
"", "", "", "", "{}", LogLevel::Critical, quill::MacroMetadata::Event::InitBacktrace,
return MacroMetadata{
"", "", "", "", "{}", nullptr, LogLevel::Critical, MacroMetadata::Event::InitBacktrace,
false, false};
}
} anonymous_log_message_info;

// we pass this message to the queue and also pass capacity as arg
this->template log<decltype(anonymous_log_message_info)>(quill::LogLevel::None,
QUILL_FMT_STRING("{}"), capacity);
this->template log<decltype(anonymous_log_message_info)>(LogLevel::None, QUILL_FMT_STRING("{}"), capacity);

// Also store the desired flush log level
_logger_details.set_backtrace_flush_level(backtrace_flush_level);
Expand All @@ -308,16 +308,16 @@ class alignas(detail::CACHE_LINE_ALIGNED) Logger
// we do not care about the other fields, except quill::MacroMetadata::Event::Flush
struct
{
constexpr quill::MacroMetadata operator()() const noexcept
constexpr MacroMetadata operator()() const noexcept
{
return quill::MacroMetadata{
"", "", "", "", "", LogLevel::Critical, quill::MacroMetadata::Event::FlushBacktrace,
return MacroMetadata{
"", "", "", "", "", nullptr, LogLevel::Critical, MacroMetadata::Event::FlushBacktrace,
false, false};
}
} anonymous_log_message_info;

// we pass this message to the queue
this->template log<decltype(anonymous_log_message_info)>(quill::LogLevel::None, QUILL_FMT_STRING(""));
this->template log<decltype(anonymous_log_message_info)>(LogLevel::None, QUILL_FMT_STRING(""));
}

private:
Expand Down
20 changes: 15 additions & 5 deletions quill/include/quill/MacroMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ class MacroMetadata
};

constexpr MacroMetadata(std::string_view lineno, std::string_view pathname, std::string_view fileline,
std::string_view func, std::string_view message_format, LogLevel level,
Event event, bool is_structured_log_template, bool is_printf_format)
std::string_view func, std::string_view message_format,
CustomTags const* custom_tags, LogLevel level, Event event,
bool is_structured_log_template, bool is_printf_format)
: _func(func),
_pathname(pathname),
_filename(_extract_source_file_name(_pathname)),
_fileline(_extract_source_file_name(fileline)),
_message_format(message_format),
_lineno(lineno),
_custom_tags(custom_tags),
_level(level),
_event(event),
_is_structured_log_template(is_structured_log_template),
Expand All @@ -46,13 +48,15 @@ class MacroMetadata

#if defined(_WIN32)
constexpr MacroMetadata(std::string_view lineno, std::string_view pathname, std::string_view fileline,
std::string_view func, std::wstring_view message_format, LogLevel level,
Event event, bool is_structured_log_template, bool is_printf_format)
std::string_view func, std::wstring_view message_format,
CustomTags const* custom_tags, LogLevel level, Event event,
bool is_structured_log_template, bool is_printf_format)
: _func(func),
_pathname(pathname),
_filename(_extract_source_file_name(_pathname)),
_fileline(_extract_source_file_name(fileline)),
_lineno(lineno),
_custom_tags(custom_tags),
_level(level),
_event(event),
_is_structured_log_template(is_structured_log_template),
Expand Down Expand Up @@ -87,7 +91,7 @@ class MacroMetadata
return _filename;
}

/**
/**
* @return file:line
*/
QUILL_NODISCARD_ALWAYS_INLINE_HOT constexpr std::string_view fileline() const noexcept
Expand Down Expand Up @@ -124,6 +128,11 @@ class MacroMetadata
return loglevel_to_string_id(_level);
}

QUILL_NODISCARD_ALWAYS_INLINE_HOT constexpr CustomTags const* custom_tags() const noexcept
{
return _custom_tags;
}

QUILL_NODISCARD_ALWAYS_INLINE_HOT constexpr Event event() const noexcept { return _event; }

QUILL_NODISCARD_ALWAYS_INLINE_HOT constexpr bool is_structured_log_template() const noexcept
Expand Down Expand Up @@ -177,6 +186,7 @@ class MacroMetadata
std::string_view _fileline;
std::string_view _message_format;
std::string_view _lineno;
CustomTags const* _custom_tags{nullptr};
LogLevel _level{LogLevel::None};
Event _event{Event::Log};
bool _is_structured_log_template{false};
Expand Down
3 changes: 3 additions & 0 deletions quill/include/quill/PatternFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class PatternFormatter
Process,
FileLine,
Message,
CustomTags,
ATTR_NR_ITEMS
};

Expand Down Expand Up @@ -121,6 +122,7 @@ class PatternFormatter
* %(thread) - Thread ID
* %(thread_name) - Thread Name if set
* %(process) - Process ID
* %(custom_tags) - Appends custom tags to the message when _WITH_TAGS macros are used.
*
* @throws on invalid format string
*/
Expand All @@ -145,6 +147,7 @@ class PatternFormatter

private:
std::string _format;
std::string _custom_tags;
/** Each named argument in the format_pattern is mapped in order to this array **/
std::array<size_t, Attribute::ATTR_NR_ITEMS> _order_index{};
std::array<fmtquill::basic_format_arg<fmtquill::format_context>, Attribute::ATTR_NR_ITEMS> _args{};
Expand Down
6 changes: 3 additions & 3 deletions quill/include/quill/Quill.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ namespace quill

/** Version Info **/
constexpr uint32_t VersionMajor{3};
constexpr uint32_t VersionMinor{4};
constexpr uint32_t VersionPatch{1};
constexpr uint32_t VersionMinor{5};
constexpr uint32_t VersionPatch{0};
constexpr uint32_t Version{VersionMajor * 10000 + VersionMinor * 100 + VersionPatch};

/** forward declarations **/
Expand Down Expand Up @@ -101,7 +101,7 @@ QUILL_ATTRIBUTE_COLD inline void start(bool with_signal_handler = false,
QUILL_ATTRIBUTE_COLD inline void init_signal_handler(std::initializer_list<int> catchable_signals = {
SIGTERM, SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV})
{
quill::detail::init_signal_handler(catchable_signals);
detail::init_signal_handler(catchable_signals);
}
#endif

Expand Down
10 changes: 4 additions & 6 deletions quill/include/quill/detail/HandlerCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ class HandlerCollection
{
return handler;
}
else
{

// recreate this handler
if constexpr (std::is_base_of<StreamHandler, THandler>::value)
if constexpr (std::is_base_of_v<StreamHandler, THandler>)
{
handler = std::make_shared<THandler>(handler_name, std::forward<Args>(args)...);
}
Expand All @@ -92,12 +91,11 @@ class HandlerCollection

search->second = handler;
return handler;
}
}

// if first time add it
std::shared_ptr<Handler> handler;
if constexpr (std::is_base_of<StreamHandler, THandler>::value)
if constexpr (std::is_base_of_v<StreamHandler, THandler>)
{
handler = std::make_shared<THandler>(handler_name, std::forward<Args>(args)...);
}
Expand All @@ -116,7 +114,7 @@ class HandlerCollection
* @throws std::runtime_error if the handler does not exist
* @return a shared_ptr to the handler
*/
QUILL_NODISCARD QUILL_ATTRIBUTE_COLD std::shared_ptr<Handler> get_handler(std::string const& handler_name);
QUILL_NODISCARD QUILL_ATTRIBUTE_COLD std::shared_ptr<Handler> get_handler(std::string const& handler_name) const;

/**
* Subscribe a handler to the vector of active handlers so that the backend thread can see it
Expand Down
Loading