LogIt++
Header-only, macro-first C++ logging library
Loading...
Searching...
No Matches
LogContext.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_DETAIL_LOGCONTEXT_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_DETAIL_LOGCONTEXT_HPP_INCLUDED
4
7
8#include <map>
9#include <memory>
10#include <string>
11#include <vector>
12
13#ifndef LOGIT_HAS_FEATURE
14#if defined(__has_feature)
15#define LOGIT_HAS_FEATURE(x) __has_feature(x)
16#else
17#define LOGIT_HAS_FEATURE(x) 0
18#endif
19#endif
20
21#ifndef LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
22#if defined(__SANITIZE_ADDRESS__) || LOGIT_HAS_FEATURE(address_sanitizer)
23#define LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS 0
24#else
25#define LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS 1
26#endif
27#endif
28
29namespace logit {
30
31#ifdef LOGIT_WITH_CONTEXT
32
35 struct LogContextSnapshot {
36 std::map<std::string, std::string> mdc;
37 std::vector<std::string> ndc;
38 };
39
40 namespace detail {
41
42# if LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
43
44 inline std::map<std::string, std::string>*& mdc_map_storage() {
45 static thread_local std::map<std::string, std::string>* instance = nullptr;
46 return instance;
47 }
48
49 inline std::vector<std::string>*& ndc_stack_storage() {
50 static thread_local std::vector<std::string>* instance = nullptr;
51 return instance;
52 }
53
54# else
55
56 inline std::unique_ptr<std::map<std::string, std::string> >& mdc_map_storage() {
57 static thread_local std::unique_ptr<std::map<std::string, std::string> > instance;
58 return instance;
59 }
60
61 inline std::unique_ptr<std::vector<std::string> >& ndc_stack_storage() {
62 static thread_local std::unique_ptr<std::vector<std::string> > instance;
63 return instance;
64 }
65
66# endif
67
68 inline std::map<std::string, std::string>& mutable_mdc_map() {
69# if LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
70 if (!mdc_map_storage()) {
71 mdc_map_storage() = new std::map<std::string, std::string>();
72 }
73 return *mdc_map_storage();
74# else
75 if (!mdc_map_storage()) {
76 mdc_map_storage().reset(new std::map<std::string, std::string>());
77 }
78 return *mdc_map_storage();
79# endif
80 }
81
82 inline std::vector<std::string>& mutable_ndc_stack() {
83# if LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
84 if (!ndc_stack_storage()) {
85 ndc_stack_storage() = new std::vector<std::string>();
86 }
87 return *ndc_stack_storage();
88# else
89 if (!ndc_stack_storage()) {
90 ndc_stack_storage().reset(new std::vector<std::string>());
91 }
92 return *ndc_stack_storage();
93# endif
94 }
95
96 inline const std::map<std::string, std::string>* mdc_map_if_exists() {
97# if LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
98 return mdc_map_storage();
99# else
100 return mdc_map_storage().get();
101# endif
102 }
103
104 inline const std::vector<std::string>* ndc_stack_if_exists() {
105# if LOGIT_DISABLE_THREAD_LOCAL_DESTRUCTORS
106 return ndc_stack_storage();
107# else
108 return ndc_stack_storage().get();
109# endif
110 }
111
112 } // namespace detail
113
115 inline void mdc_put(const std::string& key, const std::string& value) {
116 detail::mutable_mdc_map()[key] = value;
117 }
118
120 inline void mdc_remove(const std::string& key) {
121 std::map<std::string, std::string>* values =
122 const_cast<std::map<std::string, std::string>*>(detail::mdc_map_if_exists());
123 if (values != nullptr) {
124 values->erase(key);
125 }
126 }
127
129 inline void mdc_clear() {
130 std::map<std::string, std::string>* values =
131 const_cast<std::map<std::string, std::string>*>(detail::mdc_map_if_exists());
132 if (values != nullptr) {
133 values->clear();
134 }
135 }
136
138 inline void ndc_push(const std::string& message) {
139 detail::mutable_ndc_stack().push_back(message);
140 }
141
143 inline void ndc_pop() {
144 std::vector<std::string>* stack =
145 const_cast<std::vector<std::string>*>(detail::ndc_stack_if_exists());
146 if (stack != nullptr && !stack->empty()) {
147 stack->pop_back();
148 }
149 }
150
152 inline void ndc_clear() {
153 std::vector<std::string>* stack =
154 const_cast<std::vector<std::string>*>(detail::ndc_stack_if_exists());
155 if (stack != nullptr) {
156 stack->clear();
157 }
158 }
159
161 inline std::shared_ptr<const LogContextSnapshot> capture_log_context() {
162 const std::map<std::string, std::string>* mdc = detail::mdc_map_if_exists();
163 const std::vector<std::string>* ndc = detail::ndc_stack_if_exists();
164 if ((mdc == nullptr || mdc->empty()) && (ndc == nullptr || ndc->empty())) {
165 return std::shared_ptr<const LogContextSnapshot>();
166 }
167
168 std::shared_ptr<LogContextSnapshot> snapshot(new LogContextSnapshot());
169 if (mdc != nullptr) {
170 snapshot->mdc = *mdc;
171 }
172 if (ndc != nullptr) {
173 snapshot->ndc = *ndc;
174 }
175 return snapshot;
176 }
177
183 class NdcGuard {
184 public:
185 explicit NdcGuard(const std::string& message) {
186 ndc_push(message);
187 }
188
189 ~NdcGuard() {
190 ndc_pop();
191 }
192
193 NdcGuard(const NdcGuard&) = delete;
194 NdcGuard& operator=(const NdcGuard&) = delete;
195 NdcGuard(NdcGuard&&) = delete;
196 NdcGuard& operator=(NdcGuard&&) = delete;
197 };
198
199#endif // LOGIT_WITH_CONTEXT
200
201} // namespace logit
202
203#endif // LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_DETAIL_LOGCONTEXT_HPP_INCLUDED
The primary namespace for the LogIt++ library.