From 02fe9adfb708e10d2421fed933611783ce0da4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=A4rtens?= Date: Tue, 10 Sep 2019 15:22:34 +0200 Subject: [PATCH] Fix panic if starting singleplayer twice without closing the game reduce costs for metrics by checking chunks only every 100th tick add metrics for "server start time" and ingame "time of day" --- server/src/lib.rs | 19 ++++--- server/src/metrics.rs | 118 +++++++++++++++++++++++++++++------------- 2 files changed, 94 insertions(+), 43 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 2a9e67c85f..e8886ba002 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -664,13 +664,18 @@ impl Server { .with_label_values(&["sync"]) .set((before_tick_7 - before_tick_6).as_nanos() as i64); self.metrics.player_online.set(self.clients.len() as i64); - let mut chonk_cnt = 0; - let chunk_cnt = self.state.terrain().iter().fold(0, |a, (_, c)| { - chonk_cnt += 1; - a + c.sub_chunks_len() - }); - self.metrics.chonks_count.set(chonk_cnt as i64); - self.metrics.chunks_count.set(chunk_cnt as i64); + self.metrics + .time_of_day + .set(self.state.ecs().read_resource::().0); + if self.metrics.is_100th_tick() { + let mut chonk_cnt = 0; + let chunk_cnt = self.state.terrain().iter().fold(0, |a, (_, c)| { + chonk_cnt += 1; + a + c.sub_chunks_len() + }); + self.metrics.chonks_count.set(chonk_cnt as i64); + self.metrics.chunks_count.set(chunk_cnt as i64); + } //self.metrics.entity_count.set(self.state.); self.metrics .tick_time diff --git a/server/src/metrics.rs b/server/src/metrics.rs index 07f4d3a83d..8abbee9194 100644 --- a/server/src/metrics.rs +++ b/server/src/metrics.rs @@ -1,11 +1,18 @@ extern crate prometheus; extern crate prometheus_static_metric; extern crate rouille; -use prometheus::{Encoder, IntGauge, IntGaugeVec, Opts, Registry, TextEncoder}; -use rouille::router; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::thread; -use std::thread::JoinHandle; +use prometheus::{Encoder, Gauge, IntGauge, IntGaugeVec, Opts, Registry, TextEncoder}; +use rouille::{router, Server}; +use std::{ + convert::TryInto, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread, + time::{SystemTime, UNIX_EPOCH}, +}; pub struct ServerMetrics { pub chonks_count: IntGauge, @@ -14,9 +21,12 @@ pub struct ServerMetrics { pub entity_count: IntGauge, pub tick_time: IntGaugeVec, pub build_info: IntGauge, + pub start_time: IntGauge, + pub time_of_day: Gauge, pub light_count: IntGauge, - pub registry: Registry, - pub handle: Option>, + pub thread_running: Arc, + pub handle: Option>, + pub every_100th: i8, } impl ServerMetrics { @@ -35,6 +45,13 @@ impl ServerMetrics { .const_label("hash", common::util::GIT_HASH) .const_label("version", ""); let build_info = IntGauge::with_opts(opts).unwrap(); + let opts = Opts::new( + "veloren_start_time", + "start time of the server in seconds since EPOCH", + ); + let start_time = IntGauge::with_opts(opts).unwrap(); + let opts = Opts::new("time_of_day", "ingame time in ingame-seconds"); + let time_of_day = Gauge::with_opts(opts).unwrap(); let opts = Opts::new( "light_count", "number of all lights currently active on the server", @@ -57,52 +74,81 @@ impl ServerMetrics { .unwrap(); let tick_time = IntGaugeVec::from(vec); + let since_the_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards"); + start_time.set(since_the_epoch.as_secs().try_into().unwrap()); + let registry = Registry::new(); //registry.register(Box::new(chonks_count.clone())).unwrap(); registry.register(Box::new(player_online.clone())).unwrap(); registry.register(Box::new(entity_count.clone())).unwrap(); registry.register(Box::new(build_info.clone())).unwrap(); + registry.register(Box::new(start_time.clone())).unwrap(); + registry.register(Box::new(time_of_day.clone())).unwrap(); //registry.register(Box::new(light_count.clone())).unwrap(); registry.register(Box::new(chonks_count.clone())).unwrap(); registry.register(Box::new(chunks_count.clone())).unwrap(); registry.register(Box::new(tick_time.clone())).unwrap(); - prometheus::register(Box::new(player_online.clone())).unwrap(); - prometheus::register(Box::new(entity_count.clone())).unwrap(); - prometheus::register(Box::new(build_info.clone())).unwrap(); - //prometheus::register(Box::new(light_count.clone())).unwrap(); - prometheus::register(Box::new(chonks_count.clone())).unwrap(); - prometheus::register(Box::new(chunks_count.clone())).unwrap(); - prometheus::register(Box::new(tick_time.clone())).unwrap(); - let mut metrics = Self { + let thread_running = Arc::new(AtomicBool::new(true)); + let thread_running2 = thread_running.clone(); + + //TODO: make this a job + let handle = Some(thread::spawn(move || { + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 14005); + let server = Server::new(addr, move |request| { + router!(request, + (GET) (/metrics) => { + let encoder = TextEncoder::new(); + let mut buffer = vec![]; + let mf = registry.gather(); + encoder.encode(&mf, &mut buffer).unwrap(); + rouille::Response::text(String::from_utf8(buffer).unwrap()) + }, + _ => rouille::Response::empty_404() + ) + }) + .expect("Failed to start server"); + while thread_running2.load(Ordering::Relaxed) { + server.poll(); + } + })); + + Self { chonks_count, chunks_count, player_online, entity_count, tick_time, build_info, + start_time, + time_of_day, light_count, - registry, - handle: None, - }; + thread_running, + handle, + every_100th: 0, + } + } - let handle = thread::spawn(|| { - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 14005); - rouille::start_server(addr, move |request| { - router!(request, - (GET) (/metrics) => { - let encoder = TextEncoder::new(); - let mut buffer = vec![]; - let mf = prometheus::gather(); - encoder.encode(&mf, &mut buffer).unwrap(); - rouille::Response::text(String::from_utf8(buffer).unwrap()) - }, - _ => rouille::Response::empty_404() - ) - }); - }); - metrics.handle = Some(handle); - - metrics + pub fn is_100th_tick(&mut self) -> bool { + self.every_100th += 1; + if self.every_100th == 100 { + self.every_100th = 0; + true + } else { + false + } + } +} + +impl Drop for ServerMetrics { + fn drop(&mut self) { + self.thread_running.store(false, Ordering::Relaxed); + let handle = self.handle.take(); + handle + .unwrap() + .join() + .expect("Error shutting down prometheus metric exporter"); } }