userver: userver/logging/impl/tag_writer.hpp Source File
Loading...
Searching...
No Matches
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