Skip to content
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

Changing output file of a sink? #820

Closed
abrownsword opened this issue Sep 3, 2018 · 5 comments
Closed

Changing output file of a sink? #820

abrownsword opened this issue Sep 3, 2018 · 5 comments
Labels

Comments

@abrownsword
Copy link

I have a situation where I need to change which FILE* a log sink is directed to, after it has been created. For the moment I have hacked a "set_output_file()" into ansicolor_sink, but I would prefer not to have to modify the library and this might be a useful feature for others.

My use case is that I have a single logger object that is shared around the program (actually it is a logger which has both the 'console' output and a rotating file output), and initially its 'console' output goes to stdout, but once initialization is well under way it can happen that a user configuration option is discovered that requests the log output to go to another file instead of stdout. The rotating file log is not to be changed, and the logger object is widely used by that point, so redirecting the console FILE* seemed like the only option.

@gabime
Copy link
Owner

gabime commented Sep 3, 2018

Another approach would be "replacing" the console sink at runtime with the new sink .
This will work, but it is not thread safe:

auto sinks_vector = logger->sinks();
sinks_vector.erase(sinks_vector.begin()); //remove the first sink (assuming it is console)
sinks_vector.push_back(std::make_shared<new_sink>(...));

To make it thread safe you can first clone() the logger(not released yet, take it from latest), and then replace the orig:

auto new_lgger = orig_logger->clone(logger-> name());
auto sinks_vector = new_logger->sinks();
sinks_vector.erase(sinks_vector.begin()); //remove the first sink (assuming it is console)
sinks_vector.push_back(std::make_shared<new_sink>(...))
orig_logger = move(new_logger);

Anorther thread safe way would be to use the sinks::dist_sink which provides a thread safe way to removing/adding sinks.

@abrownsword
Copy link
Author

I am trying to pursue this, unfortunately the interface of spdlog::sinks::ansicolor_sink requires the FILE* to be essentially provided as a template parameter and that requires the providing class to be a global variable. I can hack to make this work, but it seems like a poor design choice.

@gabime
Copy link
Owner

gabime commented Sep 3, 2018

I can hack to make this work, but it seems like a poor design choice

I am not sure I follow. What prevents you to just replace the sink at runtime with new file sink(or ostream_sink)? No need to hack the console sink.

@abrownsword
Copy link
Author

The ansicolor_sink is a template parameterized on a stream type, and its method is called on that type, not on an instance of that type. So my type needs to have the FILE* at global scope, which is unfortunate.

@gabime gabime added the question label Sep 4, 2018
@gabime gabime closed this as completed Sep 4, 2018
@nhanders
Copy link

I tried to implement the code provided above, but ran into issues. This was my implementation in the end:

auto new_logger = orig_logger->clone(orig_logger-> name());
auto& sinks_vector = new_logger->sinks(); // must be of type auto& or it is not passed by reference
sinks_vector.erase(sinks_vector.begin()); 
sinks_vector.push_back(our_sink_object_ptr)
*orig_logger = *new_logger; // Note this line

where our_sink_object_ptr is shared between multiple loggers.

I tried to use orig_logger = move(new_logger); but it replaces the managed object of orig_logger with the logger managed by new_logger. This is confirmed by looking at the reference count of orig_logger which, for example, changes from 4 to 1 after the move operation (in my use case).

I am looking for a robust solution for this, since I am aware that the one I have provided is not thread safe. Has anyone had any success with this problem? Perhaps using sinks::dist_sink as suggested above by @gabime?

(Great library by the way!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants