Compare commits

...
5 changed files with 212 additions and 21 deletions

No files matched your search

+2 -13
View File
@@ -3,19 +3,8 @@
home.packages = with pkgs; [ pkgs.qitechPackages.electron ];
# Add autostart entry for the QiTech electron app
xdg.configFile."autostart/de.qitech.control-electron.desktop".text = ''
[Desktop Entry]
Type=Application
Name=QiTech Control
Comment=QiTech Control
Exec=qitech-control-electron
Icon=de.qitech.control-electron
Terminal=false
StartupWMClass=QiTech Control
X-GNOME-Autostart-enabled=true
X-GNOME-Autostart-Phase=Applications
'';
xdg.configFile."autostart/de.qitech.control-electron.desktop".source =
"${pkgs.qitechPackages.electron}/share/applications/de.qitech.control-electron.desktop";
dconf.settings = {
# Set GNOME wallpaper
-6
View File
@@ -1,6 +0,0 @@
pub fn init_journald_tracing<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
where
S: tracing::Subscriber + for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>,
{
Box::new(tracing_journald::layer().expect("Failed to create journald layer"))
}
+5 -2
View File
@@ -4,7 +4,7 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitEx
pub mod fmt;
#[cfg(feature = "tracing-journald")]
pub mod journald;
mod throttle;
/// Initialize the basic tracing system (without OpenTelemetry if enabled)
/// OpenTelemetry layer is deferred until async runtime is available
@@ -45,7 +45,10 @@ pub fn init_tracing() {
let subscriber = {
#[cfg(feature = "tracing-journald")]
{
subscriber.with(journald::init_journald_tracing())
use crate::logging::throttle::ThrottleLayer;
let layer = tracing_journald::layer().expect("Failed to create journald layer");
subscriber.with(ThrottleLayer::new(layer))
}
#[cfg(not(feature = "tracing-journald"))]
{
+204
View File
@@ -0,0 +1,204 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::sync::Mutex;
use std::time::{Duration, Instant};
use tracing::{Event, Level, Subscriber};
use tracing_subscriber::layer::{Context, Layer};
#[derive(Eq, PartialEq)]
struct CachedEvent {
level: Level,
message: Option<String>,
}
impl tracing::field::Visit for CachedEvent {
fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
if field.name() == "message" {
self.message = Some(value.to_string());
}
}
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn Debug) {
if field.name() == "message" && self.message.is_none() {
self.message = Some(format!("{value:?}"));
}
}
}
impl CachedEvent {
fn new(event: &Event<'_>) -> Self {
let mut s = Self {
level: event.metadata().level().to_owned(),
message: None,
};
event.record(&mut s);
s.message.get_or_insert(event.metadata().name().to_string());
s
}
}
impl Hash for CachedEvent {
fn hash<H: Hasher>(&self, state: &mut H) {
self.message.hash(state);
self.level.hash(state);
}
}
impl CachedEvent {
fn message(&self) -> String {
self.message
.clone()
.expect("Event had no name and no message field")
}
}
struct State {
window_start: Instant,
window_size: Duration,
repititions: HashMap<CachedEvent, usize>,
}
impl Default for State {
fn default() -> Self {
Self {
window_start: Instant::now(),
window_size: Duration::from_millis(300),
repititions: HashMap::default(),
}
}
}
impl State {
fn count(&mut self, event: &Event<'_>) -> bool {
let event = CachedEvent::new(event);
let repeated = self
.repititions
.entry(event)
.and_modify(|x| *x += 1)
.or_insert(0);
*repeated == 0
}
fn next_window(&mut self) -> bool {
let now = Instant::now();
if now.duration_since(self.window_start) > self.window_size {
self.window_start = now;
return true;
}
false
}
fn flush(&mut self) -> HashMap<CachedEvent, usize> {
let mut repititions = HashMap::default();
std::mem::swap(&mut repititions, &mut self.repititions);
repititions.retain(|_, c| *c > 0);
repititions
}
}
pub struct ThrottleLayer<L> {
inner: L,
state: Mutex<State>,
}
impl<L> ThrottleLayer<L> {
pub fn new(inner: L) -> Self {
Self {
inner,
state: Mutex::default(),
}
}
}
impl<L> Drop for ThrottleLayer<L> {
fn drop(&mut self) {
let mut st = self.state.lock().expect("lock");
st.flush();
}
}
impl<S, L> Layer<S> for ThrottleLayer<L>
where
S: Subscriber,
L: Layer<S>,
{
fn enabled(&self, metadata: &tracing::Metadata<'_>, ctx: Context<'_, S>) -> bool {
self.inner.enabled(metadata, ctx)
}
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
let mut st = self.state.lock().expect("lock");
let mut repititions = HashMap::default();
if st.next_window() {
repititions = st.flush();
}
let should_forward = st.count(event);
drop(st);
for (rep_event, count) in repititions.drain() {
match rep_event.level {
Level::ERROR => tracing::error!("[repeated x{count}] {}", rep_event.message()),
Level::WARN => tracing::warn!("[repeated x{count}] {}", rep_event.message()),
Level::INFO => tracing::info!("[repeated x{count}] {}", rep_event.message()),
Level::DEBUG => tracing::debug!("[repeated x{count}] {}", rep_event.message()),
Level::TRACE => tracing::trace!("[repeated x{count}] {}", rep_event.message()),
}
}
if should_forward {
self.inner.on_event(event, ctx);
}
}
fn on_new_span(
&self,
attrs: &tracing::span::Attributes<'_>,
id: &tracing::span::Id,
ctx: Context<'_, S>,
) {
self.inner.on_new_span(attrs, id, ctx)
}
fn on_record(
&self,
id: &tracing::span::Id,
values: &tracing::span::Record<'_>,
ctx: Context<'_, S>,
) {
self.inner.on_record(id, values, ctx)
}
fn on_enter(&self, id: &tracing::span::Id, ctx: Context<'_, S>) {
self.inner.on_enter(id, ctx)
}
fn on_exit(&self, id: &tracing::span::Id, ctx: Context<'_, S>) {
self.inner.on_exit(id, ctx)
}
fn on_close(&self, id: tracing::span::Id, ctx: Context<'_, S>) {
self.inner.on_close(id, ctx)
}
fn on_id_change(&self, old: &tracing::span::Id, new: &tracing::span::Id, ctx: Context<'_, S>) {
self.inner.on_id_change(old, new, ctx)
}
fn on_follows_from(
&self,
span: &tracing::span::Id,
follows: &tracing::span::Id,
ctx: Context<'_, S>,
) {
self.inner.on_follows_from(span, follows, ctx)
}
}
+1
View File
@@ -22,6 +22,7 @@ use socketio::{
#[cfg(feature = "development-build")]
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(not(feature = "development-build"))]
use utils::start_dnsmasq;
use app_state::{HotThreadMessage, SharedState};