-
Notifications
You must be signed in to change notification settings - Fork 78
Logger: Composite / Multiple loggers logger #1574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
9bb8ef0
start from poc
nitbharambe 76a0374
make mutex mutable
nitbharambe b6ce514
address comments
nitbharambe 37f37f6
address comments forwarding
nitbharambe 3fd603d
address comments sonar + others
nitbharambe 5e62c35
clang tidy
nitbharambe 8d55f7a
add get output test
nitbharambe c9dee9a
address sonar
nitbharambe 472908e
change to ostringstream
nitbharambe 967c9ce
Apply suggestion from @mgovers
nitbharambe a212e77
address comments
nitbharambe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
power_grid_model_c/power_grid_model/include/power_grid_model/common/composite_logging.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // SPDX-FileCopyrightText: Contributors to the Power Grid Model project <powergridmodel@lfenergy.org> | ||
| // | ||
| // SPDX-License-Identifier: MPL-2.0 | ||
|
|
||
| #pragma once | ||
|
|
||
| #include "logging.hpp" | ||
|
|
||
| #include <algorithm> | ||
| #include <memory> | ||
| #include <ranges> | ||
| #include <string_view> | ||
| #include <vector> | ||
|
|
||
| namespace power_grid_model::common::logging { | ||
|
|
||
| // Owns a list of child loggers (created by MultiThreadedCompositeLogger::create_child) and fans all log calls out to | ||
| // each of them. The children are owned by this logger; their lifetimes are tied to this object. | ||
| class CompositeChildLogger : public Logger { | ||
| public: | ||
| explicit CompositeChildLogger(std::vector<std::unique_ptr<Logger>> children) : children_{std::move(children)} {} | ||
|
|
||
| using Logger::log; | ||
|
|
||
| void log(LogEvent tag) override { log_all(tag); } | ||
| void log(LogEvent tag, std::string_view message) override { log_all(tag, message); } | ||
| void log(LogEvent tag, double value) override { log_all(tag, value); } | ||
| void log(LogEvent tag, Idx value) override { log_all(tag, value); } | ||
|
|
||
| private: | ||
| std::vector<std::unique_ptr<Logger>> children_; | ||
|
|
||
| template <typename... Args> void log_all(Args const&... args) { | ||
| for (auto const& child : children_) { | ||
| child->log(args...); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| // Owning fan-out MultiThreadedLogger. Holds shared ownership of MultiThreadedLogger instances and forwards | ||
| // all log calls to each. create_child() creates a CompositeChildLogger that owns one child per registered logger. | ||
| // | ||
| // Lifetime contract: each registered logger is kept alive by this composite for as long as it remains | ||
| // registered (shared ownership), regardless of whether any other owner (e.g. a C API wrapper) has released | ||
| // its own reference. This is what makes destroying the wrapper while still registered safe. | ||
| // Dedupe: registering the same logger twice is a no-op (idempotent, consistent with logging conventions). | ||
| // UB: modifying the logger list while a calculation is in progress. | ||
|
nitbharambe marked this conversation as resolved.
|
||
| class MultiThreadedCompositeLogger : public MultiThreadedLogger { | ||
|
nitbharambe marked this conversation as resolved.
|
||
| public: | ||
| MultiThreadedCompositeLogger() = default; | ||
| explicit MultiThreadedCompositeLogger(std::vector<std::shared_ptr<MultiThreadedLogger>> loggers) | ||
| : loggers_{std::move(loggers)} {} | ||
|
|
||
| // Add/remove a logger. The object address is unchanged so any existing reference_wrapper | ||
| // pointing to this composite remains valid. Do not call while a calculation is in progress. | ||
| void add(std::shared_ptr<MultiThreadedLogger> logger) { | ||
| if (logger == nullptr) { | ||
| return; // defensively ignore null registrations | ||
| } | ||
| if (std::ranges::any_of(loggers_, [&](auto const& existing) { return existing.get() == logger.get(); })) { | ||
| return; // already registered — dedupe silently, consistent with logging API conventions | ||
| } | ||
| loggers_.push_back(std::move(logger)); | ||
| } | ||
| void remove(MultiThreadedLogger const* logger) { | ||
|
mgovers marked this conversation as resolved.
|
||
| if (logger == nullptr) { | ||
| return; // defensively ignore null removals but it should be unreachable. | ||
| } | ||
| if (auto it = std::ranges::find_if(loggers_, [&](auto const& existing) { return existing.get() == logger; }); | ||
| it != loggers_.end()) { | ||
| loggers_.erase(it); | ||
| } | ||
| } | ||
| void reset() { loggers_.clear(); } | ||
|
|
||
| std::unique_ptr<Logger> create_child() override { | ||
|
mgovers marked this conversation as resolved.
mgovers marked this conversation as resolved.
|
||
| std::vector<std::unique_ptr<Logger>> child_loggers; | ||
| child_loggers.reserve(loggers_.size()); | ||
| for (auto const& logger : loggers_) { | ||
| child_loggers.push_back(logger->create_child()); | ||
| } | ||
| return std::make_unique<CompositeChildLogger>(std::move(child_loggers)); | ||
| } | ||
|
|
||
| void log(LogEvent tag) override { log_all(tag); } | ||
| void log(LogEvent tag, std::string_view message) override { log_all(tag, message); } | ||
| void log(LogEvent tag, double value) override { log_all(tag, value); } | ||
| void log(LogEvent tag, Idx value) override { log_all(tag, value); } | ||
|
|
||
| using MultiThreadedLogger::log; | ||
|
|
||
| // Fan out clear() to every registered logger. | ||
| void clear() override { | ||
|
nitbharambe marked this conversation as resolved.
|
||
| for (auto const& logger : loggers_) { | ||
| logger->clear(); | ||
| } | ||
| } | ||
|
|
||
| [[nodiscard]] bool empty() const { return loggers_.empty(); } | ||
|
|
||
| private: | ||
| std::vector<std::shared_ptr<MultiThreadedLogger>> loggers_; // owning | ||
|
|
||
| template <typename... Args> void log_all(Args const&... args) { | ||
| for (auto const& logger : loggers_) { | ||
| logger->log(args...); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| } // namespace power_grid_model::common::logging | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.