base for tracing

This commit is contained in:
MatthieuCoder 2023-01-05 18:33:53 +04:00
parent 63565094f4
commit 038add4d5e
61 changed files with 4351 additions and 778 deletions

11
.env Normal file
View file

@ -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}

2
.gitignore vendored
View file

@ -4,3 +4,5 @@ target/
.ijwb
.idea
config.yml
config/

636
Cargo.lock generated
View file

@ -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"
name = "dashmap"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
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",
]
@ -634,27 +543,6 @@ version = "1.8.0"
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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@ -662,7 +550,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"humantime 1.3.0",
"log",
"regex",
"termcolor",
]
[[package]]
name = "env_logger"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"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"
@ -1364,6 +1250,16 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "nuid"
version = "0.3.2"
@ -1374,16 +1270,6 @@ dependencies = [
"rand 0.8.5",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
@ -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"

View file

@ -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:
- 9003:9000
- 8082:8080
- "${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:
- "${PROMETHEUS_SERVICE_PORT}:${PROMETHEUS_SERVICE_PORT}"

View file

@ -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"]

View file

@ -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);
}

View file

@ -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![];

15
exes/cache/Cargo.toml vendored
View file

@ -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"
anyhow = "1.0.68"
tracing = "0.1.37"

View file

@ -1,5 +1,5 @@
use serde::Deserialize;
#[derive(Debug, Deserialize, Clone, Default)]
pub struct CacheConfiguration {
pub toggles: Vec<String>
pub toggles: Vec<String>,
}

View file

