1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::frontend::{EngineMessage, Frontend};
#[cfg(feature = "tokio_console")]
use console_subscriber;
use lazy_static::lazy_static;
use once_cell::sync::OnceCell;
use std::sync::Arc;
use tokio::{select, sync::broadcast};
use tracing::Level;
use tracing_subscriber::{
  filter::{EnvFilter, LevelFilter},
  layer::SubscriberExt,
  util::SubscriberInitExt,
};

static FRONTEND_LOGGING_SET: OnceCell<bool> = OnceCell::new();
lazy_static! {
  static ref LOG_BROADCASTER: Arc<broadcast::Sender<Vec<u8>>> = Arc::new(broadcast::channel(255).0);
}

use tracing_subscriber::fmt::MakeWriter;

pub struct BroadcastWriter {
  log_sender: Arc<broadcast::Sender<Vec<u8>>>,
}

impl BroadcastWriter {
  pub fn new(sender: Arc<broadcast::Sender<Vec<u8>>>) -> Self {
    Self { log_sender: sender }
  }
}

impl std::io::Write for BroadcastWriter {
  fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
    let sender = self.log_sender.clone();
    let len = buf.len();
    let send_buf = buf.to_vec();
    let _ = sender.send(send_buf.to_vec());
    Ok(len)
  }

  fn flush(&mut self) -> Result<(), std::io::Error> {
    Ok(())
  }
}

impl MakeWriter<'_> for BroadcastWriter {
  type Writer = BroadcastWriter;
  fn make_writer(&self) -> Self::Writer {
    BroadcastWriter::new(self.log_sender.clone())
  }
}

pub fn setup_frontend_logging(log_level: Level, frontend: Arc<dyn Frontend>) {
  // Add panic hook for emitting backtraces through the logging system.
  log_panics::init();
  let mut receiver = LOG_BROADCASTER.subscribe();
  let log_sender = frontend.clone();
  let notifier = log_sender.disconnect_notifier();
  tokio::spawn(async move {
    // We can log until our receiver disappears at this point.
    loop {
      select! {
        log = receiver.recv() => {
          match log {
            Ok(log) => {
              log_sender
                .send(EngineMessage::EngineLog {
                  message: std::str::from_utf8(&log).unwrap().to_owned(),
                })
                .await;
            }
            Err(_) => return
          }
        }
        _ = notifier.notified() => return
      }
    }
  });

  if FRONTEND_LOGGING_SET.get().is_none() {
    FRONTEND_LOGGING_SET.set(true).unwrap();
    #[cfg(feature = "tokio_console")]
    {
      /*
      let console = console_subscriber::ConsoleLayer::builder()
        //.server_addr(([0, 0, 0, 0], 5555))
        .spawn();
      tracing_subscriber::registry()
        .with(LevelFilter::from(log_level))
        .with(
          tracing_subscriber::fmt::layer()
            .json()
            //.with_max_level(log_level)
            .with_ansi(false)
            .with_writer(move || BroadcastWriter::new(LOG_BROADCASTER.clone())),
        )
        .with(sentry_tracing::layer())
        .with(console)
        .try_init()
        .unwrap();
        */
      //console_subscriber::init();
      console_subscriber::ConsoleLayer::builder()
        .server_addr(([0, 0, 0, 0], 5555))
        .init();
    }
    #[cfg(not(feature = "tokio_console"))]
    {
      tracing_subscriber::registry()
        .with(LevelFilter::from(log_level))
        .with(
          tracing_subscriber::fmt::layer()
            .json()
            //.with_max_level(log_level)
            .with_ansi(false)
            .with_writer(move || BroadcastWriter::new(LOG_BROADCASTER.clone())),
        )
        //.with(sentry_tracing::layer())
        .try_init()
        .unwrap();
      info!("Logging subscriber added to registry");
    }
  }
}

pub fn setup_console_logging(log_level: Option<Level>) {
  if log_level.is_some() {
    tracing_subscriber::registry()
      .with(tracing_subscriber::fmt::layer())
      //.with(sentry_tracing::layer())
      .with(LevelFilter::from(log_level))
      .try_init()
      .unwrap();
  } else {
    tracing_subscriber::registry()
      .with(tracing_subscriber::fmt::layer())
      //.with(sentry_tracing::layer())
      .with(
        EnvFilter::try_from_default_env()
          .or_else(|_| EnvFilter::try_new("info"))
          .unwrap(),
      )
      .try_init()
      .unwrap();
  };
  println!("Intiface Server, starting up with stdout output.");
}