From ede1c17f6b88c60387d55130a43ec85888d31db1 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 9 Jul 2023 21:38:33 +0200 Subject: [PATCH 01/10] Save stats to influxdb2 --- .gitignore | 1 + Cargo.lock | 1025 ++++++++++++++++++++++++++++++++++++- server/Cargo.toml | 5 +- server/src/arg_handler.rs | 4 + server/src/codec/mod.rs | 2 +- server/src/influxdb.rs | 104 ++++ server/src/main.rs | 32 +- 7 files changed, 1167 insertions(+), 6 deletions(-) create mode 100644 server/src/influxdb.rs diff --git a/.gitignore b/.gitignore index 9c84876..6cc2001 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ **/*.rs.bk .*.swp .idea +.env diff --git a/Cargo.lock b/Cargo.lock index 913e82c..c522595 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,45 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_glue" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -45,6 +78,17 @@ dependencies = [ "syn 2.0.23", ] +[[package]] +name = "async-trait" +version = "0.1.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "atoi" version = "1.0.0" @@ -86,6 +130,18 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "bitflags" version = "1.3.2" @@ -165,6 +221,22 @@ dependencies = [ "libc", ] +[[package]] +name = "chrono" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "time", + "wasm-bindgen", + "winapi", +] + [[package]] name = "clap" version = "3.2.25" @@ -340,6 +412,27 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "cty" version = "0.2.2" @@ -381,6 +474,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -396,6 +499,18 @@ dependencies = [ "libloading 0.8.0", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "downcast-rs" version = "1.2.0" @@ -411,12 +526,63 @@ dependencies = [ "bitflags", ] +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "equivalent" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fdeflate" version = "0.3.0" @@ -457,6 +623,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + [[package]] name = "freetype-rs" version = "0.29.1" @@ -568,6 +743,17 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "gfx" version = "0.18.3" @@ -709,6 +895,31 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "go-parse-duration" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558b88954871f5e5b2af0e62e2e176c8bde7a6c2c4ed41b13d138d96da2e2cbd" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -742,12 +953,116 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys 0.8.4", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" version = "0.24.6" @@ -782,6 +1097,63 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "influxdb2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef320cb9012fe8e17f5150b09f14b6d0f6e49560c7deeab6d94b6dbbde991093" +dependencies = [ + "base64 0.13.1", + "bytes", + "chrono", + "csv", + "dotenv", + "fallible-iterator", + "futures", + "go-parse-duration", + "influxdb2-derive", + "influxdb2-structmap", + "nom", + "opentelemetry", + "ordered-float", + "parking_lot 0.11.2", + "reqwest", + "secrecy", + "serde", + "serde_json", + "serde_qs", + "smallvec", + "snafu", + "tempfile", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "influxdb2-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990f899841aa30130fc06f7938e3cc2cbc3d5b92c03fd4b5d79a965045abcf16" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "influxdb2-structmap" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1408e712051787357e99ff732e44e8833e79cea0fabc9361018abfbff72b6265" +dependencies = [ + "chrono", + "num-traits", + "ordered-float", +] + [[package]] name = "instant" version = "0.1.12" @@ -794,6 +1166,32 @@ dependencies = [ "web-sys", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.8" @@ -853,6 +1251,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "lock_api" version = "0.4.10" @@ -878,6 +1282,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.5.0" @@ -902,6 +1315,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -926,10 +1345,28 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.5.0" @@ -1120,6 +1557,79 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91cea1dfd50064e52db033179952d18c770cbc5dfefc8eba45d619357ba3914" +dependencies = [ + "async-trait", + "dashmap", + "fnv", + "futures", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand", + "thiserror", + "tokio", + "tokio-stream", +] + +[[package]] +name = "ordered-float" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213" +dependencies = [ + "num-traits", +] + [[package]] name = "os_str_bytes" version = "6.5.1" @@ -1189,6 +1699,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pin-project" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "pin-project-lite" version = "0.2.10" @@ -1230,6 +1760,7 @@ dependencies = [ "clap", "futures", "image", + "influxdb2", "number_prefix", "parking_lot 0.12.1", "pipebuf", @@ -1259,6 +1790,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -1311,6 +1848,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "raw-window-handle" version = "0.4.3" @@ -1338,18 +1905,124 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.3.2", + "regex-syntax 0.7.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "winreg", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1362,6 +2035,38 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "core-foundation-sys 0.8.4", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys 0.8.4", + "libc", +] + [[package]] name = "serde" version = "1.0.166" @@ -1382,6 +2087,40 @@ dependencies = [ "syn 2.0.23", ] +[[package]] +name = "serde_json" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.22" @@ -1395,6 +2134,15 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shared_library" version = "0.1.9" @@ -1445,6 +2193,27 @@ dependencies = [ "wayland-protocols", ] +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "socket2" version = "0.4.9" @@ -1483,6 +2252,20 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -1518,6 +2301,42 @@ dependencies = [ "syn 2.0.23", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.29.1" @@ -1526,6 +2345,7 @@ checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", "backtrace", + "bytes", "libc", "mio", "num_cpus", @@ -1546,6 +2366,16 @@ dependencies = [ "syn 2.0.23", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -1570,6 +2400,20 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -1587,24 +2431,154 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "parking_lot 0.11.2", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unsafe-libyaml" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1636,6 +2610,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -1665,6 +2651,19 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wayland-client" version = "0.29.5" @@ -1789,6 +2788,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1897,6 +2905,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -1922,3 +2939,9 @@ name = "xml-rs" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/server/Cargo.toml b/server/Cargo.toml index d68ad41..8039ae9 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -21,7 +21,6 @@ atoi = "1.0" bufstream = "0.1" bytes = "1.1.0" clap = { version = "3.1", features = ["derive"] } -futures = "0.3.21" number_prefix = "0.4" pixelpwnr-render = { version = "0.1", path = "../render" } serde = { version = "1.0", features = ["derive"]} @@ -31,8 +30,12 @@ parking_lot = "0.12.0" image = { version = "0.24", default-features = false, features = [ "png" ] } pipebuf = "0.2" +influxdb2 = { version = "0.4", optional = true } +futures = { version = "0.3", optional = true } + [features] default = [ ] +influxdb2 = [ "dep:influxdb2", "dep:futures", "clap/env" ] [dev-dependencies] tokio-test = "0.4" diff --git a/server/src/arg_handler.rs b/server/src/arg_handler.rs index 962b667..9309259 100644 --- a/server/src/arg_handler.rs +++ b/server/src/arg_handler.rs @@ -83,6 +83,10 @@ pub struct Opts { /// Disable binary commands #[clap(long)] pub no_binary: bool, + + #[cfg(feature = "influxdb2")] + #[clap(flatten)] + pub influxdb_options: crate::influxdb::InfluxDBOptions, } macro_rules! map_duration { diff --git a/server/src/codec/mod.rs b/server/src/codec/mod.rs index 3b1aec4..f742a26 100644 --- a/server/src/codec/mod.rs +++ b/server/src/codec/mod.rs @@ -1,3 +1,4 @@ +use std::future::Future; use std::ops::DerefMut; use std::pin::Pin; use std::sync::Arc; @@ -5,7 +6,6 @@ use std::task::Poll; use std::time::{Duration, Instant}; use bytes::BytesMut; -use futures::Future; use pipebuf::PipeBuf; use pixelpwnr_render::{Color, Pixmap}; use tokio::io::{AsyncRead, AsyncWrite}; diff --git a/server/src/influxdb.rs b/server/src/influxdb.rs new file mode 100644 index 0000000..a4d876c --- /dev/null +++ b/server/src/influxdb.rs @@ -0,0 +1,104 @@ +use std::{ + sync::{atomic::AtomicBool, Arc}, + time::Duration, +}; + +use futures::TryFutureExt; +use influxdb2::models::DataPoint; + +use crate::stats::Stats; + +#[cfg(feature = "influxdb2")] +#[derive(Clone, Debug, clap::Args)] +pub struct InfluxDBOptions { + #[clap(short = 'i', long)] + pub run_influxdb: bool, + #[clap(env = "INFLUXDB_TOKEN")] + pub influxdb_api_token: String, + #[clap(env = "INFLUXDB_HOST")] + pub influxdb_host: String, + #[clap(env = "INFLUXDB_ORG")] + pub influxdb_org: String, + #[clap(env = "INFLUXDB_BUCKET")] + pub influxdb_bucket: String, + #[clap(env = "INFLUXDB_SERVER_NAME", default_value = "pixelflut")] + pub influxdb_server_name: String, + #[clap(env = "INFLUXDB_REPORTING_INTERVAL_MS", default_value = "500")] + pub influxdb_reporting_interval_ms: u64, +} + +pub struct InfluxDb { + server_name: String, + bucket: String, + stats: Arc, + reporting_interval: tokio::time::Interval, + keep_running: Arc, + inner: influxdb2::Client, +} + +impl InfluxDb { + pub async fn new( + stats: Arc, + keep_running: Arc, + options: InfluxDBOptions, + ) -> Result { + let client = influxdb2::Client::new( + options.influxdb_host, + options.influxdb_org, + options.influxdb_api_token, + ); + + let mut me = Self { + inner: client, + server_name: options.influxdb_server_name, + bucket: options.influxdb_bucket, + reporting_interval: tokio::time::interval(Duration::from_millis( + options.influxdb_reporting_interval_ms, + )), + stats, + keep_running, + }; + + me.write_stats().await?; + + Ok(me) + } + + pub async fn run(mut self) -> Result<(), String> { + while self.keep_running.load(std::sync::atomic::Ordering::Relaxed) { + self.reporting_interval.tick().await; + self.write_stats().await?; + } + + Ok(()) + } + + async fn write_stats(&mut self) -> Result<(), String> { + let bandwidth_used = self.stats.bytes_read(); + let pixels_set = self.stats.pixels(); + let clients = self.stats.clients(); + + println!("Writing stats... {bandwidth_used} bytes, {pixels_set} pixels, {clients} clients"); + + let point = |name: &str, value: usize| { + DataPoint::builder(name) + .tag("server_name", &self.server_name) + .field("value", value as f64) + .build() + .map_err(|e| format!("{e:?}")) + }; + + let points = vec![ + point("bandwidth", bandwidth_used)?, + point("pixels", pixels_set)?, + point("clients", clients)?, + ]; + + self.inner + .write(&self.bucket, futures::stream::iter(points)) + .map_err(|e| format!("{e:?}")) + .await?; + + Ok(()) + } +} diff --git a/server/src/main.rs b/server/src/main.rs index 365318c..47734c6 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -5,6 +5,9 @@ mod stat_monitor; mod stat_reporter; mod stats; +#[cfg(feature = "influxdb2")] +pub mod influxdb; + use std::{ path::PathBuf, pin::Pin, @@ -61,7 +64,19 @@ fn main() { )); } - let net_running = Arc::new(AtomicBool::new(true)); + let keep_running = Arc::new(AtomicBool::new(true)); + + #[cfg(feature = "influxdb2")] + { + // If influxdb2 is enabled and the flag is set, start the influxdb2 runner + // (or crash if that fails) + let influx = arg_handler.influxdb_options.clone(); + if influx.run_influxdb { + runtime + .block_on(start_influxdb2(influx, stats.clone(), keep_running.clone())) + .unwrap(); + } + } // Create a std threa first. Tokio's [`TcpStream::listen`] automatically sets // SO_REUSEADDR which means that it won't return an error if another program is @@ -75,7 +90,7 @@ fn main() { let net_pixmap = pixmap.clone(); let net_stats = stats.clone(); - let net_running_2 = net_running.clone(); + let net_running_2 = keep_running.clone(); let opts = arg_handler.clone().into(); let tokio_runtime = std::thread::spawn(move || { runtime.block_on(async move { @@ -85,12 +100,23 @@ fn main() { }); if !arg_handler.no_render { - render(&arg_handler, pixmap, stats, net_running); + render(&arg_handler, pixmap, stats, keep_running); } else { tokio_runtime.join().unwrap() } } +#[cfg(feature = "influxdb2")] +async fn start_influxdb2( + opts: influxdb::InfluxDBOptions, + stats: Arc, + keep_running: Arc, +) -> Result<(), String> { + let client = influxdb::InfluxDb::new(stats, keep_running, opts).await?; + tokio::spawn(client.run()); + Ok(()) +} + async fn listen( listener: std::net::TcpListener, pixmap: Arc, From 2f99c0609acfa2232eabb12a11d0ac165e843dd9 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Mon, 10 Jul 2023 18:31:54 +0200 Subject: [PATCH 02/10] Add influxdb loading/saving --- .gitignore | 1 + Cargo.lock | 239 ++++++++++++++---------------------- server/Cargo.toml | 8 +- server/src/arg_handler.rs | 98 ++++++++++++--- server/src/influxdb.rs | 141 +++++++++++++-------- server/src/main.rs | 112 +++++++++-------- server/src/stat_reporter.rs | 2 +- server/src/stats.rs | 16 ++- 8 files changed, 349 insertions(+), 268 deletions(-) diff --git a/.gitignore b/.gitignore index 6cc2001..a5a239f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .*.swp .idea .env +influxdb.yaml diff --git a/Cargo.lock b/Cargo.lock index c522595..4699136 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block" version = "0.1.6" @@ -244,7 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "indexmap 1.9.3", @@ -291,7 +297,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation 0.9.3", @@ -307,7 +313,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation 0.9.3", "core-graphics-types", @@ -360,7 +366,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation 0.7.0", "foreign-types", "libc", @@ -372,7 +378,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation 0.9.3", "core-graphics-types", "foreign-types", @@ -385,7 +391,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation 0.9.3", "libc", ] @@ -523,7 +529,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cf9537e2d06891448799b96d5a8c8083e0e90522a7fdabe6ebf4f41d79d651" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -541,6 +547,19 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.0" @@ -638,7 +657,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0589b25bed15af55e8b941aa6fdb45179b2edec35829ebf639097738a2afbe" dependencies = [ - "bitflags", + "bitflags 1.3.2", "freetype-sys", "libc", ] @@ -771,7 +790,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75fbddaef2e12b4995900539d7209d947b988a3d87ee8737484d049b526e5441" dependencies = [ - "bitflags", + "bitflags 1.3.2", "draw_state", "log", ] @@ -987,6 +1006,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -1011,19 +1036,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1183,6 +1195,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix 0.38.3", + "windows-sys", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1257,6 +1280,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "lock_api" version = "0.4.10" @@ -1349,31 +1378,13 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndk" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "jni-sys", "ndk-sys", "num_enum", @@ -1426,7 +1437,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", @@ -1439,7 +1450,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset", @@ -1557,50 +1568,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "openssl" -version = "0.10.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.23", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "opentelemetry" version = "0.13.0" @@ -1761,10 +1728,14 @@ dependencies = [ "futures", "image", "influxdb2", + "influxdb2-structmap", + "log", + "num-traits", "number_prefix", "parking_lot 0.12.1", "pipebuf", "pixelpwnr-render", + "pretty_env_logger", "serde", "serde_yaml", "tokio", @@ -1783,7 +1754,7 @@ version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", @@ -1796,6 +1767,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -1893,7 +1874,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1902,7 +1883,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1964,12 +1945,10 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1977,7 +1956,6 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-native-tls", "tokio-util", "tower-service", "url", @@ -2000,29 +1978,33 @@ version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", "windows-sys", ] [[package]] -name = "ryu" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" - -[[package]] -name = "schannel" -version = "0.1.22" +name = "rustix" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + [[package]] name = "scoped-tls" version = "1.0.1" @@ -2044,29 +2026,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" -dependencies = [ - "bitflags", - "core-foundation 0.9.3", - "core-foundation-sys 0.8.4", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" -dependencies = [ - "core-foundation-sys 0.8.4", - "libc", -] - [[package]] name = "serde" version = "1.0.166" @@ -2180,7 +2139,7 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" dependencies = [ - "bitflags", + "bitflags 1.3.2", "calloop", "dlib", "lazy_static", @@ -2262,7 +2221,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.23", "windows-sys", ] @@ -2366,16 +2325,6 @@ dependencies = [ "syn 2.0.23", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.14" @@ -2552,12 +2501,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2670,7 +2613,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" dependencies = [ - "bitflags", + "bitflags 1.3.2", "downcast-rs", "libc", "nix 0.24.3", @@ -2719,7 +2662,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "wayland-client", "wayland-commons", "wayland-scanner", @@ -2869,7 +2812,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cocoa", "core-foundation 0.9.3", "core-graphics 0.22.3", diff --git a/server/Cargo.toml b/server/Cargo.toml index 8039ae9..27fe816 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -29,13 +29,17 @@ tokio = { version = "1.17", features = ["net", "rt", "rt-multi-thread", "macros" parking_lot = "0.12.0" image = { version = "0.24", default-features = false, features = [ "png" ] } pipebuf = "0.2" +log = "0.4" +pretty_env_logger = "0.5" -influxdb2 = { version = "0.4", optional = true } +influxdb2 = { version = "0.4", optional = true, default-features = false } +influxdb2-structmap = { version = "*", optional = true } +num-traits = { version = "*", optional = true } futures = { version = "0.3", optional = true } [features] default = [ ] -influxdb2 = [ "dep:influxdb2", "dep:futures", "clap/env" ] +influxdb2 = [ "dep:influxdb2", "dep:influxdb2-structmap", "dep:num-traits", "dep:futures", "clap/env" ] [dev-dependencies] tokio-test = "0.4" diff --git a/server/src/arg_handler.rs b/server/src/arg_handler.rs index 9309259..2febfdc 100644 --- a/server/src/arg_handler.rs +++ b/server/src/arg_handler.rs @@ -1,8 +1,8 @@ -use std::net::SocketAddr; use std::path::PathBuf; use std::time::Duration; +use std::{net::SocketAddr, str::FromStr}; -use clap::Parser; +use clap::{Args, Parser}; use crate::codec::{CodecOptions, RateLimit}; @@ -28,13 +28,8 @@ pub struct Opts { #[clap(short, long)] pub fullscreen: bool, - /// The file to use for persistent stats - #[clap(long, alias = "file", value_name = "FILE")] - pub stats_file: Option, - - /// How often to save persistent stats - #[clap(long, value_name = "SECONDS", alias = "stats-save-interval")] - stats_file_interval: Option, + #[clap(flatten)] + pub stat_options: StatsOptions, /// Reporting interval of stats on screen #[clap(long, value_name = "SECONDS", alias = "stats-screen-interval")] @@ -83,10 +78,51 @@ pub struct Opts { /// Disable binary commands #[clap(long)] pub no_binary: bool, +} + +#[derive(Clone, Debug, Args)] +pub struct StatsOptions { + /// The interval at which to save stats. + #[clap(long)] + pub stats_save_interval_ms: Option, + + /// If this is set, the stats will be loaded using the provided + /// method. + #[cfg_attr(feature = "influxdb2", doc = "(Available: file, influxdb)")] + #[cfg_attr(not(feature = "influxdb2"), doc = "(Available: file)")] + #[clap(long)] + pub load_on_start: Option, + + /// The path that the stats should be saved to, and optionally loaded + /// from if `load-on-startup` is `file`. + pub stats_file: Option, + /// The YAML configuration file describing to what influxdb2 the + /// stats should be written (over HTTP) #[cfg(feature = "influxdb2")] - #[clap(flatten)] - pub influxdb_options: crate::influxdb::InfluxDBOptions, + #[clap(long)] + stats_influxdb_config: Option, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum StatsSaveMethod { + File, + #[cfg(feature = "influxdb2")] + Influxdb, +} + +impl FromStr for StatsSaveMethod { + type Err = String; + + fn from_str(s: &str) -> Result { + let method = match s.to_ascii_lowercase().as_str() { + "file" => Self::File, + #[cfg(feature = "influxdb2")] + "influxdb" => Self::Influxdb, + _ => return Err(format!("Unknown save method {s}")), + }; + Ok(method) + } } macro_rules! map_duration { @@ -95,6 +131,41 @@ macro_rules! map_duration { }; } +impl StatsOptions { + pub fn stats_save_interval(&self) -> Option { + self.stats_save_interval_ms.map(Duration::from_millis) + } +} + +#[cfg(feature = "influxdb2")] +impl StatsOptions { + pub fn influxdb_config(&self) -> Option { + let config = self.stats_influxdb_config.as_ref()?; + + let file = match std::fs::File::open(config) { + Ok(v) => v, + Err(e) => { + panic!( + "Could not open influxdb config file (\"{}\"). {e}", + config.as_os_str().to_str().unwrap() + ); + } + }; + + let options = match serde_yaml::from_reader(file) { + Ok(o) => o, + Err(e) => { + panic!( + "Failed to parse influxdb config (\"{}\"). {e}", + config.as_os_str().to_str().unwrap() + ); + } + }; + + Some(options) + } +} + impl Opts { /// Get the canvas size. pub fn size(&self) -> (usize, usize) { @@ -102,11 +173,6 @@ impl Opts { (self.width.unwrap_or(800), self.height.unwrap_or(600)) } - /// Get the stats save interval - pub fn stats_save_interval(&self) -> Option { - map_duration!(self.stats_file_interval) - } - /// Get the stats screen interval pub fn stats_screen_interval(&self) -> Option { map_duration!(self.stats_screen) diff --git a/server/src/influxdb.rs b/server/src/influxdb.rs index a4d876c..de9b5c4 100644 --- a/server/src/influxdb.rs +++ b/server/src/influxdb.rs @@ -4,81 +4,120 @@ use std::{ }; use futures::TryFutureExt; -use influxdb2::models::DataPoint; +use influxdb2::{ + models::{DataPoint, Query}, + FromDataPoint, +}; +use serde::Deserialize; use crate::stats::Stats; -#[cfg(feature = "influxdb2")] -#[derive(Clone, Debug, clap::Args)] +#[derive(Clone, Debug, Deserialize)] pub struct InfluxDBOptions { - #[clap(short = 'i', long)] - pub run_influxdb: bool, - #[clap(env = "INFLUXDB_TOKEN")] - pub influxdb_api_token: String, - #[clap(env = "INFLUXDB_HOST")] - pub influxdb_host: String, - #[clap(env = "INFLUXDB_ORG")] - pub influxdb_org: String, - #[clap(env = "INFLUXDB_BUCKET")] - pub influxdb_bucket: String, - #[clap(env = "INFLUXDB_SERVER_NAME", default_value = "pixelflut")] - pub influxdb_server_name: String, - #[clap(env = "INFLUXDB_REPORTING_INTERVAL_MS", default_value = "500")] - pub influxdb_reporting_interval_ms: u64, + pub api_token: String, + pub host: String, + pub org: String, + pub bucket: String, + pub server_name: String, } -pub struct InfluxDb { +pub struct InfluxDB { server_name: String, bucket: String, - stats: Arc, - reporting_interval: tokio::time::Interval, - keep_running: Arc, inner: influxdb2::Client, } -impl InfluxDb { - pub async fn new( +impl From for InfluxDB { + fn from(value: InfluxDBOptions) -> Self { + Self::new(value) + } +} + +impl InfluxDB { + pub fn new(options: InfluxDBOptions) -> Self { + let client = influxdb2::Client::new(options.host, options.org, options.api_token); + + Self { + inner: client, + server_name: options.server_name, + bucket: options.bucket, + } + } + + pub async fn run( + mut self, stats: Arc, keep_running: Arc, - options: InfluxDBOptions, - ) -> Result { - let client = influxdb2::Client::new( - options.influxdb_host, - options.influxdb_org, - options.influxdb_api_token, + interval: Duration, + ) -> Result<(), String> { + let mut reporting_interval = tokio::time::interval(interval); + + while keep_running.load(std::sync::atomic::Ordering::Relaxed) { + reporting_interval.tick().await; + self.write_stats(&stats).await?; + } + + Ok(()) + } + + async fn load_stat(&mut self, stat_name: &str) -> Result { + let Self { + server_name, + bucket, + inner, + } = self; + + let query = format!( + r#" + from(bucket: "{bucket}") + |> range(start: -30d) + |> filter(fn: (r) => r["_measurement"] == "{stat_name}") + |> filter(fn: (r) => r["_field"] == "value") + |> filter(fn: (r) => r["server_name"] == "{server_name}") + |> max() + "# ); - let mut me = Self { - inner: client, - server_name: options.influxdb_server_name, - bucket: options.influxdb_bucket, - reporting_interval: tokio::time::interval(Duration::from_millis( - options.influxdb_reporting_interval_ms, - )), - stats, - keep_running, - }; + let query = Query::new(query); + + #[derive(FromDataPoint, Default)] + struct Stat { + value: f64, + } - me.write_stats().await?; + let res: Vec = inner.query::(Some(query)).await.unwrap(); - Ok(me) + Ok(res.first().map(|v| v.value).unwrap_or(0.0) as u64) } - pub async fn run(mut self) -> Result<(), String> { - while self.keep_running.load(std::sync::atomic::Ordering::Relaxed) { - self.reporting_interval.tick().await; - self.write_stats().await?; + pub async fn load_stats(&mut self) -> Stats { + macro_rules! try_load { + ($name:literal) => { + match self.load_stat($name).await { + Ok(loaded_value) => { + log::info!("Loaded stat {}. Value: {loaded_value}", $name); + loaded_value + } + Err(e) => { + log::warn!("Failed to load stat {}. {e}", $name); + 0 + } + } + }; } - Ok(()) + let bandwidth = try_load!("bandwidth"); + let pixels_set = try_load!("pixels"); + + Stats::new_with(pixels_set as usize, bandwidth as usize) } - async fn write_stats(&mut self) -> Result<(), String> { - let bandwidth_used = self.stats.bytes_read(); - let pixels_set = self.stats.pixels(); - let clients = self.stats.clients(); + async fn write_stats(&mut self, stats: &Stats) -> Result<(), String> { + let bandwidth_used = stats.bytes_read(); + let pixels_set = stats.pixels(); + let clients = stats.clients(); - println!("Writing stats... {bandwidth_used} bytes, {pixels_set} pixels, {clients} clients"); + log::debug!("Sending stats to influxdb:\n\t{bandwidth_used} bytes\n\t{pixels_set} pixels\n\t{clients} clients"); let point = |name: &str, value: usize| { DataPoint::builder(name) diff --git a/server/src/main.rs b/server/src/main.rs index 47734c6..d473402 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -18,6 +18,7 @@ use std::{ time::{Duration, SystemTime}, }; +use arg_handler::StatsOptions; use clap::StructOpt; use pixelpwnr_render::{Pixmap, Renderer}; use tokio::net::{TcpListener, TcpStream}; @@ -26,27 +27,17 @@ use codec::{CodecOptions, Lines}; use stat_reporter::StatReporter; use stats::{Stats, StatsRaw}; -use crate::arg_handler::Opts; - -// TODO: use some constant for new lines +use crate::arg_handler::{Opts, StatsSaveMethod}; fn main() { - let arg_handler = Opts::parse(); - - // Build a stats manager, load persistent stats - let stats = arg_handler - .stats_file - .as_ref() - .map(|f| StatsRaw::load(f.as_path())) - .flatten() - .map(|s| Stats::from_raw(&s)) - .unwrap_or(Stats::new()); - - let stats = Arc::new(stats); - - let (width, height) = arg_handler.size(); - let pixmap = Arc::new(Pixmap::new(width, height)); - println!("Canvas size: {}x{}", width, height); + pretty_env_logger::formatted_builder() + .parse_filters( + &std::env::vars() + .find(|(n, _)| n == "RUST_LOG") + .map(|(_, v)| v) + .unwrap_or("info,gfx_device_gl=off,winit=off".to_string()), + ) + .init(); // Create a new runtime to be ran on a different (set of) OS threads // so that we don't block the runtime by running the renderer on it @@ -55,6 +46,26 @@ fn main() { .build() .unwrap(); + let arg_handler = Opts::parse(); + + let stat_save_opts = &arg_handler.stat_options; + let (width, height) = arg_handler.size(); + log::info!("Canvas size: {}x{}", width, height); + + let pixmap = Arc::new(Pixmap::new(width, height)); + let keep_running = Arc::new(AtomicBool::new(true)); + + let stats = runtime.block_on(build_stats(stat_save_opts)); + let stats = Arc::new(stats); + + #[cfg(feature = "influxdb2")] + stat_save_opts.influxdb_config().map(|c| { + if let Some(interval) = stat_save_opts.stats_save_interval() { + let client = influxdb::InfluxDB::new(c); + runtime.spawn(client.run(stats.clone(), keep_running.clone(), interval)); + } + }); + if let Some(dir) = arg_handler.save_dir.clone() { let pixmap = pixmap.clone(); runtime.spawn(spawn_save_image( @@ -64,20 +75,6 @@ fn main() { )); } - let keep_running = Arc::new(AtomicBool::new(true)); - - #[cfg(feature = "influxdb2")] - { - // If influxdb2 is enabled and the flag is set, start the influxdb2 runner - // (or crash if that fails) - let influx = arg_handler.influxdb_options.clone(); - if influx.run_influxdb { - runtime - .block_on(start_influxdb2(influx, stats.clone(), keep_running.clone())) - .unwrap(); - } - } - // Create a std threa first. Tokio's [`TcpStream::listen`] automatically sets // SO_REUSEADDR which means that it won't return an error if another program is // already listening on our port/address. Weird. @@ -86,12 +83,13 @@ fn main() { Ok(v) => v, Err(e) => panic!("Failed to bind to address {:?}. Error: {:?}", &host, e), }; - println!("Listening on: {}", host); + log::info!("Listening on: {}", host); let net_pixmap = pixmap.clone(); let net_stats = stats.clone(); let net_running_2 = keep_running.clone(); let opts = arg_handler.clone().into(); + let tokio_runtime = std::thread::spawn(move || { runtime.block_on(async move { listen(listener, net_pixmap, net_stats, opts).await; @@ -106,15 +104,33 @@ fn main() { } } -#[cfg(feature = "influxdb2")] -async fn start_influxdb2( - opts: influxdb::InfluxDBOptions, - stats: Arc, - keep_running: Arc, -) -> Result<(), String> { - let client = influxdb::InfluxDb::new(stats, keep_running, opts).await?; - tokio::spawn(client.run()); - Ok(()) +async fn build_stats(stat_opts: &StatsOptions) -> Stats { + match stat_opts.load_on_start { + Some(StatsSaveMethod::File) => { + if let Some(path) = &stat_opts.stats_file { + StatsRaw::load(path.as_path()) + .as_ref() + .map(Stats::from_raw) + .unwrap_or(Stats::new()) + } else { + log::warn!("stat loading is set to be from file, but stats file was not provided. Continuing with empty stats."); + Stats::new() + } + } + #[cfg(feature = "influxdb2")] + Some(StatsSaveMethod::Influxdb) => { + if let Some(influxdb_config) = stat_opts.influxdb_config() { + let mut client = influxdb::InfluxDB::new(influxdb_config); + client.load_stats().await + } else { + log::warn!( + "stat loading is set to be from influxdb, but influxdb config was not provided. Continuing with empty stats." + ); + Stats::new() + } + } + None => Stats::new(), + } } async fn listen( @@ -131,7 +147,7 @@ async fn listen( let (socket, _) = if let Ok(res) = listener.accept().await { res } else { - println!("Failed to accept a connection"); + log::warn!("Failed to accept a connection"); continue; }; handle_socket(socket, pixmap_worker, stats_worker, opts); @@ -177,7 +193,7 @@ fn handle_socket( ) { // A client connected, ensure we're able to get it's address let addr = socket.peer_addr().expect("failed to get remote address"); - println!("A client connected (from: {})", addr); + log::info!("A client connected (from: {})", addr); // Increase the number of clients stats.inc_clients(); @@ -198,7 +214,7 @@ fn handle_socket( let result = lines.await; // Print a disconnect message - println!("A client disconnected (from: {}). Reason: {}", addr, result); + log::info!("A client disconnected (from: {}). Reason: {}", addr, result); // Decreasde the client connections number disconnect_stats.dec_clients(); @@ -222,8 +238,8 @@ fn render( let reporter = StatReporter::new( arg_handler.stats_screen_interval(), arg_handler.stats_stdout_interval(), - arg_handler.stats_save_interval(), - arg_handler.stats_file.clone(), + arg_handler.stat_options.stats_save_interval(), + arg_handler.stat_options.stats_file.clone(), stats, Some(stats_text), ); diff --git a/server/src/stat_reporter.rs b/server/src/stat_reporter.rs index 186ddc3..7dce471 100644 --- a/server/src/stat_reporter.rs +++ b/server/src/stat_reporter.rs @@ -152,7 +152,7 @@ impl StatReporter { // Report stats to the stdout if last.is_none() || elapsed >= interval { // Create a raw stats instance - println!("Saving persistent stats..."); + log::debug!("Saving persistent stats..."); let raw = stats.to_raw(); // Save the raw stats diff --git a/server/src/stats.rs b/server/src/stats.rs index 2ef4374..4655ffa 100644 --- a/server/src/stats.rs +++ b/server/src/stats.rs @@ -47,6 +47,18 @@ impl Stats { } } + /// Construct a new stats object. + #[cfg(feature = "influxdb2")] + pub fn new_with(pixels: usize, bytes_read: usize) -> Self { + Stats { + pixels: AtomicUsize::new(pixels), + pixels_monitor: Mutex::new(StatMonitor::new()), + clients: AtomicUsize::new(0), + bytes_read: AtomicUsize::new(bytes_read), + bytes_read_monitor: Mutex::new(StatMonitor::new()), + } + } + /// Get the total number of clients currently connected. pub fn clients(&self) -> usize { self.clients.load(Ordering::Relaxed) @@ -240,7 +252,7 @@ impl StatsRaw { pub fn load(path: &Path) -> Option { // Make sure the file exists if !path.is_file() { - println!("Not loading persistent stats, file not found"); + log::warn!("Not loading persistent stats, file not found"); return None; } @@ -254,7 +266,7 @@ impl StatsRaw { // Load the raw state return serde_yaml::from_str(&data) - .map_err(|_| println!("failed to load persistent stats, malformed data")) + .map_err(|_| log::warn!("failed to load persistent stats, malformed data")) .ok(); } From adf95e0891a42246cad40dbb215ddb2e20d79657 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Mon, 10 Jul 2023 18:33:31 +0200 Subject: [PATCH 03/10] Don't need this --- server/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index 27fe816..abc8692 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -39,7 +39,7 @@ futures = { version = "0.3", optional = true } [features] default = [ ] -influxdb2 = [ "dep:influxdb2", "dep:influxdb2-structmap", "dep:num-traits", "dep:futures", "clap/env" ] +influxdb2 = [ "dep:influxdb2", "dep:influxdb2-structmap", "dep:num-traits", "dep:futures" ] [dev-dependencies] tokio-test = "0.4" From 02c61a746911f31c5747f70cdf126e97f9164077 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Mon, 10 Jul 2023 20:51:17 +0200 Subject: [PATCH 04/10] Run the influxdb reporter in StatsReporter --- server/Cargo.toml | 2 +- server/src/influxdb.rs | 23 +---- server/src/main.rs | 44 ++++---- server/src/stat_reporter.rs | 198 ++++++++++++++++-------------------- 4 files changed, 114 insertions(+), 153 deletions(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index abc8692..b1aa52c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -38,7 +38,7 @@ num-traits = { version = "*", optional = true } futures = { version = "0.3", optional = true } [features] -default = [ ] +default = [ "influxdb2" ] influxdb2 = [ "dep:influxdb2", "dep:influxdb2-structmap", "dep:num-traits", "dep:futures" ] [dev-dependencies] diff --git a/server/src/influxdb.rs b/server/src/influxdb.rs index de9b5c4..667ffc0 100644 --- a/server/src/influxdb.rs +++ b/server/src/influxdb.rs @@ -1,8 +1,3 @@ -use std::{ - sync::{atomic::AtomicBool, Arc}, - time::Duration, -}; - use futures::TryFutureExt; use influxdb2::{ models::{DataPoint, Query}, @@ -44,22 +39,6 @@ impl InfluxDB { } } - pub async fn run( - mut self, - stats: Arc, - keep_running: Arc, - interval: Duration, - ) -> Result<(), String> { - let mut reporting_interval = tokio::time::interval(interval); - - while keep_running.load(std::sync::atomic::Ordering::Relaxed) { - reporting_interval.tick().await; - self.write_stats(&stats).await?; - } - - Ok(()) - } - async fn load_stat(&mut self, stat_name: &str) -> Result { let Self { server_name, @@ -112,7 +91,7 @@ impl InfluxDB { Stats::new_with(pixels_set as usize, bandwidth as usize) } - async fn write_stats(&mut self, stats: &Stats) -> Result<(), String> { + pub async fn write_stats(&mut self, stats: &Stats) -> Result<(), String> { let bandwidth_used = stats.bytes_read(); let pixels_set = stats.pixels(); let clients = stats.clients(); diff --git a/server/src/main.rs b/server/src/main.rs index d473402..5a716dc 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -58,14 +58,6 @@ fn main() { let stats = runtime.block_on(build_stats(stat_save_opts)); let stats = Arc::new(stats); - #[cfg(feature = "influxdb2")] - stat_save_opts.influxdb_config().map(|c| { - if let Some(interval) = stat_save_opts.stats_save_interval() { - let client = influxdb::InfluxDB::new(c); - runtime.spawn(client.run(stats.clone(), keep_running.clone(), interval)); - } - }); - if let Some(dir) = arg_handler.save_dir.clone() { let pixmap = pixmap.clone(); runtime.spawn(spawn_save_image( @@ -90,6 +82,8 @@ fn main() { let net_running_2 = keep_running.clone(); let opts = arg_handler.clone().into(); + let renderer = build_renderer(&arg_handler, pixmap, stats, keep_running, &runtime); + let tokio_runtime = std::thread::spawn(move || { runtime.block_on(async move { listen(listener, net_pixmap, net_stats, opts).await; @@ -98,7 +92,7 @@ fn main() { }); if !arg_handler.no_render { - render(&arg_handler, pixmap, stats, keep_running); + renderer(); } else { tokio_runtime.join().unwrap() } @@ -222,12 +216,13 @@ fn handle_socket( } /// Start the pixel map renderer. -fn render( - arg_handler: &Opts, +fn build_renderer<'a>( + arg_handler: &'a Opts, pixmap: Arc, stats: Arc, net_running: Arc, -) { + runtime: &tokio::runtime::Runtime, +) -> impl FnOnce() -> () + 'a { // Build the renderer let renderer = Renderer::new(env!("CARGO_PKG_NAME"), pixmap); @@ -242,16 +237,23 @@ fn render( arg_handler.stat_options.stats_file.clone(), stats, Some(stats_text), + #[cfg(feature = "influxdb2")] + arg_handler + .stat_options + .influxdb_config() + .map(|c| influxdb::InfluxDB::new(c)), ); - reporter.start(); + runtime.spawn(reporter.run()); // Render the canvas - renderer.run( - arg_handler.fullscreen, - arg_handler.stats_font_size, - arg_handler.stats_offset(), - arg_handler.stats_padding, - arg_handler.stats_col_spacing, - net_running, - ); + || { + renderer.run( + arg_handler.fullscreen, + arg_handler.stats_font_size, + arg_handler.stats_offset(), + arg_handler.stats_padding, + arg_handler.stats_col_spacing, + net_running, + ) + } } diff --git a/server/src/stat_reporter.rs b/server/src/stat_reporter.rs index 7dce471..8548f34 100644 --- a/server/src/stat_reporter.rs +++ b/server/src/stat_reporter.rs @@ -2,8 +2,7 @@ use parking_lot::Mutex; use std::cmp::min; use std::path::PathBuf; use std::sync::Arc; -use std::thread::{self, sleep}; -use std::time::{Duration, SystemTime}; +use std::time::{Duration, Instant}; use crate::stats::Stats; @@ -17,27 +16,22 @@ pub struct StatReporter { /// If none, no screen stats should be reported. stdout_interval: Option, - /// The interval to save the persistent file with. + /// The interval to save the persistent file and/or influxdb2 with. /// If none, no stats will be saved. save_interval: Option, /// The file to save persistent stats to. save_path: Option, - /// The last time the screen stats were updated. - screen_last: Arc>>, - - /// The last time the stdout stats were updated. - stdout_last: Arc>>, - - /// The last time the stats were saved. - save_last: Arc>>, - /// A stats manager. stats: Arc, /// A string mutex for text on the screen. - screen: Arc>>>, + screen: Option>>, + + /// The InfluxDB client to report stats to + #[cfg(feature = "influxdb2")] + influxdb_client: Option, } impl StatReporter { @@ -49,136 +43,122 @@ impl StatReporter { save_path: Option, stats: Arc, screen: Option>>, + #[cfg(feature = "influxdb2")] influxdb_client: Option, ) -> Self { StatReporter { screen_interval, stdout_interval, save_interval, save_path, - screen_last: Arc::new(Mutex::new(None)), - stdout_last: Arc::new(Mutex::new(None)), - save_last: Arc::new(Mutex::new(None)), stats, - screen: Arc::new(screen), + screen: screen, + #[cfg(feature = "influxdb2")] + influxdb_client, } } /// Start the reporter, and spawn a thread internally which controls the /// reporting. - pub fn start(&self) { + pub async fn run(mut self) { // Do not actually start a thread if there is nothing to report - if self.screen_interval.is_none() && self.stdout_interval.is_none() { + let should_stop = self.screen_interval.is_none() && self.stdout_interval.is_none(); + + #[cfg(feature = "influxdb2")] + let should_stop = should_stop && self.influxdb_client.is_none(); + + if should_stop { return; } // Clone the arcs for use in the reporter thread - let stats = self.stats.clone(); - let screen = self.screen.clone(); - let screen_interval = self.screen_interval.clone(); - let stdout_interval = self.stdout_interval.clone(); - let save_interval = self.save_interval.clone(); - let screen_last = self.screen_last.clone(); - let stdout_last = self.stdout_last.clone(); - let save_last = self.save_last.clone(); - let save_path = self.save_path.clone(); + let mut screen_last = Instant::now(); + let mut stdout_last = Instant::now(); + let mut save_last = Instant::now(); // Update the statistics text each second in a separate thread - thread::spawn(move || { - loop { - // When the next update should happen, at least once a second - let mut next_update = Duration::from_secs(1); - - // Check the screen update time - if let Some(interval) = screen_interval { - // Get the last screen time - let mut last = screen_last.lock(); - - // Get the number of elapsed seconds since the last report - let elapsed = last - .map(|last| last.elapsed().ok()) - .unwrap_or(None) - .unwrap_or(Duration::from_secs(0)); - - // Report stats to the screen - if last.is_none() || elapsed >= interval { - if let Some(ref screen) = *screen { - Self::report_screen(&stats, screen); - *last = Some(SystemTime::now()); - } - } - // See how long we should take, update the next update time - next_update = min( - next_update, - interval.checked_sub(elapsed).unwrap_or(interval), - ); - } + loop { + // When the next update should happen, at least once a second + let mut next_update = Duration::from_secs(1); - // Check the stdout update time - if let Some(interval) = stdout_interval { - // Get the last stdout time - let mut last = stdout_last.lock(); - - // Get the number of elapsed seconds since the last report - let elapsed = last - .map(|last| last.elapsed().ok()) - .unwrap_or(None) - .unwrap_or(Duration::from_secs(0)); - - // Report stats to the stdout - if last.is_none() || elapsed >= interval { - Self::report_stdout(&stats); - *last = Some(SystemTime::now()); + // Check the screen update time + if let Some(interval) = self.screen_interval { + // Get the number of elapsed seconds since the last report + let elapsed = screen_last.elapsed(); + + // Report stats to the screen + if elapsed >= interval { + if let Some(screen) = &self.screen { + Self::report_screen(&self.stats, &mut screen.lock()); + screen_last = Instant::now(); } + } - // See how long we should take, update the next update time - next_update = min( - next_update, - interval.checked_sub(elapsed).unwrap_or(interval), - ); + // See how long we should take, update the next update time + next_update = min( + next_update, + interval.checked_sub(elapsed).unwrap_or(interval), + ); + } + + // Check the stdout update time + if let Some(interval) = self.stdout_interval { + // Get the number of elapsed seconds since the last report + let elapsed = stdout_last.elapsed(); + + // Report stats to the stdout + if elapsed >= interval { + Self::report_stdout(&self.stats); + stdout_last = Instant::now(); } - // Check the stats save update time - if let Some(interval) = save_interval { - // Get the last save time - let mut last = save_last.lock(); - - // Get the number of elapsed seconds since the last save - let elapsed = last - .map(|last| last.elapsed().ok()) - .unwrap_or(None) - .unwrap_or(Duration::from_secs(0)); - - // Report stats to the stdout - if last.is_none() || elapsed >= interval { - // Create a raw stats instance - log::debug!("Saving persistent stats..."); - let raw = stats.to_raw(); - - // Save the raw stats - if let Some(save_path) = &save_path { - raw.save(save_path.as_path()) - } + // See how long we should take, update the next update time + next_update = min( + next_update, + interval.checked_sub(elapsed).unwrap_or(interval), + ); + } + + // Check the stats save update time + if let Some(interval) = self.save_interval { + // Get the number of elapsed seconds since the last save + let elapsed = save_last.elapsed(); + + // Report stats to the stdout + if elapsed >= interval { + // Create a raw stats instance + log::debug!("Saving persistent stats..."); + let raw = self.stats.to_raw(); - *last = Some(SystemTime::now()); + // Save the raw stats + if let Some(save_path) = &self.save_path { + raw.save(save_path.as_path()) } - // See how long we should take, update the next update time - next_update = min( - next_update, - interval.checked_sub(elapsed).unwrap_or(interval), - ); + if let Some(client) = &mut self.influxdb_client { + if let Err(e) = client.write_stats(&self.stats).await { + log::error!("Failed to write stats to influxdb: {e}"); + } + } + + save_last = Instant::now(); } - // Sleep for the specified duration - sleep(next_update); + // See how long we should take, update the next update time + next_update = min( + next_update, + interval.checked_sub(elapsed).unwrap_or(interval), + ); } - }); + + // Sleep for the specified duration + tokio::time::sleep(next_update).await; + } } /// Report the stats to the screen. - fn report_screen(stats: &Arc, screen: &Arc>) { - *screen.lock() = format!( + fn report_screen(stats: &Stats, screen: &mut String) { + *screen = format!( "CONNECT WITH: \tpx:\t{}\t{}\tclients: {}\ntelnet localhost 1234 \tin:\t{}\t{}", stats.pixels_human(), stats.pixels_sec_human(), From 4540b25014f6f75ff6a632e049cdb557862c3f55 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Tue, 11 Jul 2023 18:54:59 +0200 Subject: [PATCH 05/10] log::error and std::process::exit instead --- server/src/arg_handler.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/src/arg_handler.rs b/server/src/arg_handler.rs index 2febfdc..e69c978 100644 --- a/server/src/arg_handler.rs +++ b/server/src/arg_handler.rs @@ -100,7 +100,7 @@ pub struct StatsOptions { /// The YAML configuration file describing to what influxdb2 the /// stats should be written (over HTTP) #[cfg(feature = "influxdb2")] - #[clap(long)] + #[clap(long = "influxdb-config")] stats_influxdb_config: Option, } @@ -145,20 +145,22 @@ impl StatsOptions { let file = match std::fs::File::open(config) { Ok(v) => v, Err(e) => { - panic!( + log::error!( "Could not open influxdb config file (\"{}\"). {e}", config.as_os_str().to_str().unwrap() ); + std::process::exit(1); } }; let options = match serde_yaml::from_reader(file) { Ok(o) => o, Err(e) => { - panic!( + log::error!( "Failed to parse influxdb config (\"{}\"). {e}", config.as_os_str().to_str().unwrap() ); + std::process::exit(1); } }; @@ -189,7 +191,8 @@ impl Opts { let mut parts = lower_case.split("x"); if parts.clone().count() != 2 { - panic!("Invalid stats offset"); + log::error!("Invalid stats offset"); + std::process::exit(1); } ( From d440cb2c74d9490fa5e21e6d5b25ddceaee85827 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Jul 2023 17:27:39 +0200 Subject: [PATCH 06/10] Improve doc --- server/src/arg_handler.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/arg_handler.rs b/server/src/arg_handler.rs index e69c978..94fb03d 100644 --- a/server/src/arg_handler.rs +++ b/server/src/arg_handler.rs @@ -88,8 +88,9 @@ pub struct StatsOptions { /// If this is set, the stats will be loaded using the provided /// method. - #[cfg_attr(feature = "influxdb2", doc = "(Available: file, influxdb)")] - #[cfg_attr(not(feature = "influxdb2"), doc = "(Available: file)")] + /// + /// Available: file + #[cfg_attr(feature = "influxdb2", doc = ", influxdb")] #[clap(long)] pub load_on_start: Option, From 2a7841d5caebb70db30c53c6e05ec0be52436f76 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Jul 2023 17:28:12 +0200 Subject: [PATCH 07/10] Missed this --- server/src/main.rs | 21 +++++++++++++++------ server/src/stat_reporter.rs | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index 5a716dc..f69944e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -29,6 +29,8 @@ use stats::{Stats, StatsRaw}; use crate::arg_handler::{Opts, StatsSaveMethod}; +const LOG_TARGET: &str = "pixelpwnr"; + fn main() { pretty_env_logger::formatted_builder() .parse_filters( @@ -50,7 +52,7 @@ fn main() { let stat_save_opts = &arg_handler.stat_options; let (width, height) = arg_handler.size(); - log::info!("Canvas size: {}x{}", width, height); + log::info!(target: LOG_TARGET, "Canvas size: {}x{}", width, height); let pixmap = Arc::new(Pixmap::new(width, height)); let keep_running = Arc::new(AtomicBool::new(true)); @@ -75,7 +77,7 @@ fn main() { Ok(v) => v, Err(e) => panic!("Failed to bind to address {:?}. Error: {:?}", &host, e), }; - log::info!("Listening on: {}", host); + log::info!(target: LOG_TARGET, "Listening on: {}", host); let net_pixmap = pixmap.clone(); let net_stats = stats.clone(); @@ -107,7 +109,10 @@ async fn build_stats(stat_opts: &StatsOptions) -> Stats { .map(Stats::from_raw) .unwrap_or(Stats::new()) } else { - log::warn!("stat loading is set to be from file, but stats file was not provided. Continuing with empty stats."); + log::warn!( + target: LOG_TARGET, + "stat loading is set to be from file, but stats file was not provided. Continuing with empty stats." + ); Stats::new() } } @@ -118,6 +123,7 @@ async fn build_stats(stat_opts: &StatsOptions) -> Stats { client.load_stats().await } else { log::warn!( + target: LOG_TARGET, "stat loading is set to be from influxdb, but influxdb config was not provided. Continuing with empty stats." ); Stats::new() @@ -141,7 +147,10 @@ async fn listen( let (socket, _) = if let Ok(res) = listener.accept().await { res } else { - log::warn!("Failed to accept a connection"); + log::warn!( + target: LOG_TARGET, + "Failed to accept a connection" + ); continue; }; handle_socket(socket, pixmap_worker, stats_worker, opts); @@ -187,7 +196,7 @@ fn handle_socket( ) { // A client connected, ensure we're able to get it's address let addr = socket.peer_addr().expect("failed to get remote address"); - log::info!("A client connected (from: {})", addr); + log::info!(target: LOG_TARGET, "A client connected (from: {})", addr); // Increase the number of clients stats.inc_clients(); @@ -208,7 +217,7 @@ fn handle_socket( let result = lines.await; // Print a disconnect message - log::info!("A client disconnected (from: {}). Reason: {}", addr, result); + log::info!(target: LOG_TARGET, "A client disconnected (from: {}). Reason: {}", addr, result); // Decreasde the client connections number disconnect_stats.dec_clients(); diff --git a/server/src/stat_reporter.rs b/server/src/stat_reporter.rs index 8548f34..79a6fb6 100644 --- a/server/src/stat_reporter.rs +++ b/server/src/stat_reporter.rs @@ -59,6 +59,7 @@ impl StatReporter { /// Start the reporter, and spawn a thread internally which controls the /// reporting. + #[cfg_attr(not(feature = "influxdb2"), allow(unused_mut))] pub async fn run(mut self) { // Do not actually start a thread if there is nothing to report let should_stop = self.screen_interval.is_none() && self.stdout_interval.is_none(); @@ -135,6 +136,7 @@ impl StatReporter { raw.save(save_path.as_path()) } + #[cfg(feature = "influxdb2")] if let Some(client) = &mut self.influxdb_client { if let Err(e) = client.write_stats(&self.stats).await { log::error!("Failed to write stats to influxdb: {e}"); From 33564126ee669224c436f476b41ce040bfe0795b Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Jul 2023 17:35:03 +0200 Subject: [PATCH 08/10] Update Cargo.lock --- Cargo.lock | 76 +++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4699136..cb7eb08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -86,7 +86,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -562,9 +562,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -729,7 +729,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1202,7 +1202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.3", + "rustix 0.38.4", "windows-sys", ] @@ -1683,7 +1683,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1813,9 +1813,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -1894,8 +1894,8 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.2", - "regex-syntax 0.7.3", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1909,13 +1909,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1926,9 +1926,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" @@ -1988,9 +1988,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.3" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.3.3", "errno", @@ -2028,29 +2028,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.166" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.166" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" dependencies = [ "itoa", "ryu", @@ -2202,9 +2202,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -2242,22 +2242,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -2322,7 +2322,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -2406,7 +2406,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -2549,7 +2549,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-shared", ] @@ -2583,7 +2583,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2841,9 +2841,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" dependencies = [ "memchr", ] From 38faffa71f62148bdf0bd902156470bd1c44b459 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Jul 2023 17:52:14 +0200 Subject: [PATCH 09/10] Add influxdb2 notes --- README.md | 22 ++++++++++++++++++++++ server/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b1966be..f59bb42 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,28 @@ under heavy load: - Increase the [file descriptor limit][filedescriptorlimit] (on Linux). - Quit as many other running programs. +# InfluxDB 2 reporting + +This server can also report some statistics (total bytes read from clients, total pixels updated, total clients connected) to an Influx DB 2 instance. + +To use it, compile the binary with the `influxdb2` feature, provide the `--influxdb-config` option pointing to a file, and set `--stats-save-interval-ms`. + +If you wish to report stats over TLS, you will also have to activate one of [`influxdb2`'s TLS features](https://docs.rs/crate/influxdb2/latest/features). + +```yaml +# influxdb.yaml +# The host to connect to +host: "http://influxdb:8086" +# The API token to use when reading and writing +api_token: "NDa6sIh2oei8oy-QPwpEKt6YhN3eeTC4Na-7HRoKzht9uePnxo-wSYVDgr73WWj1DEYonVWsWP7aG58hFJThWQ==" +# The organization that the bucket belongs to +org: "Home" +# The bucket to place the data in +bucket: "pixelflut" +# The server_name to tag up- and downloaded data with +server_name: "pixelflut" +``` + ## Relevant projects * [pixelpwnr (client)][pixelpwnr] diff --git a/server/Cargo.toml b/server/Cargo.toml index b1aa52c..abc8692 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -38,7 +38,7 @@ num-traits = { version = "*", optional = true } futures = { version = "0.3", optional = true } [features] -default = [ "influxdb2" ] +default = [ ] influxdb2 = [ "dep:influxdb2", "dep:influxdb2-structmap", "dep:num-traits", "dep:futures" ] [dev-dependencies] From 2afb2911da32f1add5f4b14f3a17a033cf5c0942 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Jul 2023 17:53:29 +0200 Subject: [PATCH 10/10] OK don't do this --- server/src/main.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index f69944e..f5fd7f8 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -29,8 +29,6 @@ use stats::{Stats, StatsRaw}; use crate::arg_handler::{Opts, StatsSaveMethod}; -const LOG_TARGET: &str = "pixelpwnr"; - fn main() { pretty_env_logger::formatted_builder() .parse_filters( @@ -52,7 +50,7 @@ fn main() { let stat_save_opts = &arg_handler.stat_options; let (width, height) = arg_handler.size(); - log::info!(target: LOG_TARGET, "Canvas size: {}x{}", width, height); + log::info!("Canvas size: {}x{}", width, height); let pixmap = Arc::new(Pixmap::new(width, height)); let keep_running = Arc::new(AtomicBool::new(true)); @@ -77,7 +75,7 @@ fn main() { Ok(v) => v, Err(e) => panic!("Failed to bind to address {:?}. Error: {:?}", &host, e), }; - log::info!(target: LOG_TARGET, "Listening on: {}", host); + log::info!("Listening on: {}", host); let net_pixmap = pixmap.clone(); let net_stats = stats.clone(); @@ -109,10 +107,7 @@ async fn build_stats(stat_opts: &StatsOptions) -> Stats { .map(Stats::from_raw) .unwrap_or(Stats::new()) } else { - log::warn!( - target: LOG_TARGET, - "stat loading is set to be from file, but stats file was not provided. Continuing with empty stats." - ); + log::warn!("stat loading is set to be from file, but stats file was not provided. Continuing with empty stats."); Stats::new() } } @@ -122,10 +117,7 @@ async fn build_stats(stat_opts: &StatsOptions) -> Stats { let mut client = influxdb::InfluxDB::new(influxdb_config); client.load_stats().await } else { - log::warn!( - target: LOG_TARGET, - "stat loading is set to be from influxdb, but influxdb config was not provided. Continuing with empty stats." - ); + log::warn!("stat loading is set to be from influxdb, but influxdb config was not provided. Continuing with empty stats."); Stats::new() } } @@ -147,10 +139,7 @@ async fn listen( let (socket, _) = if let Ok(res) = listener.accept().await { res } else { - log::warn!( - target: LOG_TARGET, - "Failed to accept a connection" - ); + log::warn!("Failed to accept a connection"); continue; }; handle_socket(socket, pixmap_worker, stats_worker, opts); @@ -196,7 +185,7 @@ fn handle_socket( ) { // A client connected, ensure we're able to get it's address let addr = socket.peer_addr().expect("failed to get remote address"); - log::info!(target: LOG_TARGET, "A client connected (from: {})", addr); + log::info!("A client connected (from: {})", addr); // Increase the number of clients stats.inc_clients(); @@ -217,7 +206,7 @@ fn handle_socket( let result = lines.await; // Print a disconnect message - log::info!(target: LOG_TARGET, "A client disconnected (from: {}). Reason: {}", addr, result); + log::info!("A client disconnected (from: {}). Reason: {}", addr, result); // Decreasde the client connections number disconnect_stats.dec_clients();