How to synchronize logging across threads?

I've been thinking of a project where I spawn multiple threads to monitor certain aspects of my machine. I was wondering what a good approach might be to synchronize logging across all my threads?

If my threads monitor on short timescale, I don't want any threads to block on writing to my log file, so I had the thought that I would have a dedicated thread for writing to the log file.

With that in mind, are channels the best way to approach this? E.g. multiple threads would all share the same Receiver (the log writing thread). Whenever a thread needs to write to a log, it can send the log output to the single Receiver. Then, the Receiver can write to the logfile while the monitoring threads can continue their execution.

If I understand correctly, I can use channel in std::sync::mpsc - Rust to create a single Receiver and clone Sender, where Receiver would be my log writing thread, while the cloned Sender would be the monitoring threads.

Am I thinking about this correctly? Are there better approaches to take?

  • I'd recommend you use crossbeam's channels, they're generally considered to be faster than the ones in stdlib.
  • I would probably be picky and have some static AtomicUsize which lets me ensure that messages are ordered properly. Something like this (not tested exactly, but I used something similar once):
    pub static LOG_COUNT: AtomicUsize = AtomicUsize::new(0);
    // Inside the thread that writes logs:
    let mut prev_msgs = HashMap::new();
    let mut running_count = 0;
    while let Ok((id, msg)) = receiver.recv() {
        if id == running_count {
            write(msg);
            running_count += 1;
            loop {
                if let Some(msg) = prev_msgs.remove(&running_count) {
                    write(msg);
                    running_count += 1;
                } else {
                    break;
                }
            }
        } else {
            prev_msgs.insert(id, msg);
        }
    }
    
    Where users submit a message as:
    sender.send((LOG_COUNT.fetch_add(1, Ordering::Relaxed), my_message)).unwrap();
    
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.