I have a program which is basically a game, i.e. it renders at 60fps and draws UI. I'd like log messages to be logged to my UI rather than to stdout.
I was thinking of using mpsc channels - the main thread keeps an mpsc::Receiver and prints anything from it to the UI, and I could have an mpsc::Sender which I could pass around with function calls, and clone it and send a copy whenever I spawn a new thread.
While this would work, I'd kind of like the convenience of using the log::Logger trait instead, rather than having to pass the logger around all over the place. I was thinking of something like implementing Logger for a struct MyLogger { rx: Option<mpsc::Receiver>, tx: mpsc::Sender }, which will be stored as a global static mut, and using thread_local! to get each thread lazily to clone the Sender and store it as a thread local static, which MyLogger::log can access to add a message to the queue.
You do not need a thread-local, and you especially do not need static mut.
(In general, never use static mut; ordinary statics combined with suitable interior mutability primitives are much safer. But in this case, you don't even need a static, since log has already got the static variable you need.)
Just put the channel in the log::Log implementation. Here's a simple demo:
I believe there are some channel-sender-like things that do require &mut or aren't Sync (though I don't recall what it was I encountered once) — so my general advice would be to remember to check the properties of whatever you're considering using, and consider that there might be alternatives if it doesn't suit.