aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock172
-rw-r--r--Cargo.nix268
-rw-r--r--Cargo.toml3
-rw-r--r--src/https.rs72
-rw-r--r--src/main.rs15
-rw-r--r--src/metrics.rs83
-rw-r--r--src/proxy_config.rs70
7 files changed, 655 insertions, 28 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f3acee4..e2acbd6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -109,6 +109,17 @@ dependencies = [
]
[[package]]
+name = "async-trait"
+version = "0.1.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -312,6 +323,25 @@ dependencies = [
]
[[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 = "cxx"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -356,6 +386,16 @@ dependencies = [
]
[[package]]
+name = "dashmap"
+version = "4.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
+dependencies = [
+ "cfg-if",
+ "num_cpus",
+]
+
+[[package]]
name = "dhat"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -980,6 +1020,38 @@ dependencies = [
]
[[package]]
+name = "opentelemetry"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8"
+dependencies = [
+ "async-trait",
+ "crossbeam-channel",
+ "dashmap",
+ "fnv",
+ "futures-channel",
+ "futures-executor",
+ "futures-util",
+ "js-sys",
+ "lazy_static",
+ "percent-encoding",
+ "pin-project",
+ "rand",
+ "thiserror",
+]
+
+[[package]]
+name = "opentelemetry-prometheus"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9328977e479cebe12ce0d3fcecdaea4721d234895a9440c5b5dfd113f0594ac6"
+dependencies = [
+ "opentelemetry",
+ "prometheus",
+ "protobuf",
+]
+
+[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1018,6 +1090,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
+name = "pin-project"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1036,6 +1128,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
+name = "ppv-lite86"
+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"
@@ -1085,6 +1183,27 @@ dependencies = [
]
[[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",
+ "memchr",
+ "parking_lot",
+ "protobuf",
+ "thiserror",
+]
+
+[[package]]
+name = "protobuf"
+version = "2.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
+
+[[package]]
name = "publicsuffix"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1119,6 +1238,36 @@ dependencies = [
]
[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
name = "rcgen"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1600,6 +1749,26 @@ dependencies = [
]
[[package]]
+name = "thiserror"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "thousands"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1785,7 +1954,10 @@ dependencies = [
"hyper",
"hyper-rustls",
"log",
+ "opentelemetry",
+ "opentelemetry-prometheus",
"pretty_env_logger",
+ "prometheus",
"rcgen",
"regex",
"reqwest",
diff --git a/Cargo.nix b/Cargo.nix
index ca15b13..514b19c 100644
--- a/Cargo.nix
+++ b/Cargo.nix
@@ -23,7 +23,7 @@ args@{
ignoreLockHash,
}:
let
- nixifiedLockHash = "8b9764c8874557f30d0d72cb4e6453209d5ab90c71cfe15c3367a366506066d2";
+ nixifiedLockHash = "ba43baa059b58c2c0ae0bf86c8d8dc3663b7bd3ecb95274246a3d7123238271a";
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
lockHashIgnored = if ignoreLockHash
@@ -184,6 +184,18 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".async-trait."0.1.59" = overridableMkRustCrate (profileName: rec {
+ name = "async-trait";
+ version = "0.1.59";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"; };
+ dependencies = {
+ proc_macro2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.47" { inherit profileName; }).out;
+ quote = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".quote."1.0.21" { inherit profileName; }).out;
+ syn = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".syn."1.0.105" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".atty."0.2.14" = overridableMkRustCrate (profileName: rec {
name = "atty";
version = "0.2.14";
@@ -480,6 +492,35 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".crossbeam-channel."0.5.6" = overridableMkRustCrate (profileName: rec {
+ name = "crossbeam-channel";
+ version = "0.5.6";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"; };
+ features = builtins.concatLists [
+ [ "crossbeam-utils" ]
+ [ "default" ]
+ [ "std" ]
+ ];
+ dependencies = {
+ cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
+ crossbeam_utils = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".crossbeam-utils."0.8.14" { inherit profileName; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".crossbeam-utils."0.8.14" = overridableMkRustCrate (profileName: rec {
+ name = "crossbeam-utils";
+ version = "0.8.14";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"; };
+ features = builtins.concatLists [
+ [ "std" ]
+ ];
+ dependencies = {
+ cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".cxx."1.0.83" = overridableMkRustCrate (profileName: rec {
name = "cxx";
version = "1.0.83";
@@ -538,6 +579,20 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".dashmap."4.0.2" = overridableMkRustCrate (profileName: rec {
+ name = "dashmap";
+ version = "4.0.2";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"; };
+ features = builtins.concatLists [
+ [ "default" ]
+ ];
+ dependencies = {
+ cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
+ num_cpus = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".num_cpus."1.14.0" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".dhat."0.3.2" = overridableMkRustCrate (profileName: rec {
name = "dhat";
version = "0.3.2";
@@ -752,6 +807,7 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"; };
features = builtins.concatLists [
+ [ "default" ]
[ "std" ]
];
dependencies = {
@@ -846,6 +902,9 @@ in
version = "0.2.8";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"; };
+ features = builtins.concatLists [
+ [ "std" ]
+ ];
dependencies = {
cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
${ if hostPlatform.isUnix then "libc" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.138" { inherit profileName; }).out;
@@ -1184,10 +1243,10 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"; };
dependencies = {
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "scopeguard" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".scopeguard."1.1.0" { inherit profileName; }).out;
+ scopeguard = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".scopeguard."1.1.0" { inherit profileName; }).out;
};
buildDependencies = {
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "autocfg" else null } = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".autocfg."1.1.0" { profileName = "__noProfile"; }).out;
+ autocfg = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".autocfg."1.1.0" { profileName = "__noProfile"; }).out;
};
});
@@ -1402,17 +1461,63 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" = overridableMkRustCrate (profileName: rec {
+ name = "opentelemetry";
+ version = "0.17.0";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8"; };
+ features = builtins.concatLists [
+ [ "async-trait" ]
+ [ "crossbeam-channel" ]
+ [ "dashmap" ]
+ [ "default" ]
+ [ "fnv" ]
+ [ "metrics" ]
+ [ "percent-encoding" ]
+ [ "pin-project" ]
+ [ "rand" ]
+ [ "trace" ]
+ ];
+ dependencies = {
+ async_trait = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".async-trait."0.1.59" { profileName = "__noProfile"; }).out;
+ crossbeam_channel = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".crossbeam-channel."0.5.6" { inherit profileName; }).out;
+ dashmap = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".dashmap."4.0.2" { inherit profileName; }).out;
+ fnv = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".fnv."1.0.7" { inherit profileName; }).out;
+ futures_channel = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-channel."0.3.25" { inherit profileName; }).out;
+ futures_executor = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-executor."0.3.25" { inherit profileName; }).out;
+ futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
+ ${ if hostPlatform.parsed.cpu.name == "wasm32" then "js_sys" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".js-sys."0.3.60" { inherit profileName; }).out;
+ lazy_static = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".lazy_static."1.4.0" { inherit profileName; }).out;
+ percent_encoding = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".percent-encoding."2.2.0" { inherit profileName; }).out;
+ pin_project = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-project."1.0.12" { inherit profileName; }).out;
+ rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
+ thiserror = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror."1.0.37" { inherit profileName; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".opentelemetry-prometheus."0.10.0" = overridableMkRustCrate (profileName: rec {
+ name = "opentelemetry-prometheus";
+ version = "0.10.0";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "9328977e479cebe12ce0d3fcecdaea4721d234895a9440c5b5dfd113f0594ac6"; };
+ dependencies = {
+ opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
+ prometheus = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".prometheus."0.13.3" { inherit profileName; }).out;
+ protobuf = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".protobuf."2.28.0" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".parking_lot."0.12.1" = overridableMkRustCrate (profileName: rec {
name = "parking_lot";
version = "0.12.1";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"; };
features = builtins.concatLists [
- (lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "default")
+ [ "default" ]
];
dependencies = {
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "lock_api" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".lock_api."0.4.9" { inherit profileName; }).out;
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "parking_lot_core" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".parking_lot_core."0.9.5" { inherit profileName; }).out;
+ lock_api = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".lock_api."0.4.9" { inherit profileName; }).out;
+ parking_lot_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".parking_lot_core."0.9.5" { inherit profileName; }).out;
};
});
@@ -1422,11 +1527,11 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"; };
dependencies = {
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "cfg_if" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
- ${ if (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") && hostPlatform.isUnix then "libc" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.138" { inherit profileName; }).out;
- ${ if (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") && hostPlatform.parsed.kernel.name == "redox" then "syscall" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".redox_syscall."0.2.16" { inherit profileName; }).out;
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "smallvec" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".smallvec."1.10.0" { inherit profileName; }).out;
- ${ if (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") && hostPlatform.isWindows then "windows_sys" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".windows-sys."0.42.0" { inherit profileName; }).out;
+ cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
+ ${ if hostPlatform.isUnix then "libc" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.138" { inherit profileName; }).out;
+ ${ if hostPlatform.parsed.kernel.name == "redox" then "syscall" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".redox_syscall."0.2.16" { inherit profileName; }).out;
+ smallvec = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".smallvec."1.10.0" { inherit profileName; }).out;
+ ${ if hostPlatform.isWindows then "windows_sys" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".windows-sys."0.42.0" { inherit profileName; }).out;
};
});
@@ -1451,6 +1556,28 @@ in
];
});
+ "registry+https://github.com/rust-lang/crates.io-index".pin-project."1.0.12" = overridableMkRustCrate (profileName: rec {
+ name = "pin-project";
+ version = "1.0.12";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"; };
+ dependencies = {
+ pin_project_internal = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-project-internal."1.0.12" { profileName = "__noProfile"; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".pin-project-internal."1.0.12" = overridableMkRustCrate (profileName: rec {
+ name = "pin-project-internal";
+ version = "1.0.12";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"; };
+ dependencies = {
+ proc_macro2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.47" { inherit profileName; }).out;
+ quote = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".quote."1.0.21" { inherit profileName; }).out;
+ syn = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".syn."1.0.105" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".pin-project-lite."0.2.9" = overridableMkRustCrate (profileName: rec {
name = "pin-project-lite";
version = "0.2.9";
@@ -1472,6 +1599,17 @@ in
src = fetchCratesIo { inherit name version; sha256 = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"; };
});
+ "registry+https://github.com/rust-lang/crates.io-index".ppv-lite86."0.2.17" = overridableMkRustCrate (profileName: rec {
+ name = "ppv-lite86";
+ version = "0.2.17";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"; };
+ features = builtins.concatLists [
+ [ "simd" ]
+ [ "std" ]
+ ];
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".pretty_env_logger."0.4.0" = overridableMkRustCrate (profileName: rec {
name = "pretty_env_logger";
version = "0.4.0";
@@ -1540,6 +1678,33 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".prometheus."0.13.3" = overridableMkRustCrate (profileName: rec {
+ name = "prometheus";
+ version = "0.13.3";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c"; };
+ features = builtins.concatLists [
+ [ "default" ]
+ [ "protobuf" ]
+ ];
+ dependencies = {
+ cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { inherit profileName; }).out;
+ fnv = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".fnv."1.0.7" { inherit profileName; }).out;
+ lazy_static = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".lazy_static."1.4.0" { inherit profileName; }).out;
+ memchr = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".memchr."2.5.0" { inherit profileName; }).out;
+ parking_lot = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".parking_lot."0.12.1" { inherit profileName; }).out;
+ protobuf = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".protobuf."2.28.0" { inherit profileName; }).out;
+ thiserror = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror."1.0.37" { inherit profileName; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".protobuf."2.28.0" = overridableMkRustCrate (profileName: rec {
+ name = "protobuf";
+ version = "2.28.0";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"; };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".publicsuffix."1.5.6" = overridableMkRustCrate (profileName: rec {
name = "publicsuffix";
version = "1.5.6";
@@ -1582,6 +1747,55 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" = overridableMkRustCrate (profileName: rec {
+ name = "rand";
+ version = "0.8.5";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"; };
+ features = builtins.concatLists [
+ [ "alloc" ]
+ [ "getrandom" ]
+ [ "libc" ]
+ [ "rand_chacha" ]
+ [ "std" ]
+ [ "std_rng" ]
+ ];
+ dependencies = {
+ ${ if hostPlatform.isUnix then "libc" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.138" { inherit profileName; }).out;
+ rand_chacha = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand_chacha."0.3.1" { inherit profileName; }).out;
+ rand_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand_core."0.6.4" { inherit profileName; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".rand_chacha."0.3.1" = overridableMkRustCrate (profileName: rec {
+ name = "rand_chacha";
+ version = "0.3.1";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"; };
+ features = builtins.concatLists [
+ [ "std" ]
+ ];
+ dependencies = {
+ ppv_lite86 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ppv-lite86."0.2.17" { inherit profileName; }).out;
+ rand_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand_core."0.6.4" { inherit profileName; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".rand_core."0.6.4" = overridableMkRustCrate (profileName: rec {
+ name = "rand_core";
+ version = "0.6.4";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"; };
+ features = builtins.concatLists [
+ [ "alloc" ]
+ [ "getrandom" ]
+ [ "std" ]
+ ];
+ dependencies = {
+ getrandom = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".getrandom."0.2.8" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".rcgen."0.10.0" = overridableMkRustCrate (profileName: rec {
name = "rcgen";
version = "0.10.0";
@@ -1605,7 +1819,7 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"; };
dependencies = {
- ${ if rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap" then "bitflags" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bitflags."1.3.2" { inherit profileName; }).out;
+ bitflags = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bitflags."1.3.2" { inherit profileName; }).out;
};
});
@@ -2181,6 +2395,7 @@ in
[ "proc-macro" ]
[ "quote" ]
[ "visit" ]
+ [ "visit-mut" ]
];
dependencies = {
proc_macro2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.47" { inherit profileName; }).out;
@@ -2239,6 +2454,28 @@ in
};
});
+ "registry+https://github.com/rust-lang/crates.io-index".thiserror."1.0.37" = overridableMkRustCrate (profileName: rec {
+ name = "thiserror";
+ version = "1.0.37";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"; };
+ dependencies = {
+ thiserror_impl = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror-impl."1.0.37" { profileName = "__noProfile"; }).out;
+ };
+ });
+
+ "registry+https://github.com/rust-lang/crates.io-index".thiserror-impl."1.0.37" = overridableMkRustCrate (profileName: rec {
+ name = "thiserror-impl";
+ version = "1.0.37";
+ registry = "registry+https://github.com/rust-lang/crates.io-index";
+ src = fetchCratesIo { inherit name version; sha256 = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"; };
+ dependencies = {
+ proc_macro2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.47" { inherit profileName; }).out;
+ quote = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".quote."1.0.21" { inherit profileName; }).out;
+ syn = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".syn."1.0.105" { inherit profileName; }).out;
+ };
+ });
+
"registry+https://github.com/rust-lang/crates.io-index".thousands."0.2.0" = overridableMkRustCrate (profileName: rec {
name = "thousands";
version = "0.2.0";
@@ -2507,7 +2744,10 @@ in
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.23" { inherit profileName; }).out;
hyper_rustls = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper-rustls."0.23.1" { inherit profileName; }).out;
log = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".log."0.4.17" { inherit profileName; }).out;
+ opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
+ opentelemetry_prometheus = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry-prometheus."0.10.0" { inherit profileName; }).out;
pretty_env_logger = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pretty_env_logger."0.4.0" { inherit profileName; }).out;
+ prometheus = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".prometheus."0.13.3" { inherit profileName; }).out;
rcgen = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rcgen."0.10.0" { inherit profileName; }).out;
regex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".regex."1.7.0" { inherit profileName; }).out;
reqwest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".reqwest."0.11.13" { inherit profileName; }).out;
@@ -2980,9 +3220,9 @@ in
[ "Win32_Storage_FileSystem" ]
[ "Win32_System" ]
[ "Win32_System_IO" ]
- (lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "Win32_System_LibraryLoader")
+ [ "Win32_System_LibraryLoader" ]
[ "Win32_System_Pipes" ]
- (lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "Win32_System_SystemServices")
+ [ "Win32_System_SystemServices" ]
[ "Win32_System_WindowsProgramming" ]
[ "default" ]
];
diff --git a/Cargo.toml b/Cargo.toml
index a41b3c3..416038f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -34,6 +34,9 @@ accept-encoding-fork = "0.2.0-alpha.3"
async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] }
tokio-util = { version = "0.7", features = ["io"] }
uuid = { version = "1.2", features = ["v4"] }
+opentelemetry = "0.17"
+opentelemetry-prometheus = "0.10"
+prometheus = "0.13"
dhat = { version = "0.3", optional = true }
diff --git a/src/https.rs b/src/https.rs
index ba4365d..cb5e1c8 100644
--- a/src/https.rs
+++ b/src/https.rs
@@ -21,6 +21,8 @@ use tokio::sync::watch;
use tokio_rustls::TlsAcceptor;
use tokio_util::io::{ReaderStream, StreamReader};
+use opentelemetry::{metrics, KeyValue};
+
use crate::cert_store::{CertStore, StoreResolver};
use crate::proxy_config::ProxyConfig;
use crate::reverse_proxy;
@@ -33,6 +35,11 @@ pub struct HttpsConfig {
pub compress_mime_types: Vec<String>,
}
+struct HttpsMetrics {
+ requests_received: metrics::Counter<u64>,
+ requests_served: metrics::Counter<u64>,
+}
+
pub async fn serve_https(
config: HttpsConfig,
cert_store: Arc<CertStore>,
@@ -41,6 +48,18 @@ pub async fn serve_https(
) -> Result<()> {
let config = Arc::new(config);
+ let meter = opentelemetry::global::meter("tricot");
+ let metrics = Arc::new(HttpsMetrics {
+ requests_received: meter
+ .u64_counter("https_requests_received")
+ .with_description("Total number of requests received over HTTPS")
+ .init(),
+ requests_served: meter
+ .u64_counter("https_requests_served")
+ .with_description("Total number of requests served over HTTPS")
+ .init(),
+ });
+
let mut tls_cfg = rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
@@ -71,6 +90,7 @@ pub async fn serve_https(
let rx_proxy_config = rx_proxy_config.clone();
let tls_acceptor = tls_acceptor.clone();
let config = config.clone();
+ let metrics = metrics.clone();
let mut must_exit_2 = must_exit.clone();
let conn = tokio::spawn(async move {
@@ -84,7 +104,8 @@ pub async fn serve_https(
let https_config = config.clone();
let proxy_config: Arc<ProxyConfig> =
rx_proxy_config.borrow().clone();
- handle_outer(remote_addr, req, https_config, proxy_config)
+ let metrics = metrics.clone();
+ handle_outer(remote_addr, req, https_config, proxy_config, metrics)
}),
)
.with_upgrades();
@@ -124,17 +145,43 @@ async fn handle_outer(
req: Request<Body>,
https_config: Arc<HttpsConfig>,
proxy_config: Arc<ProxyConfig>,
+ metrics: Arc<HttpsMetrics>,
) -> Result<Response<Body>, Infallible> {
- match handle(remote_addr, req, https_config, proxy_config).await {
+ let mut tags = vec![
+ KeyValue::new("method", req.method().to_string()),
+ KeyValue::new(
+ "host",
+ req.uri()
+ .authority()
+ .map(|auth| auth.to_string())
+ .or_else(|| {
+ req.headers()
+ .get("host")
+ .map(|host| host.to_str().unwrap_or_default().to_string())
+ })
+ .unwrap_or_default(),
+ ),
+ ];
+ metrics.requests_received.add(1, &tags);
+
+ let resp = match handle(remote_addr, req, https_config, proxy_config, &mut tags).await {
Err(e) => {
warn!("Handler error: {}", e);
- Ok(Response::builder()
+ Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from(format!("{}", e)))
- .unwrap())
+ .unwrap()
}
- Ok(r) => Ok(r),
- }
+ Ok(r) => r,
+ };
+
+ tags.push(KeyValue::new(
+ "response_code",
+ resp.status().as_u16().to_string(),
+ ));
+ metrics.requests_served.add(1, &tags);
+
+ Ok(resp)
}
// Custom echo service, handling two different routes and a
@@ -144,6 +191,7 @@ async fn handle(
req: Request<Body>,
https_config: Arc<HttpsConfig>,
proxy_config: Arc<ProxyConfig>,
+ tags: &mut Vec<KeyValue>,
) -> Result<Response<Body>, anyhow::Error> {
let method = req.method().clone();
let uri = req.uri().to_string();
@@ -184,6 +232,18 @@ async fn handle(
});
if let Some(proxy_to) = best_match {
+ tags.push(KeyValue::new("service_name", proxy_to.service_name.clone()));
+ tags.push(KeyValue::new(
+ "target_addr",
+ proxy_to.target_addr.to_string(),
+ ));
+ tags.push(KeyValue::new(
+ "https_target",
+ proxy_to.https_target.to_string(),
+ ));
+ tags.push(KeyValue::new("same_node", proxy_to.same_node.to_string()));
+ tags.push(KeyValue::new("same_site", proxy_to.same_site.to_string()));
+
proxy_to.calls.fetch_add(1, Ordering::SeqCst);
debug!("{}{} -> {}", host, path, proxy_to);
diff --git a/src/main.rs b/src/main.rs
index edc79b4..cb39c49 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ mod cert_store;
mod consul;
mod http;
mod https;
+mod metrics;
mod proxy_config;
mod reverse_proxy;
mod tls_util;
@@ -80,6 +81,10 @@ struct Opt {
)]
pub https_bind_addr: SocketAddr,
+ /// Bind address for metrics server (Prometheus format over HTTP)
+ #[structopt(long = "metrics-bind-addr", env = "TRICOT_METRICS_BIND_ADDR")]
+ pub metrics_bind_addr: Option<SocketAddr>,
+
/// E-mail address for Let's Encrypt certificate requests
#[structopt(long = "letsencrypt-email", env = "TRICOT_LETSENCRYPT_EMAIL")]
pub letsencrypt_email: String,
@@ -123,6 +128,8 @@ async fn main() {
let _ = provoke_exit.send(true);
};
+ let metrics_server = metrics::MetricsServer::init(opt.metrics_bind_addr);
+
let consul_config = consul::ConsulConfig {
addr: opt.consul_addr.clone(),
ca_cert: opt.consul_ca_cert.clone(),
@@ -143,6 +150,13 @@ async fn main() {
exit_on_err.clone(),
);
+ let metrics_task = tokio::spawn(
+ metrics_server
+ .run(wait_from(exit_signal.clone()))
+ .map_err(exit_on_err.clone())
+ .then(|_| async { info!("Metrics server exited") }),
+ );
+
let http_task = tokio::spawn(
http::serve_http(
opt.http_bind_addr,
@@ -176,6 +190,7 @@ async fn main() {
let dump_task = tokio::spawn(dump_config_on_change(rx_proxy_config, exit_signal.clone()));
+ let _ = metrics_task.await.expect("Tokio task await failure");
let _ = http_task.await.expect("Tokio task await failure");
let _ = https_task.await.expect("Tokio task await failure");
let _ = dump_task.await.expect("Tokio task await failure");
diff --git a/src/metrics.rs b/src/metrics.rs
new file mode 100644
index 0000000..c635269
--- /dev/null
+++ b/src/metrics.rs
@@ -0,0 +1,83 @@
+use std::convert::Infallible;
+use std::net::SocketAddr;
+use std::sync::Arc;
+
+use anyhow::Result;
+use futures::future::*;
+use log::*;
+
+use hyper::{
+ header::CONTENT_TYPE,
+ service::{make_service_fn, service_fn},
+ Body, Method, Request, Response, Server,
+};
+use opentelemetry_prometheus::PrometheusExporter;
+use prometheus::{Encoder, TextEncoder};
+
+pub struct MetricsServer {
+ bind_addr: Option<SocketAddr>,
+ exporter: PrometheusExporter,
+}
+
+impl MetricsServer {
+ pub fn init(bind_addr: Option<SocketAddr>) -> MetricsServer {
+ let exporter = opentelemetry_prometheus::exporter().init();
+ Self {
+ bind_addr,
+ exporter,
+ }
+ }
+
+ pub async fn run(self, shutdown_signal: impl Future<Output = ()>) -> Result<()> {
+ if let Some(addr) = self.bind_addr {
+ let metrics_server = Arc::new(self);
+
+ let make_svc = make_service_fn(move |_conn| {
+ let metrics_server = metrics_server.clone();
+ async move {
+ Ok::<_, Infallible>(service_fn(move |req| {
+ metrics_server.clone().serve_req(req)
+ }))
+ }
+ });
+
+ let server = Server::bind(&addr).serve(make_svc);
+ let graceful = server.with_graceful_shutdown(shutdown_signal);
+ info!("Metrics server listening on http://{}", addr);
+
+ graceful.await?;
+ } else {
+ info!("Metrics server is disabled");
+ }
+
+ Ok(())
+ }
+
+ async fn serve_req(
+ self: Arc<MetricsServer>,
+ req: Request<Body>,
+ ) -> Result<Response<Body>, hyper::Error> {
+ debug!("{} {}", req.method(), req.uri());
+
+ let response = match (req.method(), req.uri().path()) {
+ (&Method::GET, "/metrics") => {
+ let mut buffer = vec![];
+ let encoder = TextEncoder::new();
+ let metric_families = self.exporter.registry().gather();
+ encoder.encode(&metric_families, &mut buffer).unwrap();
+
+ Response::builder()
+ .status(200)
+ .header(CONTENT_TYPE, encoder.format_type())
+ .body(Body::from(buffer))
+ .unwrap()
+ }
+ _ => Response::builder()
+ .status(404)
+ .body(Body::from("Not implemented"))
+ .unwrap(),
+ };
+
+ Ok(response)
+ }
+}
diff --git a/src/proxy_config.rs b/src/proxy_config.rs
index e45cc7b..24ade8b 100644
--- a/src/proxy_config.rs
+++ b/src/proxy_config.rs
@@ -4,6 +4,7 @@ use std::sync::{atomic, Arc};
use std::{cmp, time::Duration};
use anyhow::Result;
+use opentelemetry::{metrics, KeyValue};
use futures::future::BoxFuture;
use futures::stream::{FuturesUnordered, StreamExt};
@@ -38,6 +39,15 @@ impl HostDescription {
}
}
+impl std::fmt::Display for HostDescription {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ HostDescription::Hostname(h) => write!(f, "{}", h),
+ HostDescription::Pattern(p) => write!(f, "Pattern('{}')", p.as_str()),
+ }
+ }
+}
+
#[derive(Debug)]
pub struct ProxyEntry {
/// Publicly exposed TLS hostnames for matching this rule
@@ -47,6 +57,8 @@ pub struct ProxyEntry {
/// Priority with which this rule is considered (highest first)
pub priority: u32,
+ /// Consul service name
+ pub service_name: String,
/// Node address (ip+port) to handle requests that match this entry
pub target_addr: SocketAddr,
/// Is the target serving HTTPS instead of HTTP?
@@ -75,14 +87,11 @@ impl std::fmt::Display for ProxyEntry {
write!(f, "https://")?;
}
write!(f, "{} ", self.target_addr)?;
- match &self.host {
- HostDescription::Hostname(h) => write!(f, "{}", h)?,
- HostDescription::Pattern(p) => write!(f, "Pattern('{}')", p.as_str())?,
- }
write!(
f,
- "{} {}",
- self.path_prefix.as_ref().unwrap_or(&String::new()),
+ "{}{} {}",
+ self.host,
+ self.path_prefix.as_deref().unwrap_or_default(),
self.priority
)?;
if self.same_node {
@@ -113,6 +122,7 @@ fn retry_to_time(retries: u32, max_time: Duration) -> Duration {
}
fn parse_tricot_tag(
+ service_name: String,
tag: &str,
target_addr: SocketAddr,
add_headers: &[(String, String)],
@@ -148,6 +158,7 @@ fn parse_tricot_tag(
};
Some(ProxyEntry {
+ service_name,
target_addr,
https_target: (splits[0] == "tricot-https"),
host,
@@ -178,7 +189,7 @@ fn parse_consul_catalog(
let mut entries = vec![];
- for (_, svc) in catalog.services.iter() {
+ for (service_name, svc) in catalog.services.iter() {
let ip_addr = match svc.address.parse() {
Ok(ip) => ip,
_ => match catalog.node.address.parse() {
@@ -210,7 +221,14 @@ fn parse_consul_catalog(
}
for tag in svc.tags.iter() {
- if let Some(ent) = parse_tricot_tag(tag, addr, &add_headers[..], same_node, same_site) {
+ if let Some(ent) = parse_tricot_tag(
+ service_name.clone(),
+ tag,
+ addr,
+ &add_headers[..],
+ same_node,
+ same_site,
+ ) {
entries.push(ent);
}
}
@@ -239,6 +257,7 @@ pub fn spawn_proxy_config_task(
entries: Vec::new(),
}));
+ let metrics = ProxyConfigMetrics::new(rx.clone());
let consul = Arc::new(consul);
tokio::spawn(async move {
@@ -348,11 +367,46 @@ pub fn spawn_proxy_config_task(
tx.send(Arc::new(config)).expect("Internal error");
}
+
+ drop(metrics); // ensure Metrics lives up to here
});
rx
}
+// ----
+
+struct ProxyConfigMetrics {
+ _proxy_config_entries: metrics::ValueObserver<u64>,
+}
+
+impl ProxyConfigMetrics {
+ fn new(rx: watch::Receiver<Arc<ProxyConfig>>) -> Self {
+ let meter = opentelemetry::global::meter("tricot");
+ Self {
+ _proxy_config_entries: meter
+ .u64_value_observer("proxy_config_entries", move |observer| {
+ let mut patterns = HashMap::new();
+ for ent in rx.borrow().entries.iter() {
+ let pat = format!(
+ "{}{}",
+ ent.host,
+ ent.path_prefix.as_deref().unwrap_or_default()
+ );
+ *patterns.entry(pat).or_default() += 1;
+ }
+ for (pat, num) in patterns {
+ observer.observe(num, &[KeyValue::new("host", pat)]);
+ }
+ })
+ .with_description("Number of proxy entries (back-ends) configured in Tricot")
+ .init(),
+ }
+ }
+}
+
+// ----
+
#[cfg(test)]
mod tests {
use super::*;