Add basic support for metrics

This commit is contained in:
Alex 2022-12-05 18:43:48 +01:00
parent 43a0fe14b2
commit 5d38f2cf7f
Signed by untrusted user: lx
GPG key ID: 0E496D15096376BE
7 changed files with 655 additions and 28 deletions

172
Cargo.lock generated
View file

@ -108,6 +108,17 @@ dependencies = [
"zstd-safe", "zstd-safe",
] ]
[[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]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -311,6 +322,25 @@ dependencies = [
"cfg-if", "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]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.83" version = "1.0.83"
@ -355,6 +385,16 @@ dependencies = [
"syn", "syn",
] ]
[[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]] [[package]]
name = "dhat" name = "dhat"
version = "0.3.2" version = "0.3.2"
@ -979,6 +1019,38 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[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]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -1017,6 +1089,26 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 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]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@ -1035,6 +1127,12 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "pretty_env_logger" name = "pretty_env_logger"
version = "0.4.0" version = "0.4.0"
@ -1084,6 +1182,27 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[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]] [[package]]
name = "publicsuffix" name = "publicsuffix"
version = "1.5.6" version = "1.5.6"
@ -1118,6 +1237,36 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "rcgen" name = "rcgen"
version = "0.10.0" version = "0.10.0"
@ -1599,6 +1748,26 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[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]] [[package]]
name = "thousands" name = "thousands"
version = "0.2.0" version = "0.2.0"
@ -1785,7 +1954,10 @@ dependencies = [
"hyper", "hyper",
"hyper-rustls", "hyper-rustls",
"log", "log",
"opentelemetry",
"opentelemetry-prometheus",
"pretty_env_logger", "pretty_env_logger",
"prometheus",
"rcgen", "rcgen",
"regex", "regex",
"reqwest", "reqwest",

268
Cargo.nix
View file

@ -23,7 +23,7 @@ args@{
ignoreLockHash, ignoreLockHash,
}: }:
let let
nixifiedLockHash = "8b9764c8874557f30d0d72cb4e6453209d5ab90c71cfe15c3367a366506066d2"; nixifiedLockHash = "ba43baa059b58c2c0ae0bf86c8d8dc3663b7bd3ecb95274246a3d7123238271a";
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc; workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock); currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
lockHashIgnored = if ignoreLockHash 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 { "registry+https://github.com/rust-lang/crates.io-index".atty."0.2.14" = overridableMkRustCrate (profileName: rec {
name = "atty"; name = "atty";
version = "0.2.14"; 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 { "registry+https://github.com/rust-lang/crates.io-index".cxx."1.0.83" = overridableMkRustCrate (profileName: rec {
name = "cxx"; name = "cxx";
version = "1.0.83"; 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 { "registry+https://github.com/rust-lang/crates.io-index".dhat."0.3.2" = overridableMkRustCrate (profileName: rec {
name = "dhat"; name = "dhat";
version = "0.3.2"; version = "0.3.2";
@ -752,6 +807,7 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"; }; src = fetchCratesIo { inherit name version; sha256 = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"; };
features = builtins.concatLists [ features = builtins.concatLists [
[ "default" ]
[ "std" ] [ "std" ]
]; ];
dependencies = { dependencies = {
@ -846,6 +902,9 @@ in
version = "0.2.8"; version = "0.2.8";
registry = "registry+https://github.com/rust-lang/crates.io-index"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"; }; src = fetchCratesIo { inherit name version; sha256 = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"; };
features = builtins.concatLists [
[ "std" ]
];
dependencies = { dependencies = {
cfg_if = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.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.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"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"; }; src = fetchCratesIo { inherit name version; sha256 = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"; };
dependencies = { 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 = { 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 { "registry+https://github.com/rust-lang/crates.io-index".parking_lot."0.12.1" = overridableMkRustCrate (profileName: rec {
name = "parking_lot"; name = "parking_lot";
version = "0.12.1"; version = "0.12.1";
registry = "registry+https://github.com/rust-lang/crates.io-index"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"; }; src = fetchCratesIo { inherit name version; sha256 = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"; };
features = builtins.concatLists [ features = builtins.concatLists [
(lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "default") [ "default" ]
]; ];
dependencies = { 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; lock_api = (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; 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"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"; }; src = fetchCratesIo { inherit name version; sha256 = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"; };
dependencies = { 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; cfg_if = (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 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 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; smallvec = (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; ${ 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 { "registry+https://github.com/rust-lang/crates.io-index".pin-project-lite."0.2.9" = overridableMkRustCrate (profileName: rec {
name = "pin-project-lite"; name = "pin-project-lite";
version = "0.2.9"; version = "0.2.9";
@ -1472,6 +1599,17 @@ in
src = fetchCratesIo { inherit name version; sha256 = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"; }; 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 { "registry+https://github.com/rust-lang/crates.io-index".pretty_env_logger."0.4.0" = overridableMkRustCrate (profileName: rec {
name = "pretty_env_logger"; name = "pretty_env_logger";
version = "0.4.0"; 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 { "registry+https://github.com/rust-lang/crates.io-index".publicsuffix."1.5.6" = overridableMkRustCrate (profileName: rec {
name = "publicsuffix"; name = "publicsuffix";
version = "1.5.6"; 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 { "registry+https://github.com/rust-lang/crates.io-index".rcgen."0.10.0" = overridableMkRustCrate (profileName: rec {
name = "rcgen"; name = "rcgen";
version = "0.10.0"; version = "0.10.0";
@ -1605,7 +1819,7 @@ in
registry = "registry+https://github.com/rust-lang/crates.io-index"; registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"; }; src = fetchCratesIo { inherit name version; sha256 = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"; };
dependencies = { 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" ] [ "proc-macro" ]
[ "quote" ] [ "quote" ]
[ "visit" ] [ "visit" ]
[ "visit-mut" ]
]; ];
dependencies = { dependencies = {
proc_macro2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.47" { inherit profileName; }).out; 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 { "registry+https://github.com/rust-lang/crates.io-index".thousands."0.2.0" = overridableMkRustCrate (profileName: rec {
name = "thousands"; name = "thousands";
version = "0.2.0"; 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 = (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; 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; 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; 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; 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; 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; 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_Storage_FileSystem" ]
[ "Win32_System" ] [ "Win32_System" ]
[ "Win32_System_IO" ] [ "Win32_System_IO" ]
(lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "Win32_System_LibraryLoader") [ "Win32_System_LibraryLoader" ]
[ "Win32_System_Pipes" ] [ "Win32_System_Pipes" ]
(lib.optional (rootFeatures' ? "tricot/dhat" || rootFeatures' ? "tricot/dhat-heap") "Win32_System_SystemServices") [ "Win32_System_SystemServices" ]
[ "Win32_System_WindowsProgramming" ] [ "Win32_System_WindowsProgramming" ]
[ "default" ] [ "default" ]
]; ];

View file

@ -34,6 +34,9 @@ accept-encoding-fork = "0.2.0-alpha.3"
async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] } async-compression = { version = "0.3", features = ["tokio", "gzip", "zstd", "deflate", "brotli"] }
tokio-util = { version = "0.7", features = ["io"] } tokio-util = { version = "0.7", features = ["io"] }
uuid = { version = "1.2", features = ["v4"] } uuid = { version = "1.2", features = ["v4"] }
opentelemetry = "0.17"
opentelemetry-prometheus = "0.10"
prometheus = "0.13"
dhat = { version = "0.3", optional = true } dhat = { version = "0.3", optional = true }

View file

@ -21,6 +21,8 @@ use tokio::sync::watch;
use tokio_rustls::TlsAcceptor; use tokio_rustls::TlsAcceptor;
use tokio_util::io::{ReaderStream, StreamReader}; use tokio_util::io::{ReaderStream, StreamReader};
use opentelemetry::{metrics, KeyValue};
use crate::cert_store::{CertStore, StoreResolver}; use crate::cert_store::{CertStore, StoreResolver};
use crate::proxy_config::ProxyConfig; use crate::proxy_config::ProxyConfig;
use crate::reverse_proxy; use crate::reverse_proxy;
@ -33,6 +35,11 @@ pub struct HttpsConfig {
pub compress_mime_types: Vec<String>, pub compress_mime_types: Vec<String>,
} }
struct HttpsMetrics {
requests_received: metrics::Counter<u64>,
requests_served: metrics::Counter<u64>,
}
pub async fn serve_https( pub async fn serve_https(
config: HttpsConfig, config: HttpsConfig,
cert_store: Arc<CertStore>, cert_store: Arc<CertStore>,
@ -41,6 +48,18 @@ pub async fn serve_https(
) -> Result<()> { ) -> Result<()> {
let config = Arc::new(config); 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() let mut tls_cfg = rustls::ServerConfig::builder()
.with_safe_defaults() .with_safe_defaults()
.with_no_client_auth() .with_no_client_auth()
@ -71,6 +90,7 @@ pub async fn serve_https(
let rx_proxy_config = rx_proxy_config.clone(); let rx_proxy_config = rx_proxy_config.clone();
let tls_acceptor = tls_acceptor.clone(); let tls_acceptor = tls_acceptor.clone();
let config = config.clone(); let config = config.clone();
let metrics = metrics.clone();
let mut must_exit_2 = must_exit.clone(); let mut must_exit_2 = must_exit.clone();
let conn = tokio::spawn(async move { let conn = tokio::spawn(async move {
@ -84,7 +104,8 @@ pub async fn serve_https(
let https_config = config.clone(); let https_config = config.clone();
let proxy_config: Arc<ProxyConfig> = let proxy_config: Arc<ProxyConfig> =
rx_proxy_config.borrow().clone(); 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(); .with_upgrades();
@ -124,17 +145,43 @@ async fn handle_outer(
req: Request<Body>, req: Request<Body>,
https_config: Arc<HttpsConfig>, https_config: Arc<HttpsConfig>,
proxy_config: Arc<ProxyConfig>, proxy_config: Arc<ProxyConfig>,
metrics: Arc<HttpsMetrics>,
) -> Result<Response<Body>, Infallible> { ) -> 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) => { Err(e) => {
warn!("Handler error: {}", e); warn!("Handler error: {}", e);
Ok(Response::builder() Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR) .status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from(format!("{}", e))) .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 // Custom echo service, handling two different routes and a
@ -144,6 +191,7 @@ async fn handle(
req: Request<Body>, req: Request<Body>,
https_config: Arc<HttpsConfig>, https_config: Arc<HttpsConfig>,
proxy_config: Arc<ProxyConfig>, proxy_config: Arc<ProxyConfig>,
tags: &mut Vec<KeyValue>,
) -> Result<Response<Body>, anyhow::Error> { ) -> Result<Response<Body>, anyhow::Error> {
let method = req.method().clone(); let method = req.method().clone();
let uri = req.uri().to_string(); let uri = req.uri().to_string();
@ -184,6 +232,18 @@ async fn handle(
}); });
if let Some(proxy_to) = best_match { 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); proxy_to.calls.fetch_add(1, Ordering::SeqCst);
debug!("{}{} -> {}", host, path, proxy_to); debug!("{}{} -> {}", host, path, proxy_to);

View file

@ -15,6 +15,7 @@ mod cert_store;
mod consul; mod consul;
mod http; mod http;
mod https; mod https;
mod metrics;
mod proxy_config; mod proxy_config;
mod reverse_proxy; mod reverse_proxy;
mod tls_util; mod tls_util;
@ -80,6 +81,10 @@ struct Opt {
)] )]
pub https_bind_addr: SocketAddr, 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 /// E-mail address for Let's Encrypt certificate requests
#[structopt(long = "letsencrypt-email", env = "TRICOT_LETSENCRYPT_EMAIL")] #[structopt(long = "letsencrypt-email", env = "TRICOT_LETSENCRYPT_EMAIL")]
pub letsencrypt_email: String, pub letsencrypt_email: String,
@ -123,6 +128,8 @@ async fn main() {
let _ = provoke_exit.send(true); let _ = provoke_exit.send(true);
}; };
let metrics_server = metrics::MetricsServer::init(opt.metrics_bind_addr);
let consul_config = consul::ConsulConfig { let consul_config = consul::ConsulConfig {
addr: opt.consul_addr.clone(), addr: opt.consul_addr.clone(),
ca_cert: opt.consul_ca_cert.clone(), ca_cert: opt.consul_ca_cert.clone(),
@ -143,6 +150,13 @@ async fn main() {
exit_on_err.clone(), 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( let http_task = tokio::spawn(
http::serve_http( http::serve_http(
opt.http_bind_addr, 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 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 _ = http_task.await.expect("Tokio task await failure");
let _ = https_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"); let _ = dump_task.await.expect("Tokio task await failure");

83
src/metrics.rs Normal file
View file

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

View file

@ -4,6 +4,7 @@ use std::sync::{atomic, Arc};
use std::{cmp, time::Duration}; use std::{cmp, time::Duration};
use anyhow::Result; use anyhow::Result;
use opentelemetry::{metrics, KeyValue};
use futures::future::BoxFuture; use futures::future::BoxFuture;
use futures::stream::{FuturesUnordered, StreamExt}; 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)] #[derive(Debug)]
pub struct ProxyEntry { pub struct ProxyEntry {
/// Publicly exposed TLS hostnames for matching this rule /// Publicly exposed TLS hostnames for matching this rule
@ -47,6 +57,8 @@ pub struct ProxyEntry {
/// Priority with which this rule is considered (highest first) /// Priority with which this rule is considered (highest first)
pub priority: u32, pub priority: u32,
/// Consul service name
pub service_name: String,
/// Node address (ip+port) to handle requests that match this entry /// Node address (ip+port) to handle requests that match this entry
pub target_addr: SocketAddr, pub target_addr: SocketAddr,
/// Is the target serving HTTPS instead of HTTP? /// Is the target serving HTTPS instead of HTTP?
@ -75,14 +87,11 @@ impl std::fmt::Display for ProxyEntry {
write!(f, "https://")?; write!(f, "https://")?;
} }
write!(f, "{} ", self.target_addr)?; write!(f, "{} ", self.target_addr)?;
match &self.host {
HostDescription::Hostname(h) => write!(f, "{}", h)?,
HostDescription::Pattern(p) => write!(f, "Pattern('{}')", p.as_str())?,
}
write!( write!(
f, f,
"{} {}", "{}{} {}",
self.path_prefix.as_ref().unwrap_or(&String::new()), self.host,
self.path_prefix.as_deref().unwrap_or_default(),
self.priority self.priority
)?; )?;
if self.same_node { if self.same_node {
@ -113,6 +122,7 @@ fn retry_to_time(retries: u32, max_time: Duration) -> Duration {
} }
fn parse_tricot_tag( fn parse_tricot_tag(
service_name: String,
tag: &str, tag: &str,
target_addr: SocketAddr, target_addr: SocketAddr,
add_headers: &[(String, String)], add_headers: &[(String, String)],
@ -148,6 +158,7 @@ fn parse_tricot_tag(
}; };
Some(ProxyEntry { Some(ProxyEntry {
service_name,
target_addr, target_addr,
https_target: (splits[0] == "tricot-https"), https_target: (splits[0] == "tricot-https"),
host, host,
@ -178,7 +189,7 @@ fn parse_consul_catalog(
let mut entries = vec![]; 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() { let ip_addr = match svc.address.parse() {
Ok(ip) => ip, Ok(ip) => ip,
_ => match catalog.node.address.parse() { _ => match catalog.node.address.parse() {
@ -210,7 +221,14 @@ fn parse_consul_catalog(
} }
for tag in svc.tags.iter() { 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); entries.push(ent);
} }
} }
@ -239,6 +257,7 @@ pub fn spawn_proxy_config_task(
entries: Vec::new(), entries: Vec::new(),
})); }));
let metrics = ProxyConfigMetrics::new(rx.clone());
let consul = Arc::new(consul); let consul = Arc::new(consul);
tokio::spawn(async move { tokio::spawn(async move {
@ -348,11 +367,46 @@ pub fn spawn_proxy_config_task(
tx.send(Arc::new(config)).expect("Internal error"); tx.send(Arc::new(config)).expect("Internal error");
} }
drop(metrics); // ensure Metrics lives up to here
}); });
rx 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;