bux API Reference 1.9.0
Static library of whatever are seen required in general purpose but not directly supported from Modern C++. Or whatever reusable originated from my side projects.
Loading...
Searching...
No Matches
SyncLog.h
Go to the documentation of this file.
1#pragma once
2
3#include "LogLevel.h" // E_LogLevel
4#include <chrono> // std::chrono::time_zone
5#include <concepts> // std::convertible_to<>, std::derived_from<>
6#include <mutex> // std::recursive_mutex
7#include <ostream> // std::ostream
8
9namespace bux {
10
11//
12// Types
13//
15{
16public:
17
18 virtual std::ostream *lockLog() = 0;
20 virtual std::ostream *lockLog(E_LogLevel ll) = 0;
22 virtual void unlockLog(bool flush = true) = 0;
24
25 const std::chrono::time_zone *const tz;
26
27protected:
28
29 I_SyncLog(const std::chrono::time_zone *tz_): tz(tz_) {}
30 ~I_SyncLog() = default;
32};
33
35{
36 virtual ~I_ReenterableLog() = default;
38 virtual std::ostream *useLog() = 0;
40 virtual std::ostream *useLog(E_LogLevel ll) = 0;
42 virtual void unuseLog(bool flush) = 0;
44};
45
46template<class C_SinkRefHolder> requires requires (C_SinkRefHolder holder)
47 {
48 { holder.stream() }-> std::convertible_to<std::ostream*>;
49 holder.reset();
50 }
55{
56public:
57
58 // Nonvirtuals
59 template<typename T>
60 explicit C_ReenterableLogger(T &ref, E_LogLevel max_ll = LL_VERBOSE): m_refHolder(ref), m_maxLevel(max_ll)
61 {
62 }
64 {
65 auto ret = m_maxLevel;
66 m_maxLevel = level;
67 return ret;
68 }
69 auto lockedCount() const { return m_lockCount; }
70
71 // Implement I_ReenterableLog
72 std::ostream *useLog() override
73 {
74 if (const auto ret = m_refHolder.stream()) [[likely]]
75 {
76 ++m_lockCount;
77 return ret;
78 }
79 return nullptr;
80 }
81 std::ostream *useLog(E_LogLevel ll) override
82 {
83 return ll <= m_maxLevel? useLog(): nullptr;
84 }
85 void unuseLog(bool flush) override
86 {
87 if (flush)
88 m_refHolder.stream()->flush();
89
90 if (!--m_lockCount) [[likely]]
91 m_refHolder.reset();
92 }
93
94private:
95
96 // Data
97 C_SinkRefHolder m_refHolder;
98 int m_lockCount{};
99 E_LogLevel m_maxLevel;
100};
101
102template<class C_LogImpl>
104{
105 //using type = ...;
106};
107
108template<class C_LogImpl, class C_SinkRefHolder = typename C_AutoSinkHolderT<C_LogImpl>::type>
109class C_ReenterableLoggerInside: private C_LogImpl, public C_ReenterableLogger<C_SinkRefHolder>
110{
111public:
112
113 // Ctor
114 template<class...T_Args>
115 explicit C_ReenterableLoggerInside(E_LogLevel ll, T_Args&&...args):
116 C_LogImpl(std::forward<T_Args>(args)...),
117 C_ReenterableLogger<C_SinkRefHolder>(*static_cast<C_LogImpl*>(this), ll)
118 {}
119 C_LogImpl &impl() { return *this; }
120};
121
126{
127
128public:
129
130 // Nonvirtuals
131 explicit C_SyncLogger(I_ReenterableLog &impl, const std::chrono::time_zone *tz_ = nullptr): I_SyncLog(tz_), m_impl(impl) {}
132 explicit C_SyncLogger(I_ReenterableLog &impl, bool use_local_time):
133 C_SyncLogger(impl, use_local_time? std::chrono::get_tzdb().current_zone(): nullptr) {}
134
135 // Implement I_SyncLog
136 std::ostream *lockLog() override;
137 std::ostream *lockLog(E_LogLevel ll) override;
138 void unlockLog(bool flush) override;
139
140private:
141
142 // Data
143 std::recursive_mutex m_lock;
144 I_ReenterableLog &m_impl;
145};
146
148{
149 // Data
150 std::ostream &m_out;
151
152 // Nonvirtuals
153 C_OstreamHolder(std::ostream &out): m_out(out) {}
154 std::ostream *stream() const { return &m_out; }
155 void reset() {}
156};
158
159template<std::derived_from<std::ostream> T_Sink>
160struct C_AutoSinkHolderT<T_Sink>
161{
163};
164
165template<typename T>
166struct I_SnapT
167{
168 virtual ~I_SnapT() = default;
170 virtual T snap() = 0;
172};
173
175{
176public:
177
178 // Nonvirtuals
180 std::ostream *stream() {
181 if (!m_saved)
182 m_saved = m_snap.snap();
183
184 return m_saved;
185 }
186 void reset() { m_saved = nullptr; }
187
188private:
189
190 // Data
192 std::ostream *m_saved{};
193};
195
196template<std::derived_from<I_SnapT<std::ostream*>> T_Sink>
197struct C_AutoSinkHolderT<T_Sink>
198{
200};
201
205{
206public:
207
208 // Nonvirtuals
209 C_UseLog(I_SyncLog &obj): m_obj(obj), m_locked(obj.lockLog()) {}
210 C_UseLog(I_SyncLog &obj, E_LogLevel level): m_obj(obj), m_locked(obj.lockLog(level)) {}
212 {
213 if (m_locked)
214 m_obj.unlockLog();
215 }
216 operator bool() const { return m_locked != nullptr; }
217 auto &operator*() const { return *m_locked; }
218 auto stream() const { return m_locked; }
219 auto timezone() const { return m_obj.tz; }
220
221private:
222
223 // Data
224 I_SyncLog &m_obj;
225 std::ostream *const m_locked;
226};
227
228} // namespace bux
C_PersistedSnapHolder(I_SnapT< std::ostream * > &snap)
Definition SyncLog.h:179
std::ostream * stream()
Definition SyncLog.h:180
C_ReenterableLoggerInside(E_LogLevel ll, T_Args &&...args)
Definition SyncLog.h:115
std::ostream * useLog() override
Return non-null pointer if possible.
Definition SyncLog.h:72
auto setLogLevel(E_LogLevel level)
Definition SyncLog.h:63
auto lockedCount() const
Definition SyncLog.h:69
C_ReenterableLogger(T &ref, E_LogLevel max_ll=LL_VERBOSE)
Definition SyncLog.h:60
std::ostream * useLog(E_LogLevel ll) override
Return non-null pointer if logging is permitted to log level ll.
Definition SyncLog.h:81
void unuseLog(bool flush) override
If the previous call to lockLog() returned null, the behavior is undefined.
Definition SyncLog.h:85
std::ostream * lockLog() override
Definition SyncLog.cpp:9
void unlockLog(bool flush) override
Definition SyncLog.cpp:38
C_SyncLogger(I_ReenterableLog &impl, const std::chrono::time_zone *tz_=nullptr)
Definition SyncLog.h:131
C_SyncLogger(I_ReenterableLog &impl, bool use_local_time)
Definition SyncLog.h:132
auto stream() const
Definition SyncLog.h:218
auto & operator*() const
Definition SyncLog.h:217
auto timezone() const
Definition SyncLog.h:219
C_UseLog(I_SyncLog &obj, E_LogLevel level)
Definition SyncLog.h:210
C_UseLog(I_SyncLog &obj)
Definition SyncLog.h:209
</// Thread safety is expected
Definition SyncLog.h:15
virtual std::ostream * lockLog(E_LogLevel ll)=0
Return non-null pointer if logging is permitted for the given log level ll.
virtual void unlockLog(bool flush=true)=0
If the previous call to lockLog() returned null, the behavior is undefined.
I_SyncLog(const std::chrono::time_zone *tz_)
Definition SyncLog.h:29
const std::chrono::time_zone *const tz
Definition SyncLog.h:25
~I_SyncLog()=default
Pointer deletion is not expected.
virtual std::ostream * lockLog()=0
Return non-null pointer if possible.
THE common namespace of bux library.
Definition AtomiX.cpp:3
E_LogLevel
Definition LogLevel.h:9
std::ostream & m_out
Definition SyncLog.h:150
C_OstreamHolder(std::ostream &out)
Definition SyncLog.h:153
std::ostream * stream() const
Definition SyncLog.h:154
Thread-unsafe implementation is preferred for performance.
Definition SyncLog.h:35
virtual std::ostream * useLog(E_LogLevel ll)=0
Return non-null pointer if logging is permitted to log level ll.
virtual ~I_ReenterableLog()=default
Pointer deletion is hereby granted.
virtual void unuseLog(bool flush)=0
If the previous call to lockLog() returned null, the behavior is undefined.
virtual std::ostream * useLog()=0
Return non-null pointer if possible.
< Parasitic Type
Definition SyncLog.h:167
virtual T snap()=0
Snap the current T value.
virtual ~I_SnapT()=default
Pointer deletion is hereby granted.