bux API Reference 1.11.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 "XPlatform.h" // bux::T_LocalZone, bux::local_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
26
27protected:
28
29 I_SyncLog(T_LocalZone 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, T_LocalZone tz_ = T_LocalZone()): I_SyncLog(tz_), m_impl(impl) {}
132#if LOCALZONE_IS_TIMEZONE
133 explicit C_SyncLogger(I_ReenterableLog &impl, bool use_local_time):
134 C_SyncLogger(impl, use_local_time? local_zone(): nullptr) {}
135#endif
136
137 // Implement I_SyncLog
138 std::ostream *lockLog() override;
139 std::ostream *lockLog(E_LogLevel ll) override;
140 void unlockLog(bool flush) override;
141
142private:
143
144 // Data
145 std::recursive_mutex m_lock;
146 I_ReenterableLog &m_impl;
147};
148
150{
151 // Data
152 std::ostream &m_out;
153
154 // Nonvirtuals
155 C_OstreamHolder(std::ostream &out): m_out(out) {}
156 std::ostream *stream() const { return &m_out; }
157 void reset() {}
158};
160
161template<std::derived_from<std::ostream> T_Sink>
162struct C_AutoSinkHolderT<T_Sink>
163{
165};
166
167template<typename T>
168struct I_SnapT
169{
170 virtual ~I_SnapT() = default;
172 virtual T snap() = 0;
174};
175
177{
178public:
179
180 // Nonvirtuals
182 std::ostream *stream() {
183 if (!m_saved)
184 m_saved = m_snap.snap();
185
186 return m_saved;
187 }
188 void reset() { m_saved = nullptr; }
189
190private:
191
192 // Data
194 std::ostream *m_saved{};
195};
197
198template<std::derived_from<I_SnapT<std::ostream*>> T_Sink>
199struct C_AutoSinkHolderT<T_Sink>
200{
202};
203
207{
208public:
209
210 // Nonvirtuals
211 C_UseLog(I_SyncLog &obj): m_obj(obj), m_locked(obj.lockLog()) {}
212 C_UseLog(I_SyncLog &obj, E_LogLevel level): m_obj(obj), m_locked(obj.lockLog(level)) {}
214 {
215 if (m_locked)
216 m_obj.unlockLog();
217 }
218 operator bool() const { return m_locked != nullptr; }
219 auto &operator*() const { return *m_locked; }
220 auto stream() const { return m_locked; }
221 auto timezone() const { return m_obj.tz; }
222
223private:
224
225 // Data
226 I_SyncLog &m_obj;
227 std::ostream *const m_locked;
228};
229
230} // namespace bux
C_PersistedSnapHolder(I_SnapT< std::ostream * > &snap)
Definition SyncLog.h:181
std::ostream * stream()
Definition SyncLog.h:182
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, bool use_local_time)
Definition SyncLog.h:133
C_SyncLogger(I_ReenterableLog &impl, T_LocalZone tz_=T_LocalZone())
Definition SyncLog.h:131
auto stream() const
Definition SyncLog.h:220
auto & operator*() const
Definition SyncLog.h:219
auto timezone() const
Definition SyncLog.h:221
C_UseLog(I_SyncLog &obj, E_LogLevel level)
Definition SyncLog.h:212
C_UseLog(I_SyncLog &obj)
Definition SyncLog.h:211
</// 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()=default
Pointer deletion is not expected.
const T_LocalZone tz
Definition SyncLog.h:25
I_SyncLog(T_LocalZone tz_)
Definition SyncLog.h:29
virtual std::ostream * lockLog()=0
Return non-null pointer if possible.
THE common namespace of bux library.
Definition AtomiX.cpp:3
C_ReenterableLogger< C_PersistedSnapHolder > C_ReenterableOstreamSnap
Definition SyncLog.h:196
E_LogLevel
Definition LogLevel.h:9
@ LL_VERBOSE
More detailed or advanced information probably considered too much by some.
Definition LogLevel.h:14
const std::chrono::time_zone * T_LocalZone
Definition XPlatform.h:18
C_ReenterableLogger< C_OstreamHolder > C_ReenterableOstream
Definition SyncLog.h:159
T_LocalZone local_zone()
Definition XPlatform.h:19
std::ostream & m_out
Definition SyncLog.h:152
C_OstreamHolder(std::ostream &out)
Definition SyncLog.h:155
std::ostream * stream() const
Definition SyncLog.h:156
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:169
virtual T snap()=0
Snap the current T value.
virtual ~I_SnapT()=default
Pointer deletion is hereby granted.