From: MatthieuCoder Date: Thu, 5 Jan 2023 14:33:53 +0000 (+0400) Subject: base for tracing X-Git-Tag: v0.1.1~42^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=038add4d5e8465f8bb36f1a1fa5817a02cab833b;p=matthieu%2Fnova.git base for tracing --- diff --git a/.env b/.env new file mode 100644 index 0000000..156276e --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +GRAFANA_SERVICE_PORT=3000 +GRAFANA_SERVICE_HOST=grafana + +# Jaeger +JAEGER_SERVICE_PORT=16686 +JAEGER_SERVICE_HOST=jaeger + +# Prometheus +PROMETHEUS_SERVICE_PORT=9090 +PROMETHEUS_SERVICE_HOST=prometheus +PROMETHEUS_ADDR=${PROMETHEUS_SERVICE_HOST}:${PROMETHEUS_SERVICE_PORT} \ No newline at end of file diff --git a/.gitignore b/.gitignore index cc5c15c..6c9334c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ target/ .ijwb .idea config.yml + +config/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 025545f..3d47207 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,25 +39,20 @@ dependencies = [ "gateway", "leash", "libc", - "pretty_env_logger", + "opentelemetry", + "opentelemetry-otlp", "ratelimit", "rest", "serde", "serde_json", "shared", "tokio", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", "webhook", ] -[[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 = "anyhow" version = "1.0.68" @@ -96,7 +91,7 @@ dependencies = [ "serde_nanos", "serde_repr", "subslice", - "time 0.3.17", + "time", "tokio", "tokio-retry", "tokio-rustls", @@ -244,17 +239,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bollard-stubs" -version = "1.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2f2e73fffe9455141e170fb9c1feb0ac521ec7e7dcd47a7cab72a658490fb8" -dependencies = [ - "chrono", - "serde", - "serde_with", -] - [[package]] name = "bumpalo" version = "3.11.1" @@ -279,14 +263,13 @@ version = "0.1.0" dependencies = [ "anyhow", "async-nats", - "futures-util", - "log", "proto", - "redis", "serde", "serde_json", "shared", "tokio", + "tokio-stream", + "tracing", "twilight-model", ] @@ -321,22 +304,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "serde", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - [[package]] name = "clap" version = "3.2.23" @@ -361,16 +328,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "combine" version = "4.6.6" @@ -450,6 +407,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -474,82 +450,16 @@ dependencies = [ ] [[package]] -name = "cxx" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.85" +name = "dashmap" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ - "cc", - "codespan-reporting", + "cfg-if", + "hashbrown", + "lock_api", "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core", - "quote", - "syn", + "parking_lot_core", ] [[package]] @@ -584,7 +494,6 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.3", "crypto-common", - "subtle", ] [[package]] @@ -624,7 +533,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.9", + "sha2", "zeroize", ] @@ -635,34 +544,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] -name = "enumflags2" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.4" +name = "env_logger" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "proc-macro2", - "quote", - "syn", + "atty", + "humantime 1.3.0", + "log", + "regex", + "termcolor", ] [[package]] name = "env_logger" -version = "0.7.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", - "humantime", + "humantime 2.1.0", + "is-terminal", "log", "regex", "termcolor", @@ -839,14 +740,20 @@ name = "gateway" version = "0.1.0" dependencies = [ "anyhow", + "async-nats", "bytes", - "futures", "leash", + "opentelemetry", + "opentelemetry-http", "proto", "serde", "serde_json", "shared", "tokio", + "tokio-stream", + "tracing", + "tracing-futures", + "tracing-opentelemetry", "twilight-gateway", "twilight-model", ] @@ -956,15 +863,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.6", -] - [[package]] name = "http" version = "0.2.8" @@ -1014,6 +912,12 @@ dependencies = [ "quick-error", ] +[[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.23" @@ -1077,36 +981,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[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.3.0" @@ -1127,12 +1001,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "inner" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9368e93322f271c5ca078ed2ddcfad3511f1a40f564e522ade34e6e5c8e6680" - [[package]] name = "instant" version = "0.1.12" @@ -1152,6 +1020,18 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys 0.42.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1207,10 +1087,16 @@ name = "leash" version = "0.1.0" dependencies = [ "anyhow", - "pretty_env_logger", + "env_logger 0.10.0", + "opentelemetry", + "opentelemetry-otlp", "serde", "shared", "tokio", + "tracing", + "tracing-log", + "tracing-opentelemetry", + "tracing-subscriber", ] [[package]] @@ -1230,15 +1116,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1270,6 +1147,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matchit" version = "0.7.0" @@ -1365,23 +1251,23 @@ dependencies = [ ] [[package]] -name = "nuid" -version = "0.3.2" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c1bb65186718d348306bf1afdeb20d9ab45b2ab80fb793c0fdcf59ffbb4f38" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "lazy_static", - "rand 0.8.5", + "overload", + "winapi", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "nuid" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "20c1bb65186718d348306bf1afdeb20d9ab45b2ab80fb793c0fdcf59ffbb4f38" dependencies = [ - "autocfg", - "num-traits", + "lazy_static", + "rand 0.8.5", ] [[package]] @@ -1460,6 +1346,98 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc79add46364183ece1a4542592ca593e6421c60807232f5b8f7a31703825d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry_api", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c928609d087790fc936a1067bdc310ae702bdf3b090c3f281b713622c8bbde" +dependencies = [ + "async-trait", + "futures", + "futures-util", + "http", + "opentelemetry", + "opentelemetry-proto", + "prost", + "thiserror", + "tokio", + "tonic", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61a2f56df5574508dd86aaca016c917489e589ece4141df1b5e349af8d66c28" +dependencies = [ + "futures", + "futures-util", + "opentelemetry", + "prost", + "tonic", + "tonic-build", +] + +[[package]] +name = "opentelemetry_api" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" +dependencies = [ + "fnv", + "futures-channel", + "futures-util", + "indexmap", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" +dependencies = [ + "async-trait", + "crossbeam-channel", + "dashmap", + "fnv", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "percent-encoding", + "rand 0.8.5", + "thiserror", + "tokio", + "tokio-stream", +] + [[package]] name = "ordered-float" version = "2.10.0" @@ -1485,6 +1463,12 @@ version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1639,16 +1623,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" -dependencies = [ - "env_logger", - "log", -] - [[package]] name = "prettyplease" version = "0.1.22" @@ -1668,36 +1642,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "procfs" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69" -dependencies = [ - "bitflags", - "byteorder", - "hex", - "lazy_static", - "rustix", -] - -[[package]] -name = "prometheus" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" -dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "libc", - "memchr", - "parking_lot", - "procfs", - "protobuf", - "thiserror", -] - [[package]] name = "prost" version = "0.11.5" @@ -1763,12 +1707,6 @@ dependencies = [ "tonic-build", ] -[[package]] -name = "protobuf" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" - [[package]] name = "quick-error" version = "1.2.3" @@ -1860,17 +1798,19 @@ name = "ratelimit" version = "0.1.0" dependencies = [ "anyhow", - "futures-util", "hyper", "leash", + "opentelemetry", + "opentelemetry-http", "proto", + "redis", "serde", - "serde_json", "shared", "tokio", "tokio-stream", "tonic", "tracing", + "tracing-opentelemetry", "twilight-http-ratelimiting 0.14.0 (git+https://github.com/MatthieuCoder/twilight.git)", ] @@ -1918,6 +1858,15 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.28" @@ -1939,24 +1888,22 @@ version = "0.1.0" dependencies = [ "anyhow", "dns-lookup", - "futures-util", "hashring", "http", "hyper", "hyper-tls", - "lazy_static", "leash", + "opentelemetry", + "opentelemetry-http", "proto", "serde", - "serde_json", "shared", "tokio", - "tokio-scoped", "tokio-stream", "tonic", "tracing", + "tracing-opentelemetry", "twilight-http-ratelimiting 0.14.0 (git+https://github.com/MatthieuCoder/twilight.git)", - "xxhash-rust", ] [[package]] @@ -2070,12 +2017,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - [[package]] name = "sct" version = "0.7.0" @@ -2171,25 +2112,12 @@ dependencies = [ ] [[package]] -name = "serde_with" -version = "1.14.0" +name = "serde_test" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "3611210d2d67e3513204742004d6ac6f589e521861dabb0f649b070eea8bed9e" dependencies = [ "serde", - "serde_with_macros", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", ] [[package]] @@ -2234,14 +2162,12 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.6" +name = "sharded-slab" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", + "lazy_static", ] [[package]] @@ -2251,18 +2177,14 @@ dependencies = [ "anyhow", "async-nats", "config", - "enumflags2", - "hyper", - "inner", - "log", - "prometheus", "redis", "serde", "serde_json", "serde_repr", - "testcontainers", + "serde_test", "thiserror", "tokio", + "tracing", "twilight-model", ] @@ -2412,23 +2334,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "testcontainers" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e2b1567ca8a2b819ea7b28c92be35d9f76fb9edb214321dcc86eb96023d1f87" -dependencies = [ - "bollard-stubs", - "futures", - "hex", - "hmac", - "log", - "rand 0.8.5", - "serde", - "serde_json", - "sha2 0.10.6", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -2456,14 +2361,12 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.45" +name = "thread_local" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "once_cell", ] [[package]] @@ -2581,16 +2484,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "tokio-scoped" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4beb8ba13bc53ac53ce1d52b42f02e5d8060f0f42138862869beb769722b256" -dependencies = [ - "tokio", - "tokio-stream", -] - [[package]] name = "tokio-stream" version = "0.1.11" @@ -2768,6 +2661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -2780,6 +2674,50 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "env_logger 0.7.1", + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de" +dependencies = [ + "once_cell", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -2892,7 +2830,7 @@ dependencies = [ "serde", "serde-value", "serde_repr", - "time 0.3.17", + "time", "tracing", ] @@ -2938,12 +2876,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -2973,6 +2905,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[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" @@ -3001,12 +2939,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[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" @@ -3082,17 +3014,17 @@ name = "webhook" version = "0.1.0" dependencies = [ "anyhow", + "async-nats", "ed25519-dalek", - "futures-util", "hex", "hyper", - "lazy_static", "leash", "proto", "serde", "serde_json", "shared", "tokio", + "tracing", "twilight-model", ] @@ -3248,12 +3180,6 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" -[[package]] -name = "xxhash-rust" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70" - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/docker-compose.yaml b/docker-compose.yaml index 2472e45..6d5ccdb 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -6,6 +6,7 @@ services: ports: - 4222:4222 - 8222:8222 + redis: image: redis @@ -17,12 +18,14 @@ services: args: - COMPONENT=cache volumes: - - ./config.yml:/config/default.yml + - ./config/default.yml:/config/default.yml environment: - - RUST_LOG=info + - RUST_LOG=debug + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 depends_on: - nats - redis + - otelcol gateway: image: ghcr.io/discordnova/nova/gateway @@ -32,13 +35,13 @@ services: args: - COMPONENT=gateway volumes: - - ./config.yml:/config/default.yml + - ./config/default.yml:/config/default.yml environment: - - RUST_LOG=info + - RUST_LOG=debug + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 depends_on: - nats - ports: - - 9000:9000 + - otelcol rest: image: ghcr.io/discordnova/nova/rest @@ -48,14 +51,16 @@ services: args: - COMPONENT=rest volumes: - - ./config.yml:/config/default.yml + - ./config/default.yml:/config/default.yml environment: - - RUST_LOG=info + - RUST_LOG=debug + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 depends_on: - ratelimit + - otelcol ports: - 9001:9000 - - 8080:8080 + - 8090:8090 webhook: image: ghcr.io/discordnova/nova/webhook @@ -63,16 +68,19 @@ services: build: context: . args: + - RUST_LOG=debug - COMPONENT=webhook volumes: - - ./config.yml:/config/default.yml + - ./config/default.yml:/config/default.yml environment: - - RUST_LOG=info + - RUST_LOG=debug + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 depends_on: - nats + - otelcol ports: - 9002:9000 - - 8081:8080 + - 8091:8091 ratelimit: image: ghcr.io/discordnova/nova/ratelimit restart: always @@ -81,12 +89,84 @@ services: args: - COMPONENT=ratelimit volumes: - - ./config.yml:/config/default.yml + - ./config/default.yml:/config/default.yml environment: - - RUST_LOG=info + - RUST_LOG=debug + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 depends_on: - nats - redis + - otelcol + + # ******************** + # Telemetry Components + # ******************** + # Jaeger + jaeger: + image: jaegertracing/all-in-one + container_name: jaeger + command: + - "--memory.max-debugs" + - "10000" + - "--query.base-path" + - "/jaeger/ui" + - "--prometheus.server-url" + - "http://${PROMETHEUS_ADDR}" + deploy: + resources: + limits: + memory: 275M + restart: always + ports: + - "${JAEGER_SERVICE_PORT}:${JAEGER_SERVICE_PORT}" # Jaeger UI + - "4317" # OTLP gRPC default port + environment: + - COLLECTOR_OTLP_ENABLED=true + - METRICS_STORAGE_TYPE=prometheus + + # Grafana + grafana: + image: grafana/grafana:9.1.0 + container_name: grafana + volumes: + - ./otel/grafana/grafana.ini:/etc/grafana/grafana.ini + - ./otel/grafana/provisioning/:/etc/grafana/provisioning/ + ports: + - "${GRAFANA_SERVICE_PORT}:${GRAFANA_SERVICE_PORT}" + + # OpenTelemetry Collector + otelcol: + image: otel/opentelemetry-collector-contrib:0.61.0 + deploy: + resources: + limits: + memory: 100M + restart: always + command: [ "--config=/etc/otelcol-config.yml", "--config=/etc/otelcol-config-extras.yml" ] + volumes: + - ./otel/otelcollector/otelcol-config.yml:/etc/otelcol-config.yml + - ./otel/otelcollector/otelcol-config-extras.yml:/etc/otelcol-config-extras.yml + ports: + - "4317:4317" # OTLP over gRPC receiver + - "4318:4318" # OTLP over HTTP receiver + - "9464" # Prometheus exporter + - "8888" # metrics endpoint + depends_on: + - jaeger + + # Prometheus + prometheus: + image: quay.io/prometheus/prometheus:v2.34.0 + container_name: prometheus + command: + - --web.console.templates=/etc/prometheus/consoles + - --web.console.libraries=/etc/prometheus/console_libraries + - --storage.tsdb.retention.time=1h + - --config.file=/etc/prometheus/prometheus-config.yaml + - --storage.tsdb.path=/prometheus + - --web.enable-lifecycle + - --web.route-prefix=/ + volumes: + - ./otel/prometheus/prometheus-config.yaml:/etc/prometheus/prometheus-config.yaml ports: - - 9003:9000 - - 8082:8080 \ No newline at end of file + - "${PROMETHEUS_SERVICE_PORT}:${PROMETHEUS_SERVICE_PORT}" diff --git a/exes/all/Cargo.toml b/exes/all/Cargo.toml index 41396fc..26e8d04 100644 --- a/exes/all/Cargo.toml +++ b/exes/all/Cargo.toml @@ -16,13 +16,19 @@ ratelimit = { path = "../ratelimit" } rest = { path = "../rest" } webhook = { path = "../webhook" } -tokio = { version = "1.23.0", features = ["full"] } +tokio = { version = "1.23.0", features = ["rt"] } serde = "1.0.152" serde_json = "1.0.91" anyhow = "1.0.68" +tracing = "0.1.37" + config = "0.13.3" -pretty_env_logger = "0.4.0" + +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +tracing-opentelemetry = "0.18.0" +opentelemetry = { version ="0.18.0", features = ["rt-tokio"] } +opentelemetry-otlp = { version = "0.11.0" } [lib] crate-type = ["staticlib"] diff --git a/exes/all/build.rs b/exes/all/build.rs index 192dffd..00d7afc 100644 --- a/exes/all/build.rs +++ b/exes/all/build.rs @@ -1,9 +1,8 @@ extern crate cbindgen; +use cbindgen::{Config, Language}; use std::env; use std::path::PathBuf; -use cbindgen::{Config, Language}; - fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -20,6 +19,6 @@ fn main() { }; cbindgen::generate_with_config(crate_dir, config) - .unwrap() - .write_to_file(output_file); + .unwrap() + .write_to_file(output_file); } diff --git a/exes/all/src/lib.rs b/exes/all/src/lib.rs index de83243..1c99109 100644 --- a/exes/all/src/lib.rs +++ b/exes/all/src/lib.rs @@ -5,14 +5,21 @@ use anyhow::Result; use config::{Config, Environment, File}; use gateway::GatewayServer; use leash::Component; +use opentelemetry::{ + global, + sdk::{propagation::TraceContextPropagator, trace, Resource}, + KeyValue, +}; +use opentelemetry_otlp::WithExportConfig; use ratelimit::RatelimiterServerComponent; use rest::ReverseProxyServer; use serde::de::DeserializeOwned; use serde_json::Value; -use shared::{config::Settings, log::info}; +use shared::config::Settings; use std::{ env, ffi::{CStr, CString}, + str::FromStr, time::Duration, }; use tokio::{ @@ -20,6 +27,11 @@ use tokio::{ sync::oneshot::{self, Sender}, task::JoinHandle, }; +use tracing::info; +use tracing_subscriber::{ + filter::Directive, fmt, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, + EnvFilter, +}; use webhook::WebhookServer; pub struct AllInOneInstance { @@ -83,9 +95,7 @@ pub extern "C" fn load_config() -> *const libc::c_char { #[no_mangle] /// Initialise les logs des composants de nova /// Utilise la crate `pretty_log_env` -pub extern "C" fn init_logs() { - pretty_env_logger::init(); -} +pub extern "C" fn init_logs() {} #[no_mangle] /// Stops a nova instance @@ -108,6 +118,29 @@ pub unsafe extern "C" fn start_instance(config: *const libc::c_char) -> *mut All // Initialize a tokio runtime let rt = Runtime::new().unwrap(); rt.block_on(async move { + global::set_text_map_propagator(TraceContextPropagator::new()); + let tracer = + opentelemetry_otlp::new_pipeline() + .tracing() + .with_trace_config(trace::config().with_resource(Resource::new(vec![ + KeyValue::new("service.name", "all-in-one"), + ]))) + .with_exporter(opentelemetry_otlp::new_exporter().tonic().with_env()) + .install_batch(opentelemetry::runtime::Tokio) + .unwrap(); + + let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); + + tracing_subscriber::registry() + .with(fmt::layer()) + .with(telemetry) + .with( + EnvFilter::builder() + .with_default_directive(Directive::from_str("info").unwrap()) + .from_env() + .unwrap(), + ) + .init(); // Start the gateway server let mut aio = vec![]; diff --git a/exes/cache/Cargo.toml b/exes/cache/Cargo.toml index 9a7f9ee..349deaa 100644 --- a/exes/cache/Cargo.toml +++ b/exes/cache/Cargo.toml @@ -8,12 +8,15 @@ edition = "2018" [dependencies] shared = { path = "../../libs/shared" } proto = { path = "../../libs/proto" } -async-nats = "0.25.1" -tokio = { version = "1", features = ["full"] } + +tokio = { version = "1", features = ["rt"] } +tokio-stream = "0.1.11" + serde = { version = "1.0.8", features = ["derive"] } -log = { version = "0.4", features = ["std"] } serde_json = { version = "1.0" } -redis = "*" -futures-util = "*" + +async-nats = "0.25.1" twilight-model = "0.14" -anyhow = "1.0.68" \ No newline at end of file +anyhow = "1.0.68" + +tracing = "0.1.37" \ No newline at end of file diff --git a/exes/cache/src/config.rs b/exes/cache/src/config.rs index 3d9f5e2..3136c1a 100644 --- a/exes/cache/src/config.rs +++ b/exes/cache/src/config.rs @@ -1,5 +1,5 @@ use serde::Deserialize; #[derive(Debug, Deserialize, Clone, Default)] pub struct CacheConfiguration { - pub toggles: Vec + pub toggles: Vec, } diff --git a/exes/cache/src/main.rs b/exes/cache/src/main.rs index 5240a6a..bc13cd5 100644 --- a/exes/cache/src/main.rs +++ b/exes/cache/src/main.rs @@ -1,8 +1,6 @@ -use std::{error::Error, pin::Pin}; +use std::{error::Error, future::Future, pin::Pin}; use async_nats::{Client, Subscriber}; -use futures_util::{stream::StreamExt, Future}; -use log::info; use managers::{ automoderation::Automoderation, bans::Bans, channels::Channels, guild_schedules::GuildSchedules, guilds::Guilds, integrations::Integrations, invites::Invites, @@ -10,6 +8,8 @@ use managers::{ stage_instances::StageInstances, threads::Threads, CacheManager, }; use shared::{config::Settings, payloads::CachePayload}; +use tokio_stream::StreamExt; +use tracing::info; use twilight_model::gateway::event::DispatchEvent; use crate::config::CacheConfiguration; @@ -43,8 +43,8 @@ async fn main() -> Result<(), Box> { let settings: Settings = Settings::new("cache").unwrap(); info!("loaded configuration: {:?}", settings); let nats = - Into::> + Send>>>::into(settings.nats).await?; - // let redis: redis::Client = settings.redis.into(); + Into::> + Send>>>::into(settings.nats) + .await?; let mut cache = Cache::default(); diff --git a/exes/cache/src/managers/channels.rs b/exes/cache/src/managers/channels.rs index fe34acc..c645420 100644 --- a/exes/cache/src/managers/channels.rs +++ b/exes/cache/src/managers/channels.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Channels {} impl CacheManager for Channels { diff --git a/exes/cache/src/managers/guild_schedules.rs b/exes/cache/src/managers/guild_schedules.rs index bcc79c5..0c565f1 100644 --- a/exes/cache/src/managers/guild_schedules.rs +++ b/exes/cache/src/managers/guild_schedules.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct GuildSchedules {} impl CacheManager for GuildSchedules { diff --git a/exes/cache/src/managers/guilds.rs b/exes/cache/src/managers/guilds.rs index 3f5f4c4..6e142c8 100644 --- a/exes/cache/src/managers/guilds.rs +++ b/exes/cache/src/managers/guilds.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Guilds {} impl CacheManager for Guilds { @@ -15,16 +14,16 @@ impl CacheManager for Guilds { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::GuildCreate(_) => {}, - DispatchEvent::GuildDelete(_) => {}, - DispatchEvent::UnavailableGuild(_) => {}, - DispatchEvent::GuildUpdate(_) => {}, - DispatchEvent::WebhooksUpdate(_) => {}, - DispatchEvent::GuildStickersUpdate(_) => {}, - DispatchEvent::GuildEmojisUpdate(_) => {}, - DispatchEvent::VoiceServerUpdate(_) => {}, - DispatchEvent::GuildIntegrationsUpdate(_) => {}, - DispatchEvent::CommandPermissionsUpdate(_) => {}, + DispatchEvent::GuildCreate(_) => {} + DispatchEvent::GuildDelete(_) => {} + DispatchEvent::UnavailableGuild(_) => {} + DispatchEvent::GuildUpdate(_) => {} + DispatchEvent::WebhooksUpdate(_) => {} + DispatchEvent::GuildStickersUpdate(_) => {} + DispatchEvent::GuildEmojisUpdate(_) => {} + DispatchEvent::VoiceServerUpdate(_) => {} + DispatchEvent::GuildIntegrationsUpdate(_) => {} + DispatchEvent::CommandPermissionsUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/integrations.rs b/exes/cache/src/managers/integrations.rs index 99d292e..8e71724 100644 --- a/exes/cache/src/managers/integrations.rs +++ b/exes/cache/src/managers/integrations.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Integrations {} impl CacheManager for Integrations { diff --git a/exes/cache/src/managers/invites.rs b/exes/cache/src/managers/invites.rs index 21da64f..6168e82 100644 --- a/exes/cache/src/managers/invites.rs +++ b/exes/cache/src/managers/invites.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Invites {} impl CacheManager for Invites { diff --git a/exes/cache/src/managers/members.rs b/exes/cache/src/managers/members.rs index 3a483f1..21e6cde 100644 --- a/exes/cache/src/managers/members.rs +++ b/exes/cache/src/managers/members.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Members {} impl CacheManager for Members { @@ -15,11 +14,11 @@ impl CacheManager for Members { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::MemberAdd(_) => {}, - DispatchEvent::MemberRemove(_) => {}, - DispatchEvent::MemberUpdate(_) => {}, - DispatchEvent::MemberChunk(_) => {}, - DispatchEvent::UserUpdate(_) => {}, + DispatchEvent::MemberAdd(_) => {} + DispatchEvent::MemberRemove(_) => {} + DispatchEvent::MemberUpdate(_) => {} + DispatchEvent::MemberChunk(_) => {} + DispatchEvent::UserUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/messages.rs b/exes/cache/src/managers/messages.rs index 7b06ae7..1725781 100644 --- a/exes/cache/src/managers/messages.rs +++ b/exes/cache/src/managers/messages.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Messages {} impl CacheManager for Messages { @@ -15,10 +14,10 @@ impl CacheManager for Messages { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::MessageCreate(_) => {}, - DispatchEvent::MessageDelete(_) => {}, - DispatchEvent::MessageDeleteBulk(_) => {}, - DispatchEvent::MessageUpdate(_) => {}, + DispatchEvent::MessageCreate(_) => {} + DispatchEvent::MessageDelete(_) => {} + DispatchEvent::MessageDeleteBulk(_) => {} + DispatchEvent::MessageUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/mod.rs b/exes/cache/src/managers/mod.rs index 370cda6..9768a86 100644 --- a/exes/cache/src/managers/mod.rs +++ b/exes/cache/src/managers/mod.rs @@ -1,22 +1,22 @@ +use std::future::Future; use std::pin::Pin; use twilight_model::gateway::event::DispatchEvent; -use std::future::Future; use crate::CacheSourcedEvents; +pub mod automoderation; +pub mod bans; pub mod channels; -pub mod guilds; pub mod guild_schedules; -pub mod stage_instances; +pub mod guilds; pub mod integrations; +pub mod invites; pub mod members; -pub mod bans; -pub mod reactions; pub mod messages; -pub mod threads; -pub mod invites; +pub mod reactions; pub mod roles; -pub mod automoderation; +pub mod stage_instances; +pub mod threads; pub trait CacheManager { fn handle(&self, event: DispatchEvent) -> Pin>>; diff --git a/exes/cache/src/managers/reactions.rs b/exes/cache/src/managers/reactions.rs index 5d21e0b..b154638 100644 --- a/exes/cache/src/managers/reactions.rs +++ b/exes/cache/src/managers/reactions.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Reactions {} impl CacheManager for Reactions { @@ -15,10 +14,10 @@ impl CacheManager for Reactions { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::ReactionAdd(_) => {}, - DispatchEvent::ReactionRemove(_) => {}, - DispatchEvent::ReactionRemoveAll(_) => {}, - DispatchEvent::ReactionRemoveEmoji(_) => {}, + DispatchEvent::ReactionAdd(_) => {} + DispatchEvent::ReactionRemove(_) => {} + DispatchEvent::ReactionRemoveAll(_) => {} + DispatchEvent::ReactionRemoveEmoji(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/roles.rs b/exes/cache/src/managers/roles.rs index 5fa0f22..c69526f 100644 --- a/exes/cache/src/managers/roles.rs +++ b/exes/cache/src/managers/roles.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct Roles {} impl CacheManager for Roles { @@ -15,9 +14,9 @@ impl CacheManager for Roles { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::RoleCreate(_) => {}, - DispatchEvent::RoleDelete(_) => {}, - DispatchEvent::RoleUpdate(_) => {}, + DispatchEvent::RoleCreate(_) => {} + DispatchEvent::RoleDelete(_) => {} + DispatchEvent::RoleUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/stage_instances.rs b/exes/cache/src/managers/stage_instances.rs index 314d089..baeabc8 100644 --- a/exes/cache/src/managers/stage_instances.rs +++ b/exes/cache/src/managers/stage_instances.rs @@ -5,7 +5,6 @@ use crate::CacheSourcedEvents; use super::CacheManager; use std::future::Future; - #[derive(Default)] pub struct StageInstances {} impl CacheManager for StageInstances { @@ -15,9 +14,9 @@ impl CacheManager for StageInstances { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::StageInstanceCreate(_) => {}, - DispatchEvent::StageInstanceDelete(_) => {}, - DispatchEvent::StageInstanceUpdate(_) => {}, + DispatchEvent::StageInstanceCreate(_) => {} + DispatchEvent::StageInstanceDelete(_) => {} + DispatchEvent::StageInstanceUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/cache/src/managers/threads.rs b/exes/cache/src/managers/threads.rs index d4efc2e..8956616 100644 --- a/exes/cache/src/managers/threads.rs +++ b/exes/cache/src/managers/threads.rs @@ -14,12 +14,12 @@ impl CacheManager for Threads { ) -> std::pin::Pin>> { Box::pin(async move { match event { - DispatchEvent::ThreadCreate(_) => {}, - DispatchEvent::ThreadDelete(_) => {}, - DispatchEvent::ThreadListSync(_) => {}, - DispatchEvent::ThreadMemberUpdate(_) => {}, - DispatchEvent::ThreadMembersUpdate(_) => {}, - DispatchEvent::ThreadUpdate(_) => {}, + DispatchEvent::ThreadCreate(_) => {} + DispatchEvent::ThreadDelete(_) => {} + DispatchEvent::ThreadListSync(_) => {} + DispatchEvent::ThreadMemberUpdate(_) => {} + DispatchEvent::ThreadMembersUpdate(_) => {} + DispatchEvent::ThreadUpdate(_) => {} _ => unreachable!(), }; diff --git a/exes/gateway/Cargo.toml b/exes/gateway/Cargo.toml index d71ed4a..a174710 100644 --- a/exes/gateway/Cargo.toml +++ b/exes/gateway/Cargo.toml @@ -7,11 +7,24 @@ edition = "2018" shared = { path = "../../libs/shared" } proto = { path = "../../libs/proto" } leash = { path = "../../libs/leash" } -tokio = { version = "1", features = ["full"] } + +tokio = { version = "1", features = ["rt", "signal"] } +tokio-stream = "0.1.11" + twilight-gateway = { version = "0.14" } twilight-model = "0.14" + +bytes = "1.3.0" +anyhow = "1.0.68" + serde = { version = "1.0.8", features = ["derive"] } -futures = "0.3" serde_json = { version = "1.0" } -bytes = "*" -anyhow = "*" \ No newline at end of file + +tracing = "0.1.37" +tracing-futures = "0.2.5" + +async-nats = "0.25.1" + +tracing-opentelemetry = "0.18.0" +opentelemetry = "0.18.0" +opentelemetry-http = "0.7.0" \ No newline at end of file diff --git a/exes/gateway/src/config.rs b/exes/gateway/src/config.rs index 923ab30..7b12bfe 100644 --- a/exes/gateway/src/config.rs +++ b/exes/gateway/src/config.rs @@ -1,4 +1,4 @@ -use shared::serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use twilight_gateway::Intents; #[derive(Serialize, Deserialize, Clone)] diff --git a/exes/gateway/src/lib.rs b/exes/gateway/src/lib.rs index d7a4cee..014b72a 100644 --- a/exes/gateway/src/lib.rs +++ b/exes/gateway/src/lib.rs @@ -1,19 +1,28 @@ +use async_nats::{Client, HeaderMap, HeaderValue}; use config::GatewayConfig; use leash::{AnyhowResultFuture, Component}; +use opentelemetry::{global, propagation::Injector}; use shared::{ config::Settings, - log::{debug, info}, - nats_crate::Client, - payloads::{CachePayload, DispatchEventTagged, Tracing}, + payloads::{CachePayload, DispatchEventTagged}, }; -use std::{convert::TryFrom, pin::Pin}; -use tokio::sync::oneshot; +use std::{convert::TryFrom, future::Future, pin::Pin, str::FromStr}; +use tokio::{select, sync::oneshot}; +use tokio_stream::StreamExt; +use tracing_opentelemetry::OpenTelemetrySpanExt; use twilight_gateway::{Event, Shard}; pub mod config; -use futures::FutureExt; -use futures::{select, Future, StreamExt}; +use tracing::{debug, info, trace_span}; use twilight_model::gateway::event::DispatchEvent; +struct MetadataMap<'a>(&'a mut HeaderMap); + +impl<'a> Injector for MetadataMap<'a> { + fn set(&mut self, key: &str, value: String) { + self.0.insert(key, HeaderValue::from_str(&value).unwrap()) + } +} + pub struct GatewayServer {} impl Component for GatewayServer { type Config = GatewayConfig; @@ -22,7 +31,7 @@ impl Component for GatewayServer { fn start( &self, settings: Settings, - stop: oneshot::Receiver<()>, + mut stop: oneshot::Receiver<()>, ) -> AnyhowResultFuture<()> { Box::pin(async move { let (shard, mut events) = Shard::builder(settings.token.to_owned(), settings.intents) @@ -33,35 +42,41 @@ impl Component for GatewayServer { settings.nats, ) .await?; - shard.start().await?; - let mut stop = stop.fuse(); loop { select! { - event = events.next().fuse() => { + event = events.next() => { + if let Some(event) = event { match event { Event::Ready(ready) => { info!("Logged in as {}", ready.user.name); - } + }, _ => { + let name = event.kind().name(); if let Ok(dispatch_event) = DispatchEvent::try_from(event) { + debug!("handling event {}", name.unwrap()); + let data = CachePayload { - tracing: Tracing { - node_id: "".to_string(), - span: None, - }, data: DispatchEventTagged { data: dispatch_event, }, }; let value = serde_json::to_string(&data)?; - debug!("nats send: {}", value); let bytes = bytes::Bytes::from(value); - nats.publish(format!("nova.cache.dispatch.{}", name.unwrap()), bytes) + + let span = trace_span!("nats send"); + + let mut header_map = HeaderMap::new(); + let context = span.context(); + global::get_text_map_propagator(|propagator| { + propagator.inject_context(&context, &mut MetadataMap(&mut header_map)) + }); + + nats.publish_with_headers(format!("nova.cache.dispatch.{}", name.unwrap()), header_map, bytes) .await?; } } @@ -70,7 +85,7 @@ impl Component for GatewayServer { break } }, - _ = stop => break + _ = (&mut stop) => break }; } diff --git a/exes/gateway/src/main.rs b/exes/gateway/src/main.rs index 2e18f9c..f1b0298 100644 --- a/exes/gateway/src/main.rs +++ b/exes/gateway/src/main.rs @@ -1,4 +1,4 @@ -use leash::ignite; use gateway::GatewayServer; +use leash::ignite; ignite!(GatewayServer); diff --git a/exes/ratelimit/Cargo.toml b/exes/ratelimit/Cargo.toml index 82ca9f6..d82d8c9 100644 --- a/exes/ratelimit/Cargo.toml +++ b/exes/ratelimit/Cargo.toml @@ -9,13 +9,21 @@ edition = "2021" shared = { path = "../../libs/shared" } proto = { path = "../../libs/proto" } leash = { path = "../../libs/leash" } -hyper = { version = "0.14", features = ["full"] } -tokio = { version = "1", features = ["full"] } + +hyper = "0.14" +tokio = { version = "1", features = ["rt"] } + serde = { version = "1.0.8", features = ["derive"] } + twilight-http-ratelimiting = { git = "https://github.com/MatthieuCoder/twilight.git" } anyhow = "*" -futures-util = "0.3.17" tracing = "*" -serde_json = { version = "1.0" } +tracing-opentelemetry = "0.18.0" +opentelemetry = "0.18.0" +opentelemetry-http = "0.7.0" + tonic = "0.8.3" tokio-stream = "0.1.11" + + +redis = { version = "0.22.1", features = ["cluster", "connection-manager", "tokio-comp"] } \ No newline at end of file diff --git a/exes/ratelimit/src/grpc.rs b/exes/ratelimit/src/grpc.rs index a75c329..fbcf3b7 100644 --- a/exes/ratelimit/src/grpc.rs +++ b/exes/ratelimit/src/grpc.rs @@ -1,11 +1,13 @@ - +use opentelemetry::{global, propagation::Extractor}; +use proto::nova::ratelimit::ratelimiter::{ + ratelimiter_server::Ratelimiter, BucketSubmitTicketRequest, BucketSubmitTicketResponse, +}; use std::pin::Pin; - -use futures_util::Stream; -use proto::nova::ratelimit::ratelimiter::{ratelimiter_server::Ratelimiter, BucketSubmitTicketResponse, BucketSubmitTicketRequest}; use tokio::sync::mpsc; -use tokio_stream::{wrappers::ReceiverStream, StreamExt}; +use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt}; use tonic::{Request, Response, Status, Streaming}; +use tracing::{debug, debug_span, info, Instrument}; +use tracing_opentelemetry::OpenTelemetrySpanExt; use twilight_http_ratelimiting::{ticket::TicketReceiver, RatelimitHeaders}; use crate::redis_global_local_bucket_ratelimiter::RedisGlobalLocalBucketRatelimiter; @@ -20,9 +22,28 @@ impl RLServer { } } +struct MetadataMap<'a>(&'a tonic::metadata::MetadataMap); + +impl<'a> Extractor for MetadataMap<'a> { + /// Get a value for a key from the MetadataMap. If the value can't be converted to &str, returns None + fn get(&self, key: &str) -> Option<&str> { + self.0.get(key).and_then(|metadata| metadata.to_str().ok()) + } + + /// Collect all the keys from the MetadataMap. + fn keys(&self) -> Vec<&str> { + self.0 + .keys() + .map(|key| match key { + tonic::metadata::KeyRef::Ascii(v) => v.as_str(), + tonic::metadata::KeyRef::Binary(v) => v.as_str(), + }) + .collect::>() + } +} + #[tonic::async_trait] impl Ratelimiter for RLServer { - type SubmitTicketStream = Pin> + Send>>; @@ -30,6 +51,14 @@ impl Ratelimiter for RLServer { &self, req: Request>, ) -> Result, Status> { + let parent_cx = + global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(req.metadata()))); + // Generate a tracing span as usual + let span = tracing::span!(tracing::Level::INFO, "request process"); + + // Assign parent trace from external context + span.set_parent(parent_cx); + let mut in_stream = req.into_inner(); let (tx, rx) = mpsc::channel(128); let imrl = self.ratelimiter.clone(); @@ -45,29 +74,30 @@ impl Ratelimiter for RLServer { match result.data.unwrap() { proto::nova::ratelimit::ratelimiter::bucket_submit_ticket_request::Data::Path(path) => { - let a = imrl.ticket(path).await.unwrap(); + let span = debug_span!("requesting ticket"); + let a = imrl.ticket(path).instrument(span).await.unwrap(); receiver = Some(a); - tx.send(Ok(BucketSubmitTicketResponse { accepted: 1 })).await.unwrap(); - }, proto::nova::ratelimit::ratelimiter::bucket_submit_ticket_request::Data::Headers(b) => { if let Some(recv) = receiver { - let recv = recv.await.unwrap(); + let span = debug_span!("waiting for headers data"); + let recv = recv.instrument(span).await.unwrap(); let rheaders = RatelimitHeaders::from_pairs(b.headers.iter().map(|f| (f.0.as_str(), f.1.as_bytes()))).unwrap(); - - recv.headers(Some(rheaders)).unwrap(); + recv.headers(Some(rheaders)).unwrap(); break; } }, } } - println!("\tstream ended"); - }); + + debug!("\tstream ended"); + info!("request terminated"); + }.instrument(span)); // echo just write the same data that was received let out_stream = ReceiverStream::new(rx); @@ -76,4 +106,4 @@ impl Ratelimiter for RLServer { Box::pin(out_stream) as Self::SubmitTicketStream )) } -} \ No newline at end of file +} diff --git a/exes/ratelimit/src/lib.rs b/exes/ratelimit/src/lib.rs index 345c37a..7a1f98c 100644 --- a/exes/ratelimit/src/lib.rs +++ b/exes/ratelimit/src/lib.rs @@ -1,9 +1,9 @@ -use futures_util::FutureExt; use grpc::RLServer; use leash::{AnyhowResultFuture, Component}; use proto::nova::ratelimit::ratelimiter::ratelimiter_server::RatelimiterServer; +use redis::aio::MultiplexedConnection; use redis_global_local_bucket_ratelimiter::RedisGlobalLocalBucketRatelimiter; -use shared::{config::Settings, redis_crate::aio::MultiplexedConnection}; +use shared::config::Settings; use std::future::Future; use std::{net::ToSocketAddrs, pin::Pin}; use tokio::sync::oneshot; @@ -34,7 +34,9 @@ impl Component for RatelimiterServerComponent { .add_service(RatelimiterServer::new(server)) .serve_with_shutdown( "0.0.0.0:8093".to_socket_addrs().unwrap().next().unwrap(), - stop.map(|_| ()), + async move { + let _ = stop.await; + }, ) .await?; diff --git a/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/bucket.rs b/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/bucket.rs index d739acf..b35dc45 100644 --- a/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/bucket.rs +++ b/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/bucket.rs @@ -4,7 +4,6 @@ //! and respects the global ratelimit. use super::RedisLockPair; -use twilight_http_ratelimiting::{headers::RatelimitHeaders, ticket::TicketNotifier}; use std::{ collections::HashMap, mem, @@ -21,6 +20,7 @@ use tokio::{ }, time::{sleep, timeout}, }; +use twilight_http_ratelimiting::{headers::RatelimitHeaders, ticket::TicketNotifier}; /// Time remaining until a bucket will reset. #[derive(Clone, Debug)] @@ -265,8 +265,8 @@ impl BucketQueueTask { RatelimitHeaders::None => return, RatelimitHeaders::Present(present) => { Some((present.limit(), present.remaining(), present.reset_after())) - }, - _=> unreachable!() + } + _ => unreachable!(), }; tracing::debug!(path=?self.path, "updating bucket"); diff --git a/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/mod.rs b/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/mod.rs index a97d5a3..a055b04 100644 --- a/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/mod.rs +++ b/exes/ratelimit/src/redis_global_local_bucket_ratelimiter/mod.rs @@ -1,12 +1,11 @@ use self::bucket::{Bucket, BucketQueueTask}; -use shared::redis_crate::aio::MultiplexedConnection; -use shared::redis_crate::{AsyncCommands}; +use redis::aio::MultiplexedConnection; +use redis::AsyncCommands; use tokio::sync::Mutex; use twilight_http_ratelimiting::ticket::{self, TicketNotifier}; use twilight_http_ratelimiting::GetTicketFuture; mod bucket; - -use futures_util::future; +use std::future; use std::{ collections::hash_map::{Entry, HashMap}, sync::Arc, @@ -97,6 +96,6 @@ impl RedisGlobalLocalBucketRatelimiter { ); } - Box::pin(future::ok(rx)) + Box::pin(future::ready(Ok(rx))) } } diff --git a/exes/rest/Cargo.toml b/exes/rest/Cargo.toml index f4c5ecc..39e9798 100644 --- a/exes/rest/Cargo.toml +++ b/exes/rest/Cargo.toml @@ -10,20 +10,23 @@ shared = { path = "../../libs/shared" } proto = { path = "../../libs/proto" } leash = { path = "../../libs/leash" } -hyper = { version = "0.14", features = ["full"] } -tokio = { version = "1", features = ["full"] } +hyper= "0.14" +http = "0.2.8" + +tokio = { version = "1", features = ["rt"] } serde = { version = "1.0.8", features = ["derive"] } -futures-util = "0.3.17" + hyper-tls = "0.5.0" -lazy_static = "1.4.0" -xxhash-rust = { version = "0.8.2", features = ["xxh32"] } + +# todo(MatthieuCoder): Move to the real twilight when patch is merged twilight-http-ratelimiting = { git = "https://github.com/MatthieuCoder/twilight.git" } + tracing = "0.1.37" +anyhow = "1.0.68" hashring = "0.3.0" -anyhow = "*" tonic = "0.8.3" -serde_json = { version = "1.0" } -http = "0.2.8" tokio-stream = "0.1.11" dns-lookup = "1.0.8" -tokio-scoped = "0.2.0" \ No newline at end of file +opentelemetry = "0.18.0" +opentelemetry-http = "0.7.0" +tracing-opentelemetry = "0.18.0" \ No newline at end of file diff --git a/exes/rest/src/config.rs b/exes/rest/src/config.rs index 4e27a30..3bfe8db 100644 --- a/exes/rest/src/config.rs +++ b/exes/rest/src/config.rs @@ -1,5 +1,5 @@ -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use serde::Deserialize; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; fn default_listening_address() -> SocketAddr { SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 8090)) @@ -7,8 +7,7 @@ fn default_listening_address() -> SocketAddr { #[derive(Debug, Deserialize, Clone)] pub struct ServerSettings { - #[serde(default = "default_listening_address")] - pub listening_adress: SocketAddr + pub listening_adress: SocketAddr, } impl Default for ServerSettings { fn default() -> Self { @@ -20,7 +19,7 @@ impl Default for ServerSettings { #[derive(Debug, Deserialize, Clone, Default)] pub struct Discord { - pub token: String + pub token: String, } #[derive(Debug, Deserialize, Clone, Default)] diff --git a/exes/rest/src/handler.rs b/exes/rest/src/handler.rs index 004f763..3ad4cea 100644 --- a/exes/rest/src/handler.rs +++ b/exes/rest/src/handler.rs @@ -1,11 +1,3 @@ -use std::{ - collections::hash_map::DefaultHasher, - convert::TryFrom, - hash::{Hash, Hasher}, - str::FromStr, - time::Instant, -}; - use anyhow::bail; use http::{ header::{AUTHORIZATION, CONNECTION, HOST, TRANSFER_ENCODING, UPGRADE}, @@ -13,7 +5,13 @@ use http::{ }; use hyper::{client::HttpConnector, Body, Client}; use hyper_tls::HttpsConnector; -use shared::log::error; +use std::{ + collections::hash_map::DefaultHasher, + convert::TryFrom, + hash::{Hash, Hasher}, + str::FromStr, +}; +use tracing::{debug_span, error, instrument, Instrument}; use twilight_http_ratelimiting::{Method, Path}; use crate::ratelimit_client::RemoteRatelimiter; @@ -36,6 +34,7 @@ fn normalize_path(request_path: &str) -> (&str, &str) { } } +#[instrument] pub async fn handle_request( client: Client, Body>, ratelimiter: RemoteRatelimiter, @@ -72,7 +71,7 @@ pub async fn handle_request( "Failed to parse path for {:?} {}: {:?}", method, trimmed_path, e ); - bail!("failed o parse"); + bail!("failed to parse"); } } .hash(&mut hash); @@ -80,21 +79,18 @@ pub async fn handle_request( (hash.finish().to_string(), uri_string) }; - let start_ticket_request = Instant::now(); - let header_sender = match ratelimiter.ticket(hash).await { + let span = debug_span!("ticket validation request"); + let header_sender = match span + .in_scope(|| ratelimiter.ticket(hash)) + .await + { Ok(sender) => sender, Err(e) => { error!("Failed to receive ticket for ratelimiting: {:?}", e); bail!("failed to reteive ticket"); } }; - let time_took_ticket = Instant::now() - start_ticket_request; - - request.headers_mut().insert( - AUTHORIZATION, - HeaderValue::from_bytes(token.as_bytes()) - .expect("strings are guaranteed to be valid utf-8"), - ); + request .headers_mut() .insert(HOST, HeaderValue::from_static("discord.com")); @@ -106,7 +102,7 @@ pub async fn handle_request( request.headers_mut().remove("proxy-connection"); request.headers_mut().remove(TRANSFER_ENCODING); request.headers_mut().remove(UPGRADE); - + if let Some(auth) = request.headers_mut().get_mut(AUTHORIZATION) { if auth .to_str() @@ -130,25 +126,14 @@ pub async fn handle_request( } }; *request.uri_mut() = uri; - - let start_upstream_req = Instant::now(); - let mut resp = match client.request(request).await { + let span = debug_span!("upstream request to discord"); + let resp = match client.request(request).instrument(span).await { Ok(response) => response, Err(e) => { error!("Error when requesting the Discord API: {:?}", e); bail!("failed to request the discord api"); } }; - let upstream_time_took = Instant::now() - start_upstream_req; - - resp.headers_mut().append( - "X-TicketRequest-Ms", - HeaderValue::from_str(&time_took_ticket.as_millis().to_string()).unwrap(), - ); - resp.headers_mut().append( - "X-Upstream-Ms", - HeaderValue::from_str(&upstream_time_took.as_millis().to_string()).unwrap(), - ); let ratelimit_headers = resp .headers() diff --git a/exes/rest/src/lib.rs b/exes/rest/src/lib.rs index 02721cc..158fc97 100644 --- a/exes/rest/src/lib.rs +++ b/exes/rest/src/lib.rs @@ -8,6 +8,8 @@ use hyper::{ }; use hyper_tls::HttpsConnector; use leash::{AnyhowResultFuture, Component}; +use opentelemetry::{global, trace::{Tracer}}; +use opentelemetry_http::HeaderExtractor; use shared::config::Settings; use std::{convert::Infallible, sync::Arc}; use tokio::sync::oneshot; @@ -38,6 +40,12 @@ impl Component for ReverseProxyServer { let token = token.clone(); async move { Ok::<_, Infallible>(service_fn(move |request: Request| { + let parent_cx = global::get_text_map_propagator(|propagator| { + propagator.extract(&HeaderExtractor(request.headers())) + }); + let _span = global::tracer("") + .start_with_context("handle_request", &parent_cx); + let client = client.clone(); let ratelimiter = ratelimiter.clone(); let token = token.clone(); @@ -64,4 +72,4 @@ impl Component for ReverseProxyServer { fn new() -> Self { Self {} } -} \ No newline at end of file +} diff --git a/exes/rest/src/ratelimit_client/mod.rs b/exes/rest/src/ratelimit_client/mod.rs index ea34ad9..7493af9 100644 --- a/exes/rest/src/ratelimit_client/mod.rs +++ b/exes/rest/src/ratelimit_client/mod.rs @@ -1,10 +1,10 @@ -use self::remote_hashring::{HashRingWrapper, VNode}; -use futures_util::Future; +use self::remote_hashring::{HashRingWrapper, MetadataMap, VNode}; +use opentelemetry::global; use proto::nova::ratelimit::ratelimiter::bucket_submit_ticket_request::{Data, Headers}; use proto::nova::ratelimit::ratelimiter::BucketSubmitTicketRequest; -use shared::log::debug; use std::collections::HashMap; use std::fmt::Debug; +use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::time::UNIX_EPOCH; @@ -12,6 +12,9 @@ use std::time::{Duration, SystemTime}; use tokio::sync::oneshot::{self}; use tokio::sync::{broadcast, mpsc, RwLock}; use tokio_stream::wrappers::ReceiverStream; +use tonic::Request; +use tracing::{debug, debug_span, Instrument, Span, instrument}; +use tracing_opentelemetry::OpenTelemetrySpanExt; mod remote_hashring; @@ -45,7 +48,7 @@ impl RemoteRatelimiter { let mut write = self.remotes.write().await; - for ip in ["localhost"] { + for ip in ["ratelimit"] { let a = VNode::new(ip.into()).await?; write.add(a.clone()); } @@ -82,55 +85,80 @@ impl RemoteRatelimiter { obj } + #[instrument(name = "ticket task")] pub fn ticket(&self, path: String) -> IssueTicket { let remotes = self.remotes.clone(); let (tx, rx) = oneshot::channel::>(); - - Box::pin(async move { - // Get node managing this path - let mut node = (*remotes.read().await.get(&path).unwrap()).clone(); - - // Buffers for the gRPC streaming channel. - let (send, remote) = mpsc::channel(5); - let (do_request, wait) = oneshot::channel(); - // Tonic requires a stream to be used; Since we use a mpsc channel, we can create a stream from it - let stream = ReceiverStream::new(remote); - - // Start the grpc streaming - let ticket = node.submit_ticket(stream).await?; - - // First, send the request - send.send(BucketSubmitTicketRequest { - data: Some(Data::Path(path)), - }) - .await?; - - // We continuously listen for events in the channel. - tokio::spawn(async move { - let message = ticket.into_inner().message().await.unwrap().unwrap(); - - if message.accepted == 1 { - do_request.send(()).unwrap(); - let headers = rx.await.unwrap(); - - send.send(BucketSubmitTicketRequest { - data: Some(Data::Headers(Headers { - precise_time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("time went backwards") - .as_millis() as u64, - headers, - })), - }) - .await - .unwrap(); - } - }); - - // Wait for the message to be sent - wait.await?; - - Ok(tx) - }) + Box::pin( + async move { + // Get node managing this path + let mut node = (*remotes.read().await.get(&path).unwrap()).clone(); + + // Buffers for the gRPC streaming channel. + let (send, remote) = mpsc::channel(5); + let (do_request, wait) = oneshot::channel(); + // Tonic requires a stream to be used; Since we use a mpsc channel, we can create a stream from it + let stream = ReceiverStream::new(remote); + + let mut request = Request::new(stream); + + let span = debug_span!("remote request"); + let context = span.context(); + global::get_text_map_propagator(|propagator| { + propagator.inject_context(&context, &mut MetadataMap(request.metadata_mut())) + }); + + // Start the grpc streaming + let ticket = node.submit_ticket(request).await?; + + // First, send the request + send.send(BucketSubmitTicketRequest { + data: Some(Data::Path(path)), + }) + .await?; + + // We continuously listen for events in the channel. + let span = debug_span!("stream worker"); + tokio::spawn( + async move { + let span = debug_span!("waiting for ticket upstream"); + let message = ticket + .into_inner() + .message() + .instrument(span) + .await + .unwrap() + .unwrap(); + + if message.accepted == 1 { + debug!("request ticket was accepted"); + do_request.send(()).unwrap(); + let span = debug_span!("waiting for response headers"); + let headers = rx.instrument(span).await.unwrap(); + + send.send(BucketSubmitTicketRequest { + data: Some(Data::Headers(Headers { + precise_time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("time went backwards") + .as_millis() + as u64, + headers, + })), + }) + .await + .unwrap(); + } + } + .instrument(span), + ); + + // Wait for the message to be sent + wait.await?; + + Ok(tx) + } + .instrument(Span::current()), + ) } } diff --git a/exes/rest/src/ratelimit_client/remote_hashring.rs b/exes/rest/src/ratelimit_client/remote_hashring.rs index 4e3fa06..d1c1702 100644 --- a/exes/rest/src/ratelimit_client/remote_hashring.rs +++ b/exes/rest/src/ratelimit_client/remote_hashring.rs @@ -1,4 +1,6 @@ use core::fmt::Debug; +use std::convert::TryFrom; +use opentelemetry::propagation::Injector; use proto::nova::ratelimit::ratelimiter::ratelimiter_client::RatelimiterClient; use std::hash::Hash; use std::ops::Deref; @@ -32,6 +34,20 @@ impl Hash for VNode { } } +pub struct MetadataMap<'a>(pub &'a mut tonic::metadata::MetadataMap); + +impl<'a> Injector for MetadataMap<'a> { + /// Set a key and value in the MetadataMap. Does nothing if the key or value are not valid inputs + fn set(&mut self, key: &str, value: String) { + if let Ok(key) = tonic::metadata::MetadataKey::from_bytes(key.as_bytes()) { + if let Ok(val) = tonic::metadata::MetadataValue::try_from(&value) { + self.0.insert(key, val); + } + } + } +} + + impl VNode { pub async fn new(address: String) -> Result { let client = RatelimiterClient::connect(format!("http://{}:8093", address.clone())).await?; diff --git a/exes/webhook/Cargo.toml b/exes/webhook/Cargo.toml index 589b5bd..0c50009 100644 --- a/exes/webhook/Cargo.toml +++ b/exes/webhook/Cargo.toml @@ -4,21 +4,19 @@ version = "0.1.0" edition = "2018" [dependencies] -hyper = { version = "0.14", features = ["full"] } -tokio = { version = "1", features = ["full"] } +hyper = "0.14" +tokio = { version = "1", features = ["rt"] } shared = { path = "../../libs/shared" } proto = { path = "../../libs/proto" } leash = { path = "../../libs/leash" } +tracing = "0.1.37" serde = { version = "1.0.8", features = ["derive"] } -hex = "0.4.3" serde_json = { version = "1.0" } -lazy_static = "1.4.0" + +hex = "0.4.3" ed25519-dalek = "1" twilight-model = { version = "0.14" } anyhow = "1.0.68" -futures-util = "0.3.25" -[[bin]] -name = "webhook" -path = "src/main.rs" +async-nats = "0.25.1" diff --git a/exes/webhook/src/config.rs b/exes/webhook/src/config.rs index d1b3fb6..02543e6 100644 --- a/exes/webhook/src/config.rs +++ b/exes/webhook/src/config.rs @@ -9,7 +9,6 @@ fn default_listening_address() -> SocketAddr { #[derive(Debug, Deserialize, Clone, Copy)] pub struct ServerSettings { - #[serde(default = "default_listening_address")] pub listening_adress: SocketAddr, } impl Default for ServerSettings { diff --git a/exes/webhook/src/handler/mod.rs b/exes/webhook/src/handler/mod.rs index 3ef859e..594919b 100644 --- a/exes/webhook/src/handler/mod.rs +++ b/exes/webhook/src/handler/mod.rs @@ -1,4 +1,5 @@ use crate::config::WebhookConfig; +use async_nats::Client; use ed25519_dalek::PublicKey; use error::WebhookError; use hyper::{ @@ -6,11 +7,7 @@ use hyper::{ service::Service, Body, Method, Request, Response, StatusCode, }; -use shared::nats_crate::Client; -use shared::{ - log::{debug, error}, - payloads::{CachePayload, DispatchEventTagged, Tracing}, -}; +use shared::payloads::{CachePayload, DispatchEventTagged}; use signature::validate_signature; use std::{ future::Future, @@ -18,6 +15,7 @@ use std::{ str::from_utf8, task::{Context, Poll}, }; +use tracing::{debug, error}; use twilight_model::gateway::event::DispatchEvent; use twilight_model::{ application::interaction::{Interaction, InteractionType}, @@ -98,10 +96,6 @@ impl WebhookService { // this should hopefully not fail ? let data = CachePayload { - tracing: Tracing { - node_id: "".to_string(), - span: None, - }, data: DispatchEventTagged { data: DispatchEvent::InteractionCreate(Box::new( InteractionCreate(value), diff --git a/exes/webhook/src/handler/signature.rs b/exes/webhook/src/handler/signature.rs index fc5555f..ece7b85 100644 --- a/exes/webhook/src/handler/signature.rs +++ b/exes/webhook/src/handler/signature.rs @@ -1,41 +1,13 @@ -use shared::prometheus::{Counter, HistogramVec, labels, opts, register_counter, register_histogram_vec}; -use ed25519_dalek::PublicKey; -use ed25519_dalek::Verifier; -use ed25519_dalek::Signature; -use std::convert::TryInto; - -lazy_static::lazy_static! { - static ref SIGNATURE_TIME_HISTOGRAM: HistogramVec = register_histogram_vec!( - "nova_webhook_signature_time", - "The time taken by the signature verification", - &["signature"] - ).unwrap(); - - static ref SIGNATURE_COUNTER: Counter = register_counter!(opts!( - "nova_webhook_signatures_verify", - "number of signatures verification issued by the service", - labels! {"handler" => "webhook_main"} - )).unwrap(); -} - -fn demo(v: Vec) -> [T; N] { - v.try_into() - .unwrap_or_else(|v: Vec| panic!("Expected a Vec of length {} but it was {}", N, v.len())) -} +use ed25519_dalek::{PublicKey, Signature, Verifier}; pub fn validate_signature(public_key: &PublicKey, data: &[u8], hex_signature: &str) -> bool { - SIGNATURE_COUNTER.inc(); - let timer = SIGNATURE_TIME_HISTOGRAM.with_label_values(&["webhook_main"]).start_timer(); - - let signature_result = hex::decode(hex_signature); + let mut slice: [u8; Signature::BYTE_SIZE] = [0; Signature::BYTE_SIZE]; + let signature_result = hex::decode_to_slice(hex_signature, &mut slice); let mut result = false; - if let Ok(signature) = signature_result { - let sig = Signature::from(demo(signature)); - - result = public_key.verify(data, &sig).is_ok(); + if signature_result.is_ok() { + result = public_key.verify(data, &Signature::from(slice)).is_ok(); } - timer.observe_duration(); result } diff --git a/exes/webhook/src/handler/tests/handler.rs b/exes/webhook/src/handler/tests/handler.rs index e69de29..8b13789 100644 --- a/exes/webhook/src/handler/tests/handler.rs +++ b/exes/webhook/src/handler/tests/handler.rs @@ -0,0 +1 @@ + diff --git a/exes/webhook/src/handler/tests/mod.rs b/exes/webhook/src/handler/tests/mod.rs index cf7f558..60ae6d3 100644 --- a/exes/webhook/src/handler/tests/mod.rs +++ b/exes/webhook/src/handler/tests/mod.rs @@ -1,2 +1,2 @@ -pub mod signature; pub mod handler; +pub mod signature; diff --git a/exes/webhook/src/lib.rs b/exes/webhook/src/lib.rs index 43ab9c4..057e70f 100644 --- a/exes/webhook/src/lib.rs +++ b/exes/webhook/src/lib.rs @@ -6,11 +6,12 @@ use crate::{ config::WebhookConfig, handler::{make_service::MakeSvc, WebhookService}, }; +use async_nats::Client; use hyper::Server; use leash::{AnyhowResultFuture, Component}; -use shared::{config::Settings, log::info, nats_crate::Client}; +use shared::config::Settings; use tokio::sync::oneshot; - +use tracing::info; #[derive(Clone, Copy)] pub struct WebhookServer {} @@ -27,7 +28,7 @@ impl Component for WebhookServer { info!("Starting server on {}", settings.server.listening_adress); let bind = settings.server.listening_adress; - info!("NAts connected!"); + info!("Nats connected!"); let nats = Into::> + Send>>>::into( settings.nats, ) diff --git a/libs/leash/Cargo.toml b/libs/leash/Cargo.toml index 32f385c..364bc3a 100644 --- a/libs/leash/Cargo.toml +++ b/libs/leash/Cargo.toml @@ -8,6 +8,12 @@ edition = "2021" [dependencies] shared = { path = "../shared" } anyhow = "1.0.68" -tokio = { version = "1.23.0", features = ["full"] } -pretty_env_logger = "0.4" -serde = "1.0.152" \ No newline at end of file +tokio = { version = "1.23.0", features = ["rt", "signal"] } +serde = "1.0.152" +tracing-log = { version = "0.1.3", features = ["env_logger"] } +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +tracing = "0.1.37" +env_logger = "0.10.0" +tracing-opentelemetry = "0.18.0" +opentelemetry = { version ="0.18.0", features = ["rt-tokio"] } +opentelemetry-otlp = { version = "0.11.0" } \ No newline at end of file diff --git a/libs/leash/src/lib.rs b/libs/leash/src/lib.rs index a73a0b5..cd67075 100644 --- a/libs/leash/src/lib.rs +++ b/libs/leash/src/lib.rs @@ -1,8 +1,17 @@ use anyhow::Result; +use opentelemetry::sdk::propagation::TraceContextPropagator; +use opentelemetry::sdk::trace::{self}; +use opentelemetry::sdk::Resource; +use opentelemetry::{global, KeyValue}; +use opentelemetry_otlp::WithExportConfig; use serde::de::DeserializeOwned; use shared::config::Settings; +use std::str::FromStr; use std::{future::Future, pin::Pin}; use tokio::sync::oneshot; +use tracing::{info, log::trace}; +use tracing_subscriber::filter::Directive; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; pub type AnyhowResultFuture = Pin> + Send>>; pub trait Component: Send + Sync + 'static + Sized { @@ -18,27 +27,48 @@ pub trait Component: Send + Sync + 'static + Sized { fn _internal_start(self) -> AnyhowResultFuture<()> { Box::pin(async move { - pretty_env_logger::init(); + global::set_text_map_propagator(TraceContextPropagator::new()); + let tracer = opentelemetry_otlp::new_pipeline() + .tracing() + .with_trace_config(trace::config().with_resource(Resource::new(vec![ + KeyValue::new("service.name", Self::SERVICE_NAME), + ]))) + .with_exporter(opentelemetry_otlp::new_exporter().tonic().with_env()) + .install_batch(opentelemetry::runtime::Tokio)?; + + let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); + + tracing_subscriber::registry() + .with(fmt::layer()) + .with(telemetry) + .with( + EnvFilter::builder() + .with_default_directive(Directive::from_str("info").unwrap()) + .from_env()?, + ) + .init(); + + info!("Starting nova"); let settings = Settings::::new(Self::SERVICE_NAME); let (stop, stop_channel) = oneshot::channel(); - // Start the grpc healthcheck - tokio::spawn(async move {}); - - // Start the prometheus monitoring job - tokio::spawn(async move {}); - tokio::spawn(async move { + trace!("started signal watching"); #[cfg(unix)] tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) .unwrap() .recv() .await; #[cfg(not(unix))] - tokio::signal::ctrl_c().await; + return tokio::signal::ctrl_c().await.unwrap(); stop.send(()).unwrap(); }); + + trace!( + "Starting component {component}", + component = Self::SERVICE_NAME + ); self.start(settings?, stop_channel).await }) } diff --git a/libs/shared/Cargo.toml b/libs/shared/Cargo.toml index ce08fbc..419ad0c 100644 --- a/libs/shared/Cargo.toml +++ b/libs/shared/Cargo.toml @@ -4,22 +4,21 @@ version = "0.1.0" edition = "2021" [dependencies] -log = { version = "0.4", features = ["std"] } serde = { version = "1.0.8", features = ["derive"] } +serde_json = { version = "1.0" } serde_repr = "0.1" -config = "0.13" -hyper = { version = "0.14", features = ["full"] } -tokio = { version = "1", features = ["full"] } -enumflags2 = { version = "0.7.1", features = ["serde"] } -prometheus = { version = "0.13", features = ["process"] } + +config = { version = "0.13", default-features = false, features = ["json", "yaml-rust", "ini"] } + async-nats = "0.25.1" -testcontainers = "0.14" +redis = { version = "0.22.1", features = ["cluster", "connection-manager", "tokio-comp"] } + +tokio = { version = "1", features = ["signal", "rt"] } + twilight-model = "0.14" -serde_json = { version = "1.0" } thiserror = "1.0.38" -inner = "0.1.1" anyhow = "1.0.68" -[dependencies.redis] -version = "*" -features = ["cluster", "connection-manager", "tokio-comp"] +serde_test = "1.0.152" + +tracing = "0.1.37" \ No newline at end of file diff --git a/libs/shared/src/config.rs b/libs/shared/src/config.rs index ab584a2..73bc449 100644 --- a/libs/shared/src/config.rs +++ b/libs/shared/src/config.rs @@ -1,23 +1,21 @@ -use std::{env, ops::Deref}; use config::{Config, Environment, File}; -use log::info; -use serde::{Deserialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Deserialize}; +use std::{env, ops::Deref}; +use tracing::info; use crate::error::GenericError; #[derive(Debug, Deserialize, Clone)] pub struct Settings { #[serde(skip_deserializing)] pub config: T, - pub monitoring: crate::monitoring::MonitoringConfiguration, pub nats: crate::nats::NatsConfiguration, pub redis: crate::redis::RedisConfiguration, } -impl Settings -{ +impl Settings { pub fn new(service_name: &str) -> Result, GenericError> { let mut builder = Config::builder(); - + builder = builder.add_source(File::with_name("config/default")); let mode = env::var("ENV").unwrap_or_else(|_| "development".into()); info!("Configuration Environment: {}", mode); @@ -28,7 +26,7 @@ impl Settings let env = Environment::with_prefix("NOVA").separator("__"); // we can configure each component using environment variables builder = builder.add_source(env); - + let config = builder.build()?; let mut settings: Settings = config.clone().try_deserialize()?; @@ -39,10 +37,10 @@ impl Settings } } -impl Deref for Settings { +impl Deref for Settings { type Target = T; fn deref(&self) -> &Self::Target { &self.config } -} \ No newline at end of file +} diff --git a/libs/shared/src/error.rs b/libs/shared/src/error.rs index 31b1dcd..990dd1c 100644 --- a/libs/shared/src/error.rs +++ b/libs/shared/src/error.rs @@ -14,5 +14,5 @@ pub enum GenericError { StepFailed(String), #[error("io error")] - Io(#[from] io::Error) + Io(#[from] io::Error), } diff --git a/libs/shared/src/lib.rs b/libs/shared/src/lib.rs index 62d8689..68ff335 100644 --- a/libs/shared/src/lib.rs +++ b/libs/shared/src/lib.rs @@ -1,16 +1,7 @@ -pub use ::config as config_crate; -pub use ::async_nats as nats_crate; -pub use ::redis as redis_crate; -pub use log; -pub use prometheus; -pub use serde; -pub use testcontainers; - /// This crate is all the utilities shared by the nova rust projects /// It includes logging, config and protocols. pub mod config; pub mod error; -pub mod monitoring; pub mod nats; pub mod payloads; pub mod redis; diff --git a/libs/shared/src/monitoring.rs b/libs/shared/src/monitoring.rs deleted file mode 100644 index 4bff043..0000000 --- a/libs/shared/src/monitoring.rs +++ /dev/null @@ -1,61 +0,0 @@ -use hyper::{ - header::CONTENT_TYPE, - service::{make_service_fn, service_fn}, - Body, Request, Response, Server, -}; -use log::{error, info}; -use prometheus::{Encoder, TextEncoder}; -use serde::Deserialize; -use std::net::ToSocketAddrs; - -#[derive(Clone, Debug, Deserialize)] -/// Options for the monitoring service -pub struct MonitoringConfiguration { - pub enabled: bool, - pub address: Option, - pub port: Option, -} - -/// Handler for the hyper http server -async fn serve_metrics(_request: Request) -> Result, hyper::Error> { - let encoder = TextEncoder::new(); - let metrics = prometheus::gather(); - - let mut buffer = vec![]; - encoder.encode(&metrics, &mut buffer).unwrap(); - - let response = Response::builder() - .status(200) - .header(CONTENT_TYPE, encoder.format_type()) - .body(Body::from(buffer)) - .unwrap(); - Ok(response) -} - -/// Starts a monitoring server on the requested port -pub fn start_monitoring(configuration: &MonitoringConfiguration) { - let config = configuration.clone(); - tokio::task::spawn(async move { - if config.enabled { - let address = format!( - "{}:{}", - config - .address - .expect("a listening address must be specified for the metrics server"), - config - .port - .expect("a listening port must be specified for the metrics server") - ); - info!("Starting monitoring server on {}", address); - - let listen_address = address.to_socket_addrs().unwrap().next().unwrap(); - let server = Server::bind(&listen_address).serve(make_service_fn(|_| async { - Ok::<_, hyper::Error>(service_fn(serve_metrics)) - })); - - if let Err(e) = server.await { - error!("failed to start the monitoring server {}", e); - } - } - }); -} diff --git a/libs/shared/src/payloads.rs b/libs/shared/src/payloads.rs index 7b56dfb..6e51b2d 100644 --- a/libs/shared/src/payloads.rs +++ b/libs/shared/src/payloads.rs @@ -1,9 +1,10 @@ use std::fmt::Debug; -use crate::serde::Deserializer; use serde::de::DeserializeSeed; +use serde::Deserializer; use serde::{Deserialize, Serialize}; use serde_json::Value; +use tracing::trace_span; use twilight_model::gateway::event::{DispatchEvent, DispatchEventWithTypeDeserializer}; #[derive(Debug, Clone)] @@ -20,15 +21,19 @@ struct DispatchEventTaggedSerialized { pub kind: String, } +// todo(MatthieuCoder): Remove the use of the Value impl<'de> Deserialize<'de> for DispatchEventTagged { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { + let _s = trace_span!("deserializing DispatchEventTagged"); let tagged = DispatchEventTaggedSerialized::deserialize(deserializer)?; let deserializer_seed = DispatchEventWithTypeDeserializer::new(&tagged.kind); let dispatch_event = deserializer_seed.deserialize(tagged.data).unwrap(); - Ok(DispatchEventTagged { data: dispatch_event }) + Ok(DispatchEventTagged { + data: dispatch_event, + }) } } @@ -37,28 +42,19 @@ impl Serialize for DispatchEventTagged { where S: serde::Serializer, { - let kind = self.data.kind().name().unwrap().to_string(); - - let s = DispatchEventTaggedSerialized { - kind, + let _s = trace_span!("serializing DispatchEventTagged"); + let kind = self.data.kind().name().unwrap(); + DispatchEventTaggedSerialized { data: serde_json::to_value(&self.data).unwrap(), - }; - - s.serialize(serializer) + kind: kind.to_string(), + } + .serialize(serializer) } } /// Payload send to the nova cache queues #[derive(Serialize, Deserialize, Debug, Clone)] -// #[serde(bound(deserialize = "T: Deserialize<'de> + std::default::Default + Clone"))] pub struct CachePayload { - pub tracing: Tracing, #[serde(flatten)] pub data: DispatchEventTagged, } - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Tracing { - pub node_id: String, - pub span: Option, -} diff --git a/otel/grafana/grafana.ini b/otel/grafana/grafana.ini new file mode 100644 index 0000000..e9c5b16 --- /dev/null +++ b/otel/grafana/grafana.ini @@ -0,0 +1,1170 @@ +##################### Grafana Configuration Example ##################### +# +# Everything has defaults so you only need to uncomment things you want to +# change + +# possible values : production, development +;app_mode = production + +# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty +;instance_name = ${HOSTNAME} + +# force migration will run migrations that might cause dataloss +;force_migration = false + +#################################### Paths #################################### +[paths] +# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) +;data = /var/lib/grafana + +# Temporary files in `data` directory older than given duration will be removed +;temp_data_lifetime = 24h + +# Directory where grafana can store logs +;logs = /var/log/grafana + +# Directory where grafana will automatically scan and look for plugins +;plugins = /var/lib/grafana/plugins + +# folder that contains provisioning config files that grafana will apply on startup and while running. +provisioning = /etc/grafana/provisioning + +#################################### Server #################################### +[server] +# Protocol (http, https, h2, socket) +protocol = http + +# The ip address to bind to, empty will bind to all interfaces +;http_addr = + +# The http port to use +http_port = 3000 + +# The public facing domain name used to access grafana from a browser +domain = localhost + +# Redirect to correct domain if host header does not match domain +# Prevents DNS rebinding attacks +;enforce_domain = false + +# The full public facing url you use in browser, used for redirects and emails +# If you use reverse proxy and sub path specify full url (with sub path) +root_url = %(protocol)s://%(domain)s/grafana/ + +# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons. +serve_from_sub_path = true + +# Log web requests +;router_logging = false + +# the path relative working path +;static_root_path = public + +# enable gzip +;enable_gzip = false + +# https certs & key file +;cert_file = +;cert_key = + +# Unix socket path +;socket = + +# CDN Url +;cdn_url = + +# Sets the maximum time using a duration format (5s/5m/5ms) before timing out read of an incoming request and closing idle connections. +# `0` means there is no timeout for reading the request. +;read_timeout = 0 + +#################################### Database #################################### +[database] +# You can configure the database connection by specifying type, host, name, user and password +# as separate properties or as on string using the url properties. + +# Either "mysql", "postgres" or "sqlite3", it's your choice +;type = sqlite3 +;host = 127.0.0.1:3306 +;name = grafana +;user = root +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" +;password = + +# Use either URL or the previous fields to configure the database +# Example: mysql://user:secret@host:port/database +;url = + +# For "postgres" only, either "disable", "require" or "verify-full" +;ssl_mode = disable + +# Database drivers may support different transaction isolation levels. +# Currently, only "mysql" driver supports isolation levels. +# If the value is empty - driver's default isolation level is applied. +# For "mysql" use "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE". +;isolation_level = + +;ca_cert_path = +;client_key_path = +;client_cert_path = +;server_cert_name = + +# For "sqlite3" only, path relative to data_path setting +;path = grafana.db + +# Max idle conn setting default is 2 +;max_idle_conn = 2 + +# Max conn setting default is 0 (mean not set) +;max_open_conn = + +# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours) +;conn_max_lifetime = 14400 + +# Set to true to log the sql calls and execution times. +;log_queries = + +# For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared) +;cache_mode = private + +# For "mysql" only if lockingMigration feature toggle is set. How many seconds to wait before failing to lock the database for the migrations, default is 0. +;locking_attempt_timeout_sec = 0 + +################################### Data sources ######################### +[datasources] +# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API. +;datasource_limit = 5000 + +#################################### Cache server ############################# +[remote_cache] +# Either "redis", "memcached" or "database" default is "database" +;type = database + +# cache connectionstring options +# database: will use Grafana primary database. +# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=0,ssl=false`. Only addr is required. ssl may be 'true', 'false', or 'insecure'. +# memcache: 127.0.0.1:11211 +;connstr = + +#################################### Data proxy ########################### +[dataproxy] + +# This enables data proxy logging, default is false +;logging = false + +# How long the data proxy waits to read the headers of the response before timing out, default is 30 seconds. +# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set. +;timeout = 30 + +# How long the data proxy waits to establish a TCP connection before timing out, default is 10 seconds. +;dialTimeout = 10 + +# How many seconds the data proxy waits before sending a keepalive probe request. +;keep_alive_seconds = 30 + +# How many seconds the data proxy waits for a successful TLS Handshake before timing out. +;tls_handshake_timeout_seconds = 10 + +# How many seconds the data proxy will wait for a server's first response headers after +# fully writing the request headers if the request has an "Expect: 100-continue" +# header. A value of 0 will result in the body being sent immediately, without +# waiting for the server to approve. +;expect_continue_timeout_seconds = 1 + +# Optionally limits the total number of connections per host, including connections in the dialing, +# active, and idle states. On limit violation, dials will block. +# A value of zero (0) means no limit. +;max_conns_per_host = 0 + +# The maximum number of idle connections that Grafana will keep alive. +;max_idle_connections = 100 + +# How many seconds the data proxy keeps an idle connection open before timing out. +;idle_conn_timeout_seconds = 90 + +# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false. +;send_user_header = false + +# Limit the amount of bytes that will be read/accepted from responses of outgoing HTTP requests. +;response_limit = 0 + +# Limits the number of rows that Grafana will process from SQL data sources. +;row_limit = 1000000 + +#################################### Analytics #################################### +[analytics] +# Server reporting, sends usage counters to stats.grafana.org every 24 hours. +# No ip addresses are being tracked, only simple counters to track +# running instances, dashboard and error counts. It is very helpful to us. +# Change this option to false to disable reporting. +;reporting_enabled = true + +# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs +;reporting_distributor = grafana-labs + +# Set to false to disable all checks to https://grafana.com +# for new versions of grafana. The check is used +# in some UI views to notify that a grafana update exists. +# This option does not cause any auto updates, nor send any information +# only a GET request to https://raw.githubusercontent.com/grafana/grafana/main/latest.json to get the latest version. +;check_for_updates = true + +# Set to false to disable all checks to https://grafana.com +# for new versions of plugins. The check is used +# in some UI views to notify that a plugin update exists. +# This option does not cause any auto updates, nor send any information +# only a GET request to https://grafana.com to get the latest versions. +;check_for_plugin_updates = true + +# Google Analytics universal tracking code, only enabled if you specify an id here +;google_analytics_ua_id = + +# Google Tag Manager ID, only enabled if you specify an id here +;google_tag_manager_id = + +# Rudderstack write key, enabled only if rudderstack_data_plane_url is also set +;rudderstack_write_key = + +# Rudderstack data plane url, enabled only if rudderstack_write_key is also set +;rudderstack_data_plane_url = + +# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set +;rudderstack_sdk_url = + +# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config +;rudderstack_config_url = + +# Controls if the UI contains any links to user feedback forms +;feedback_links_enabled = true + +#################################### Security #################################### +[security] +# disable creation of admin user on first start of grafana +;disable_initial_admin_creation = false + +# default admin user, created on startup +;admin_user = admin + +# default admin password, can be changed before first start of grafana, or in profile settings +;admin_password = admin + +# used for signing +;secret_key = SW2YcwTIb9zpOOhoPsMm + +# current key provider used for envelope encryption, default to static value specified by secret_key +;encryption_provider = secretKey.v1 + +# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1 +;available_encryption_providers = + +# disable gravatar profile images +;disable_gravatar = false + +# data source proxy whitelist (ip_or_domain:port separated by spaces) +;data_source_proxy_whitelist = + +# disable protection against brute force login attempts +;disable_brute_force_login_protection = false + +# set to true if you host Grafana behind HTTPS. default is false. +;cookie_secure = false + +# set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled" +;cookie_samesite = lax + +# set to true if you want to allow browsers to render Grafana in a ,