userver: userver/logging/impl/tag_writer.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
tag_writer.hpp
1#pragma once
2
3#include <string_view>
4#include <type_traits>
5
6#include <userver/compiler/impl/constexpr.hpp>
7#include <userver/logging/log_extra.hpp>
8#include <userver/logging/log_helper.hpp>
9#include <userver/utils/encoding/tskv.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace logging::impl {
14
15[[noreturn]] void ThrowInvalidEscapedTagKey(std::string_view key);
16
17class TagKey final {
18 public:
19 template <typename StringType, typename Enabled = std::enable_if_t<
20 !std::is_same_v<StringType, TagKey>>>
21 USERVER_IMPL_CONSTEVAL /*implicit*/ TagKey(const StringType& escaped_key);
22
23 std::string_view GetEscapedKey() const noexcept;
24
25 private:
26 std::string_view escaped_key_;
27};
28
29class RuntimeTagKey final {
30 public:
31 explicit RuntimeTagKey(std::string_view unescaped_key);
32
33 std::string_view GetUnescapedKey() const noexcept;
34
35 private:
36 std::string_view unescaped_key_;
37};
38
39// Allows to add tags directly to the logged message, bypassing LogExtra.
40class TagWriter {
41 public:
42 template <typename T>
43 void PutTag(TagKey key, const T& value);
44
45 template <typename T>
46 void PutTag(RuntimeTagKey key, const T& value);
47
48 // The tags must not be duplicated in other Put* calls.
49 void PutLogExtra(const LogExtra& extra);
50
51 // Copies the tags to the internal LogExtra. They will be deduplicated
52 // automatically.
53 void ExtendLogExtra(const LogExtra& extra);
54
55 private:
56 friend class logging::LogHelper;
57
58 explicit TagWriter(LogHelper& lh) noexcept;
59
60 void PutKey(TagKey key);
61 void PutKey(RuntimeTagKey key);
62
63 void MarkValueEnd() noexcept;
64
65 LogHelper& lh_;
66};
67
68constexpr bool DoesTagNeedEscaping(std::string_view key) noexcept {
69 for (const char c : key) {
70 const bool needs_no_escaping_in_all_formats =
71 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
72 (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '/';
73 if (!needs_no_escaping_in_all_formats) {
74 return true;
75 }
76 }
77 return false;
78}
79
80template <typename StringType, typename Enabled>
81USERVER_IMPL_CONSTEVAL TagKey::TagKey(const StringType& escaped_key)
82 : escaped_key_(escaped_key) {
83 if (DoesTagNeedEscaping(escaped_key_)) {
84 ThrowInvalidEscapedTagKey(escaped_key_);
85 }
86}
87
88template <typename T>
89void TagWriter::PutTag(TagKey key, const T& value) {
90 PutKey(key);
91 lh_ << value;
92 MarkValueEnd();
93}
94
95template <typename T>
96void TagWriter::PutTag(RuntimeTagKey key, const T& value) {
97 PutKey(key);
98 lh_ << value;
99 MarkValueEnd();
100}
101
102} // namespace logging::impl
103
104USERVER_NAMESPACE_END