9 #include "quill/core/Attributes.h" 10 #include "quill/core/Filesystem.h" 11 #include "quill/core/QuillError.h" 12 #include "quill/core/Spinlock.h" 13 #include "quill/core/ThreadPrimitives.h" 19 #include <type_traits> 39 explicit SinkInfo() =
default;
40 SinkInfo(std::string sid, std::weak_ptr<Sink> sptr)
41 : sink_id(static_cast<std::string&&>(sid)), sink_ptr(
static_cast<std::weak_ptr<Sink>&&
>(sptr)) {};
44 std::weak_ptr<Sink> sink_ptr;
52 QUILL_EXPORT
static SinkManager& instance() noexcept
59 QUILL_NODISCARD std::shared_ptr<Sink> get_sink(std::string
const& sink_name)
const 62 std::string normalized_sink_name;
65 normalized_sink_name = detail::normalize_file_sink_path(fs::path{sink_name},
false).
string();
75 std::shared_ptr<Sink> sink = _find_sink(sink_name);
77 if (!sink && !normalized_sink_name.empty() && normalized_sink_name != sink_name)
79 sink = _find_sink(normalized_sink_name);
82 if (QUILL_UNLIKELY(!sink))
84 QUILL_THROW(
QuillError{
"Sink with name \"" + sink_name +
"\" does not exist"});
94 template <
typename TSink,
typename... Args>
95 std::shared_ptr<Sink>
create_sink(std::string
const& sink_name, Args&&... args)
97 static_assert(std::is_base_of_v<Sink, TSink>,
"TSink must derive from Sink");
99 std::string
const sink_id = _normalized_sink_name<TSink>(sink_name);
101 (void)_reserve_sink_id_for_creation(sink_name, sink_id,
false);
102 return _create_reserved_sink<TSink>(sink_id,
static_cast<Args&&
>(args)...);
110 template <
typename TSink,
typename... Args>
113 static_assert(std::is_base_of_v<Sink, TSink>,
"TSink must derive from Sink");
115 std::string
const sink_id = _normalized_sink_name<TSink>(sink_name);
117 std::shared_ptr<Sink> sink = _reserve_sink_id_for_creation(sink_name, sink_id,
true);
118 return sink ? sink : _create_reserved_sink<TSink>(sink_id,
static_cast<Args&&
>(args)...);
122 uint32_t cleanup_unused_sinks()
129 for (
auto it = _sinks.begin(); it != _sinks.end();)
131 if (it->sink_ptr.expired())
133 it = _sinks.erase(it);
146 template <
typename TSink>
147 static std::string _normalized_sink_name(std::string
const& sink_name)
149 if constexpr (std::disjunction_v<std::is_same<FileSink, TSink>, std::is_base_of<FileSink, TSink>>)
151 return detail::normalize_file_sink_path(fs::path{sink_name}).
string();
162 QUILL_NODISCARD std::shared_ptr<Sink> _reserve_sink_id_for_creation(std::string
const& sink_name,
163 std::string
const& sink_id,
bool return_existing)
170 std::shared_ptr<Sink> sink = _find_sink(sink_id);
180 "\" already exists. " 181 "Use create_or_get_sink() if you want to retrieve the existing sink, " 182 "or choose a different name."});
186 if (_try_mark_sink_pending(sink_id))
196 template <
typename TSink,
typename... Args>
197 std::shared_ptr<Sink> _create_reserved_sink(std::string
const& sink_id, Args&&... args)
199 std::shared_ptr<Sink> sink;
200 QUILL_TRY { sink = _create_sink_instance<TSink>(sink_id,
static_cast<Args&&
>(args)...); }
201 #if !defined(QUILL_NO_EXCEPTIONS) 204 _remove_pending_sink(sink_id);
209 _publish_created_sink(sink_id, sink);
213 template <
typename TSink,
typename... Args>
214 static std::shared_ptr<Sink> _create_sink_instance(std::string
const& sink_id, Args&&... args)
216 if constexpr (std::disjunction_v<std::is_same<FileSink, TSink>, std::is_base_of<FileSink, TSink>>)
218 return std::make_shared<TSink>(sink_id,
static_cast<Args&&
>(args)...);
222 return std::make_shared<TSink>(
static_cast<Args&&
>(args)...);
226 void _publish_created_sink(std::string
const& sink_id, std::shared_ptr<Sink>
const& sink)
232 _insert_sink(sink_id, sink);
233 _erase_pending_sink(sink_id);
235 #if !defined(QUILL_NO_EXCEPTIONS) 238 _erase_pending_sink(sink_id);
244 void _remove_pending_sink(std::string
const& sink_id) noexcept
247 _erase_pending_sink(sink_id);
251 void _insert_sink(std::string
const& sink_name, std::shared_ptr<Sink>
const& sink)
254 std::lower_bound(_sinks.begin(), _sinks.end(), sink_name,
255 [](SinkInfo
const& elem, std::string
const& b) {
return elem.sink_id < b; });
257 if (search_it != _sinks.end() && search_it->sink_id == sink_name && search_it->sink_ptr.expired())
259 search_it->sink_ptr = sink;
263 _sinks.insert(search_it, SinkInfo{sink_name, sink});
266 QUILL_NODISCARD
bool _try_mark_sink_pending(std::string
const& sink_name)
268 auto search_it = std::lower_bound(_pending_sink_ids.begin(), _pending_sink_ids.end(), sink_name);
270 if (search_it != _pending_sink_ids.end() && *search_it == sink_name)
275 _pending_sink_ids.insert(search_it, sink_name);
279 void _erase_pending_sink(std::string
const& sink_name) noexcept
281 auto search_it = std::lower_bound(_pending_sink_ids.begin(), _pending_sink_ids.end(), sink_name);
283 if (search_it != _pending_sink_ids.end() && *search_it == sink_name)
285 _pending_sink_ids.erase(search_it);
290 QUILL_NODISCARD std::shared_ptr<Sink> _find_sink(std::string
const& target)
const noexcept
292 std::shared_ptr<Sink> sink;
295 std::lower_bound(_sinks.begin(), _sinks.end(), target,
296 [](SinkInfo
const& elem, std::string
const& b) {
return elem.sink_id < b; });
298 if (search_it != std::end(_sinks) && search_it->sink_id == target)
300 sink = search_it->sink_ptr.lock();
307 std::vector<SinkInfo> _sinks;
308 std::vector<std::string> _pending_sink_ids;
QUILL_ATTRIBUTE_HOT void sleep_for_ns(uint64_t ns) noexcept
Mirrors std::this_thread::sleep_for(std::chrono::nanoseconds{ns}).
Definition: ThreadPrimitives.h:43
Keep the Windows-specific FileSink split isolated under _WIN32.
Definition: FileSink.h:645
std::shared_ptr< Sink > create_or_get_sink(std::string const &sink_name, Args &&... args)
Creates a new sink or returns an existing one with the given name.
Definition: SinkManager.h:111
Base class for sinks.
Definition: Sink.h:46
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:28
Definition: Spinlock.h:18
custom exception
Definition: QuillError.h:47
Definition: Spinlock.h:58
Definition: SinkManager.h:34
std::shared_ptr< Sink > create_sink(std::string const &sink_name, Args &&... args)
Creates a new sink with the given name.
Definition: SinkManager.h:95