@ -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<dyn Error + Send + Sync>> {
let settings: Settings<CacheConfiguration> = Settings::new("cache").unwrap();
info!("loaded configuration: {:?}", settings);
let nats =
Into::<Pin<Box<dyn Future<Output = anyhow::Result<Client>> + Send>>>::into(settings.nats).await?;
// let redis: redis::Client = settings.redis.into();
Into::<Pin<Box<dyn Future<Output = anyhow::Result<Client>> + Send>>>::into(settings.nats)
.await?;
let mut cache = Cache::default();

View file

@ -5,7 +5,6 @@ use crate::CacheSourcedEvents;
use super::CacheManager;
use std::future::Future;
#[derive(Default)]
pub struct Channels {}
impl CacheManager for Channels {

View file

@ -5,7 +5,6 @@ use crate::CacheSourcedEvents;
use super::CacheManager;
use std::future::Future;
#[derive(Default)]
pub struct GuildSchedules {}
impl CacheManager for GuildSchedules {

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
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!(),
};

View file

@ -5,7 +5,6 @@ use crate::CacheSourcedEvents;
use super::CacheManager;
use std::future::Future;
#[derive(Default)]
pub struct Integrations {}
impl CacheManager for Integrations {

View file

@ -5,7 +5,6 @@ use crate::CacheSourcedEvents;
use super::CacheManager;
use std::future::Future;
#[derive(Default)]
pub struct Invites {}
impl CacheManager for Invites {

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
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!(),
};

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
Box::pin(async move {
match event {
DispatchEvent::MessageCreate(_) => {},
DispatchEvent::MessageDelete(_) => {},
DispatchEvent::MessageDeleteBulk(_) => {},
DispatchEvent::MessageUpdate(_) => {},
DispatchEvent::MessageCreate(_) => {}
DispatchEvent::MessageDelete(_) => {}
DispatchEvent::MessageDeleteBulk(_) => {}
DispatchEvent::MessageUpdate(_) => {}
_ => unreachable!(),
};

View file

@ -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 channels;
pub mod guilds;
pub mod guild_schedules;
pub mod stage_instances;
pub mod integrations;
pub mod members;
pub mod bans;
pub mod reactions;
pub mod messages;
pub mod threads;
pub mod invites;
pub mod roles;
pub mod automoderation;
pub mod bans;
pub mod channels;
pub mod guild_schedules;
pub mod guilds;
pub mod integrations;
pub mod invites;
pub mod members;
pub mod messages;
pub mod reactions;
pub mod roles;
pub mod stage_instances;
pub mod threads;
pub trait CacheManager {
fn handle(&self, event: DispatchEvent) -> Pin<Box<dyn Future<Output = CacheSourcedEvents>>>;

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
Box::pin(async move {
match event {
DispatchEvent::ReactionAdd(_) => {},
DispatchEvent::ReactionRemove(_) => {},
DispatchEvent::ReactionRemoveAll(_) => {},
DispatchEvent::ReactionRemoveEmoji(_) => {},
DispatchEvent::ReactionAdd(_) => {}
DispatchEvent::ReactionRemove(_) => {}
DispatchEvent::ReactionRemoveAll(_) => {}
DispatchEvent::ReactionRemoveEmoji(_) => {}
_ => unreachable!(),
};

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
Box::pin(async move {
match event {
DispatchEvent::RoleCreate(_) => {},
DispatchEvent::RoleDelete(_) => {},
DispatchEvent::RoleUpdate(_) => {},
DispatchEvent::RoleCreate(_) => {}
DispatchEvent::RoleDelete(_) => {}
DispatchEvent::RoleUpdate(_) => {}
_ => unreachable!(),
};

View file

@ -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<dyn Future<Output = crate::CacheSourcedEvents>>> {
Box::pin(async move {
match event {
DispatchEvent::StageInstanceCreate(_) => {},
DispatchEvent::StageInstanceDelete(_) => {},
DispatchEvent::StageInstanceUpdate(_) => {},
DispatchEvent::StageInstanceCreate(_) => {}
DispatchEvent::StageInstanceDelete(_) => {}
DispatchEvent::StageInstanceUpdate(_) => {}
_ => unreachable!(),
};

View file

@ -14,12 +14,12 @@ impl CacheManager for Threads {
) -> std::pin::Pin<Box<dyn Future<Output = crate::CacheSourcedEvents>>> {
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!(),
};

View file

@ -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 = "*"
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"

View file

@ -1,4 +1,4 @@
use shared::serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize};
use twilight_gateway::Intents;
#[derive(Serialize, Deserialize, Clone)]

View file

@ -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<Self::Config>,
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
};
}

View file

@ -1,4 +1,4 @@
use leash::ignite;
use gateway::GatewayServer;
use leash::ignite;
ignite!(GatewayServer);

View file

@ -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"] }

View file

@ -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::<Vec<_>>()
}
}
#[tonic::async_trait]
impl Ratelimiter for RLServer {
type SubmitTicketStream =
Pin<Box<dyn Stream<Item = Result<BucketSubmitTicketResponse, Status>> + Send>>;
@ -30,6 +51,14 @@ impl Ratelimiter for RLServer {
&self,
req: Request<Streaming<BucketSubmitTicketRequest>>,
) -> Result<Response<Self::SubmitTicketStream>, 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
))
}
}
}

View file

@ -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?;

View file

@ -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");

View file

@ -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)))
}
}

View file

@ -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"] }
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"] }
twilight-http-ratelimiting = { git = "https://github.com/MatthieuCoder/twilight.git" }
tracing = "0.1.37"
hashring = "0.3.0"
anyhow = "*"
tonic = "0.8.3"
serde_json = { version = "1.0" }
hyper= "0.14"
http = "0.2.8"
tokio = { version = "1", features = ["rt"] }
serde = { version = "1.0.8", features = ["derive"] }
hyper-tls = "0.5.0"
# 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"
tonic = "0.8.3"
tokio-stream = "0.1.11"
dns-lookup = "1.0.8"
tokio-scoped = "0.2.0"
opentelemetry = "0.18.0"
opentelemetry-http = "0.7.0"
tracing-opentelemetry = "0.18.0"

View file

@ -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)]

View file

@ -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<HttpsConnector<HttpConnector>, 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()

View file

@ -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<Body>| {
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 {}
}
}
}

View file

