From e535c66b50f1e357b03a0f74aadcb1401b37ccd8 Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Sun, 14 Jul 2024 15:40:59 +0200 Subject: [PATCH] logging and other stuff --- Cargo.lock | 365 +++++++++++++++--------- Cargo.toml | 10 +- logs/dynip-cloudflare-2024-07-14.log | 5 + logs/dynip-cloudflare-2024-07-14.log.gz | 1 + src/lib.rs | 3 + src/logging.rs | 87 ++++++ src/main.rs | 139 +++++---- src/utils.rs | 20 +- 8 files changed, 416 insertions(+), 214 deletions(-) create mode 100644 logs/dynip-cloudflare-2024-07-14.log create mode 100644 logs/dynip-cloudflare-2024-07-14.log.gz create mode 100644 src/logging.rs diff --git a/Cargo.lock b/Cargo.lock index d29837c..4b2465f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -41,61 +32,18 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -161,9 +109,9 @@ checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] name = "cc" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47de7e88bbbd467951ae7f5a6f34f70d1b4d9cfce53d5fd70f74ebe118b3db56" +checksum = "9711f33475c22aab363b05564a17d7b789bf3dfec5ebabb586adee56f0e271b5" [[package]] name = "cfg-if" @@ -186,10 +134,14 @@ dependencies = [ ] [[package]] -name = "colorchoice" -version = "1.0.1" +name = "colored" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] [[package]] name = "core-foundation" @@ -207,6 +159,23 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "destructure_traitobject" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" + [[package]] name = "dirs" version = "5.0.1" @@ -234,15 +203,17 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", + "colored", "dirs", - "env_logger", "futures", "log", + "log4rs", "netlink-packet-core", "netlink-packet-route", "netlink-sys", "reqwest", "rtnetlink", + "scopeguard", "serde", "serde_json", "tokio", @@ -258,29 +229,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_filter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -389,7 +337,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -638,12 +586,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - [[package]] name = "itoa" version = "1.0.11" @@ -659,6 +601,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -696,6 +644,43 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "serde", +] + +[[package]] +name = "log-mdc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" + +[[package]] +name = "log4rs" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +dependencies = [ + "anyhow", + "arc-swap", + "chrono", + "derivative", + "fnv", + "humantime", + "libc", + "log", + "log-mdc", + "once_cell", + "parking_lot", + "rand", + "serde", + "serde-value", + "serde_json", + "serde_yaml", + "thiserror", + "thread-id", + "typemap-ors", + "winapi", +] [[package]] name = "memchr" @@ -879,7 +864,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -906,6 +891,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -958,7 +952,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -979,6 +973,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.86" @@ -997,6 +997,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 = "redox_syscall" version = "0.5.2" @@ -1017,35 +1047,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - [[package]] name = "reqwest" version = "0.12.5" @@ -1204,9 +1205,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -1217,9 +1218,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -1234,6 +1235,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.204" @@ -1242,7 +1253,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -1277,6 +1288,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1323,6 +1347,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.71" @@ -1390,7 +1425,17 @@ checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", +] + +[[package]] +name = "thread-id" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +dependencies = [ + "libc", + "winapi", ] [[package]] @@ -1435,7 +1480,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -1558,6 +1603,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typemap-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +dependencies = [ + "unsafe-any-ors", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -1579,6 +1633,21 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unsafe-any-ors" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" +dependencies = [ + "destructure_traitobject", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -1596,12 +1665,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "vcpkg" version = "0.2.15" @@ -1644,7 +1707,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -1678,7 +1741,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1699,6 +1762,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 43a2f2f..7233ebf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,15 +7,21 @@ edition = "2021" anyhow = "1.0.86" chrono = "0.4.38" dirs = "5.0.1" -env_logger = "0.11.3" futures = "0.3.30" log = "0.4.22" netlink-packet-core = "0.7.0" netlink-packet-route = "0.19.0" netlink-sys = { version = "0.8.6", features = ["tokio"] } reqwest = { version = "0.12.5", features = ["json"] } -rtnetlink = "0.14.1" # Updated to a version compatible with netlink-packet-route v0.20.1 +rtnetlink = "0.14.1" # Updated to a version compatible with netlink-packet-route v0.20.1 serde = { version = "1.0.204", features = ["rc", "derive"] } serde_json = "1.0.120" tokio = { version = "1.38.0", features = ["full"] } toml = "0.8.14" +log4rs = { version = "1.3.0", features = [ + "console_appender", + "file_appender", + "rolling_file_appender", +] } +scopeguard = "1.2.0" +colored = "2.1.0" diff --git a/logs/dynip-cloudflare-2024-07-14.log b/logs/dynip-cloudflare-2024-07-14.log new file mode 100644 index 0000000..725a817 --- /dev/null +++ b/logs/dynip-cloudflare-2024-07-14.log @@ -0,0 +1,5 @@ +2024-07-14 15:30:54 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml +2024-07-14 15:35:23 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml +2024-07-14 15:38:03 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml +2024-07-14 15:38:18 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml +2024-07-14 15:40:38 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml diff --git a/logs/dynip-cloudflare-2024-07-14.log.gz b/logs/dynip-cloudflare-2024-07-14.log.gz new file mode 100644 index 0000000..f4ed9d8 --- /dev/null +++ b/logs/dynip-cloudflare-2024-07-14.log.gz @@ -0,0 +1 @@ +2024-07-14 15:26:30 [ERROR] Failed to find any config file, tried the paths: /home/love/Documents/Code/dynip-cloudflare/dynip-cloudflare.toml, /home/love/.config/dynip-cloudflare/config.toml diff --git a/src/lib.rs b/src/lib.rs index e9a9b05..02ed27b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,13 @@ mod cloudflare; mod config; mod public_ip; pub mod utils; +mod logging; pub use cloudflare::CloudflareClient; pub use config::{get_config_path, read_config, Config}; pub use public_ip::get_current_public_ipv4; +pub use logging::init_logger; pub const PROGRAM_NAME: &'static str = "dynip-cloudflare"; pub const MAX_ERORS_IN_ROW_DEFAULT: usize = 10; +const LOG_DIR: &str = "logs"; diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..697fd27 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,87 @@ +use chrono::Local; +use colored::*; +use log::LevelFilter; +use log4rs::append::console::{ConsoleAppender, Target}; +use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller; +use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger; +use log4rs::append::rolling_file::policy::compound::CompoundPolicy; +use log4rs::config::{Appender, Config, Root}; +use log4rs::encode::pattern::PatternEncoder; +use log4rs::encode::{self, Encode}; +use log4rs::filter::threshold::ThresholdFilter; + +use crate::{LOG_DIR, PROGRAM_NAME}; + +#[derive(Debug)] +struct ColoredPatternEncoder; + +impl ColoredPatternEncoder { + pub fn new() -> Self { + ColoredPatternEncoder {} + } +} + +impl Encode for ColoredPatternEncoder { + fn encode(&self, w: &mut dyn encode::Write, record: &log::Record) -> anyhow::Result<()> { + let now = Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); + let level = match record.level() { + log::Level::Error => record.level().to_string().red().bold(), + log::Level::Warn => record.level().to_string().yellow().bold(), + log::Level::Info => record.level().to_string().green().bold(), + log::Level::Debug => record.level().to_string().blue().bold(), + log::Level::Trace => record.level().to_string().purple().bold(), + }; + let message = record.args().to_string().cyan(); + Ok(writeln!(w, "{} [{}] {}", now.bold(), level, message)?) + } +} + +pub fn init_logger() { + let today = Local::now().format("%Y-%m-%d").to_string(); + + if std::fs::metadata(LOG_DIR).is_err() { + std::fs::create_dir(LOG_DIR).expect("Failed to create log dir"); + } + + let log_file_path = format!("{}/{}-{}.log", LOG_DIR, PROGRAM_NAME, today); + let log_file_pattern = format!("{}/{}-{}-{{}}.log", LOG_DIR, PROGRAM_NAME, today); + + let level = log::LevelFilter::Info; + + let stderr = ConsoleAppender::builder() + .encoder(Box::new(ColoredPatternEncoder::new())) + .target(Target::Stderr) + .build(); + + const TRIGGER_FILE_SIZE: u64 = 5 * 1024; // 5KB as max log file size to roll + let trigger = SizeTrigger::new(TRIGGER_FILE_SIZE); + let roller = FixedWindowRoller::builder() + .base(0) + .build(&log_file_pattern, 3) + .unwrap(); + let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller)); + + let logfile = log4rs::append::rolling_file::RollingFileAppender::builder() + .encoder(Box::new(PatternEncoder::new( + "{d(%Y-%m-%d %H:%M:%S)} [{l}] {m}\n", + ))) + .build(log_file_path, Box::new(policy)) + .unwrap(); + + let config = Config::builder() + .appender(Appender::builder().build("logfile", Box::new(logfile))) + .appender( + Appender::builder() + .filter(Box::new(ThresholdFilter::new(level))) + .build("stderr", Box::new(stderr)), + ) + .build( + Root::builder() + .appender("logfile") + .appender("stderr") + .build(LevelFilter::Trace), + ) + .unwrap(); + + log4rs::init_config(config).expect("Failed to initialize logger"); +} diff --git a/src/main.rs b/src/main.rs index 9668048..9413631 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,8 @@ +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + use futures::stream::StreamExt; use log::{debug, error, info, log_enabled, Level}; use netlink_packet_core::NetlinkPayload; @@ -6,6 +11,8 @@ use netlink_sys::{AsyncSocket, SocketAddr}; use rtnetlink::new_connection; use dynip_cloudflare::{utils, CloudflareClient, MAX_ERORS_IN_ROW_DEFAULT}; +use scopeguard::defer; +use tokio::{signal, sync::Notify}; const RTNLGRP_LINK: u32 = 1; const RTNLGRP_IPV4_IFADDR: u32 = 5; @@ -23,7 +30,24 @@ const fn nl_mgrp(group: u32) -> u32 { #[tokio::main] async fn main() { - utils::init_logger(); + dynip_cloudflare::init_logger(); + defer! { + log::logger().flush(); + } + let should_exit = Arc::new(AtomicBool::new(false)); + let notify = Arc::new(Notify::new()); + + let should_exit_clone = should_exit.clone(); + let notify_clone = notify.clone(); + + tokio::spawn(async move { + signal::ctrl_c() + .await + .expect("Failed to install CTRL+C signal handler"); + should_exit_clone.store(true, Ordering::SeqCst); + notify_clone.notify_one(); + }); + let config = if let Some(aux) = utils::get_config().await { aux } else { @@ -55,63 +79,72 @@ async fn main() { let mut errs_counter: usize = 0; let errs_max = config.max_errors_in_row.unwrap_or(MAX_ERORS_IN_ROW_DEFAULT); - while let Some((message, _)) = messages.next().await { - match message.payload { - NetlinkPayload::InnerMessage(RtnlMessage::NewAddress(msg)) => { - if log_enabled!(Level::Debug) { - debug!("New IPv4 address message: {:?}", msg); - } else { - info!("New IPv4 address"); + while !should_exit.load(Ordering::SeqCst) { + tokio::select! { + _ = notify.notified() => { + break; + } + message = messages.next() => { + if let Some((message, _)) = message { + match message.payload { + NetlinkPayload::InnerMessage(RtnlMessage::NewAddress(msg)) => { + if log_enabled!(Level::Debug) { + debug!("New IPv4 address message: {:?}", msg); + } else { + info!("New IPv4 address"); - if let Err(e) = cloudflare.check().await { - errs_counter += 1; - error!( - "Failed to check cloudflare ({}/{}): {:?}", - errs_counter, errs_max, &e - ); - if errs_counter >= errs_max { - return; + if let Err(e) = cloudflare.check().await { + errs_counter += 1; + error!( + "Failed to check cloudflare ({}/{}): {:?}", + errs_counter, errs_max, &e + ); + if errs_counter >= errs_max { + return; + } + } + } + } + NetlinkPayload::InnerMessage(RtnlMessage::DelAddress(msg)) => { + if log_enabled!(Level::Debug) { + debug!("Deleted IPv4 address message: {:?}", msg); + } else { + info!("Deleted IPv4 address"); + } + } + NetlinkPayload::InnerMessage(RtnlMessage::NewLink(link)) => { + if log_enabled!(Level::Debug) { + debug!("New link message (interface connected): {:?}", link); + } else { + info!("New link (interface connected)"); + + if let Err(e) = cloudflare.check().await { + errs_counter += 1; + error!( + "Failed to check cloudflare ({}/{}): {:?}", + errs_counter, errs_max, &e + ); + if errs_counter >= errs_max { + return; + } + } + } + } + NetlinkPayload::InnerMessage(RtnlMessage::DelLink(link)) => { + if log_enabled!(Level::Debug) { + debug!("Deleted link message (interface disconnected): {:?}", link); + } else { + info!("Deleted link (interface disconnected)"); + } + } + _ => { + if log_enabled!(Level::Debug) { + debug!("Unhandled message payload: {:?}", message.payload); + } } } } } - NetlinkPayload::InnerMessage(RtnlMessage::DelAddress(msg)) => { - if log_enabled!(Level::Debug) { - debug!("Deleted IPv4 address message: {:?}", msg); - } else { - info!("Deleted IPv4 address"); - } - } - NetlinkPayload::InnerMessage(RtnlMessage::NewLink(link)) => { - if log_enabled!(Level::Debug) { - debug!("New link message (interface connected): {:?}", link); - } else { - info!("New link (interface connected)"); - - if let Err(e) = cloudflare.check().await { - errs_counter += 1; - error!( - "Failed to check cloudflare ({}/{}): {:?}", - errs_counter, errs_max, &e - ); - if errs_counter >= errs_max { - return; - } - } - } - } - NetlinkPayload::InnerMessage(RtnlMessage::DelLink(link)) => { - if log_enabled!(Level::Debug) { - debug!("Deleted link message (interface disconnected): {:?}", link); - } else { - info!("Deleted link (interface disconnected)"); - } - } - _ => { - if log_enabled!(Level::Debug) { - debug!("Unhandled message payload: {:?}", message.payload); - } - } } } } diff --git a/src/utils.rs b/src/utils.rs index f4967e7..fe6604d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,23 +1,5 @@ -use env_logger::{Builder, Env}; -use log::{error, LevelFilter}; -use std::io::Write; - use crate::{get_config_path, read_config, Config}; - -pub fn init_logger() { - Builder::from_env(Env::default().default_filter_or("info")) - .format(|buf, record| { - writeln!( - buf, - "{} [{}] - {}", - chrono::Local::now().format("%Y:%m:%d %H:%M:%S"), - record.level(), - record.args() - ) - }) - .filter(None, LevelFilter::Info) - .init(); -} +use log::error; pub async fn get_config() -> Option { let config_path = match get_config_path().await {