@ -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::<HashMap<String, String>>();
Box::pin(
async move {
// Get node managing this path
let mut node = (*remotes.read().await.get(&path).unwrap()).clone();
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);
// 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);
// Start the grpc streaming
let ticket = node.submit_ticket(stream).await?;
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()))
});
// First, send the request
send.send(BucketSubmitTicketRequest {
data: Some(Data::Path(path)),
})
.await?;
// Start the grpc streaming
let ticket = node.submit_ticket(request).await?;
// We continuously listen for events in the channel.
tokio::spawn(async move {
let message = ticket.into_inner().message().await.unwrap().unwrap();
// First, send the request
send.send(BucketSubmitTicketRequest {
data: Some(Data::Path(path)),
})
.await?;
if message.accepted == 1 {
do_request.send(()).unwrap();
let headers = rx.await.unwrap();
// 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();
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();
}
});
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();
// Wait for the message to be sent
wait.await?;
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),
);
Ok(tx)
})
// Wait for the message to be sent
wait.await?;
Ok(tx)
}
.instrument(Span::current()),
)
}
}

View file

@ -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<Self, tonic::transport::Error> {
let client = RatelimiterClient::connect(format!("http://{}:8093", address.clone())).await?;

View file

@ -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"

View file

@ -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 {

View file

@ -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),

View file

@ -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<T, const N: usize>(v: Vec<T>) -> [T; N] {
v.try_into()
.unwrap_or_else(|v: Vec<T>| 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
}

View file

@ -0,0 +1 @@

View file

@ -1,2 +1,2 @@
pub mod signature;
pub mod handler;
pub mod signature;

View file

@ -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::<Pin<Box<dyn Future<Output = anyhow::Result<Client>> + Send>>>::into(
settings.nats,
)

View file

@ -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"
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" }

View file

@ -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<T> = Pin<Box<dyn Future<Output = Result<T>> + 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::<Self::Config>::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
})
}

View file

@ -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_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"] }
async-nats = "0.25.1"
testcontainers = "0.14"
twilight-model = "0.14"
serde_json = { version = "1.0" }
serde_repr = "0.1"
config = { version = "0.13", default-features = false, features = ["json", "yaml-rust", "ini"] }
async-nats = "0.25.1"
redis = { version = "0.22.1", features = ["cluster", "connection-manager", "tokio-comp"] }
tokio = { version = "1", features = ["signal", "rt"] }
twilight-model = "0.14"
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"

View file

@ -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<T: Clone + DeserializeOwned + Default> {
#[serde(skip_deserializing)]
pub config: T,
pub monitoring: crate::monitoring::MonitoringConfiguration,
pub nats: crate::nats::NatsConfiguration,
pub redis: crate::redis::RedisConfiguration,
}
impl<T: Clone + DeserializeOwned + Default> Settings<T>
{
impl<T: Clone + DeserializeOwned + Default> Settings<T> {
pub fn new(service_name: &str) -> Result<Settings<T>, 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<T: Clone + DeserializeOwned + Default> Settings<T>
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<T> = config.clone().try_deserialize()?;
@ -39,10 +37,10 @@ impl<T: Clone + DeserializeOwned + Default> Settings<T>
}
}
impl<T: Clone + DeserializeOwned + Default> Deref for Settings<T> {
impl<T: Clone + DeserializeOwned + Default> Deref for Settings<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.config
}
}
}

View file

@ -14,5 +14,5 @@ pub enum GenericError {
StepFailed(String),
#[error("io error")]
Io(#[from] io::Error)
Io(#[from] io::Error),
}

View file

@ -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;

View file

@ -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<String>,
pub port: Option<i32>,
}
/// Handler for the hyper http server
async fn serve_metrics(_request: Request<Body>) -> Result<Response<Body>, 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);
}
}
});
}

View file

@ -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<D>(deserializer: D) -> Result<Self, D::Error>
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<String>,
}

1170
otel/grafana/grafana.ini Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
apiVersion: 1
providers:
- name: 'OpenTelemetry Demo'
orgId: 1
folder: 'Demo'
type: file
disableDeletion: false
editable: true
options:
path: /etc/grafana/provisioning/dashboards/general

View file

@ -0,0 +1,693 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 1,
"links": [],
"liveNow": false,
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 14,
"panels": [],
"title": "Metrics",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 1
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(runtime_cpython_cpu_time{type=~\"system\"}[$__interval])*100",
"legendFormat": "__auto",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(runtime_cpython_cpu_time{type=~\"user\"}[$__interval])*100",
"hide": false,
"legendFormat": "__auto",
"range": true,
"refId": "B"
}
],
"title": "Recommendation Service (CPU%)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "decmbytes"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 1
},
"id": 8,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(runtime_cpython_memory{type=~\"rss|vms\"}[$__interval])/1024/1024",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Recommendation Service (Memory)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 9
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(app_recommendations_counter{recommendation_type=\"catalog\"}[$__interval])",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Recommendations Count",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 9
},
"id": 10,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(calls_total{status_code=\"STATUS_CODE_ERROR\"}[$__interval])",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Error Rate",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "dtdurationms"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 17
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "histogram_quantile(0.50, sum(rate(latency_bucket{service_name=\"${service}\"}[$__rate_interval])) by (le))",
"legendFormat": "__auto",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "histogram_quantile(0.95, sum(rate(latency_bucket{service_name=\"${service}\"}[$__rate_interval])) by (le))",
"hide": false,
"legendFormat": "__auto",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "histogram_quantile(0.99, sum(rate(latency_bucket{service_name=\"${service}\"}[$__rate_interval])) by (le))",
"hide": false,
"legendFormat": "__auto",
"range": true,
"refId": "C"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "histogram_quantile(0.999, sum(rate(latency_bucket{service_name=\"${service}\"}[$__rate_interval])) by (le))",
"hide": false,
"legendFormat": "__auto",
"range": true,
"refId": "D"
}
],
"title": "Service Latency (from SpanMetrics)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "reqps"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 17
},
"id": 12,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"editorMode": "code",
"expr": "rate(latency_count{service_name=\"${service}\"}[$__rate_interval])",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Endpoint Rate by Service",
"type": "timeseries"
}
],
"schemaVersion": 37,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": "",
"current": {
"selected": false,
"text": "recommendationservice",
"value": "recommendationservice"
},
"datasource": {
"type": "prometheus",
"uid": "webstore-metrics"
},
"definition": "latency_bucket",
"hide": 0,
"includeAll": false,
"multi": false,
"name": "service",
"options": [],
"query": {
"query": "latency_bucket",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "/.*service_name=\\\"([^\\\"]+)\\\".*/",
"skipUrlSync": false,
"sort": 1,
"type": "query"
}
]
},
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Demo Dashboard",
"uid": "W2gX2zHVk",
"version": 2,
"weekStart": ""
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
apiVersion: 1
datasources:
- name: Prometheus
uid: webstore-metrics
type: prometheus
url: http://prometheus:9090
editable: true
isDefault: true

View file

@ -0,0 +1,9 @@
apiVersion: 1
datasources:
- name: Jaeger
uid: webstore-traces
type: jaeger
url: http://jaeger:16686/jaeger/ui
editable: true
isDefault: false

View file

@ -0,0 +1,2 @@
# extra settings to be merged into OpenTelemetry Collector configuration
# do not delete this file

View file

@ -0,0 +1,34 @@
receivers:
otlp:
protocols:
grpc:
http:
cors:
allowed_origins:
- "http://*"
- "https://*"
exporters:
otlp:
endpoint: "jaeger:4317"
tls:
insecure: true
logging:
prometheus:
endpoint: "otelcol:9464"
processors:
batch:
spanmetrics:
metrics_exporter: prometheus
service:
pipelines:
traces:
receivers: [otlp]
processors: [spanmetrics, batch]
exporters: [logging, otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus, logging]

View file

@ -0,0 +1,12 @@
global:
evaluation_interval: 30s
scrape_interval: 5s
scrape_configs:
- job_name: otel
static_configs:
- targets:
- 'otelcol:9464'
- job_name: otel-collector
static_configs:
- targets:
- 'otelcol:8888'