Skip to content

Commit cebd129

Browse files
authored
Merge pull request #14700 from Turbo87/add-otel-metrics
Add `opentelemetry` metrics support
2 parents ac319d5 + 93d345f commit cebd129

25 files changed

Lines changed: 926 additions & 59 deletions

File tree

Cargo.lock

Lines changed: 133 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ crates_io_env_vars = { path = "crates/crates_io_env_vars" }
9898
crates_io_fastly = { path = "crates/crates_io_fastly" }
9999
crates_io_github = { path = "crates/crates_io_github" }
100100
crates_io_github_app = { path = "crates/crates_io_github_app" }
101+
crates_io_heroku = { path = "crates/crates_io_heroku" }
101102
crates_io_index = { path = "crates/crates_io_index" }
102103
crates_io_linecount = { path = "crates/crates_io_linecount" }
103104
crates_io_markdown = { path = "crates/crates_io_markdown" }
@@ -139,6 +140,9 @@ moka = { version = "=0.12.16", default-features = false, features = ["future"] }
139140
native-tls = "=0.2.18"
140141
oauth2 = { version = "=5.0.0", default-features = false }
141142
object_store = { version = "=0.14.1", features = ["aws"] }
143+
opentelemetry = { version = "=0.32.0", default-features = false, features = ["metrics"] }
144+
opentelemetry-otlp = { version = "=0.32.0", default-features = false, features = ["gzip-http", "http-proto", "internal-logs", "metrics", "reqwest-blocking-client", "zstd-http"] }
145+
opentelemetry_sdk = { version = "=0.32.1", default-features = false, features = ["metrics"] }
142146
p256 = "=0.14.0"
143147
parking_lot = "=0.12.5"
144148
paste = "=1.0.15"
@@ -171,6 +175,7 @@ typomania = { version = "=0.2.0", default-features = false }
171175
url = "=2.5.8"
172176
utoipa = { version = "=5.5.0", features = ["chrono"] }
173177
utoipa-axum = "=0.2.0"
178+
uuid = { version = "=1.26.1", features = ["v4"] }
174179

175180
[dev-dependencies]
176181
bytes = "=1.12.1"
@@ -188,6 +193,7 @@ diesel = { version = "=2.3.13", features = ["r2d2"] }
188193
googletest = "=0.14.3"
189194
insta = { version = "=1.48.0", features = ["glob", "json", "redactions"] }
190195
jsonwebtoken = { version = "=11.0.0", features = ["aws_lc_rs"] }
196+
opentelemetry_sdk = { version = "=0.32.1", default-features = false, features = ["testing"] }
191197
quoted_printable = "=0.5.2"
192198
sentry = { version = "=0.49.2", features = ["test"] }
193199
tokio = "=1.53.1"

crates/crates_io_heroku/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,48 @@
22

33
use crates_io_env_vars::var;
44

5+
/// Returns whether the process is running on Heroku, as indicated by `HEROKU`.
6+
pub fn is_heroku() -> anyhow::Result<bool> {
7+
Ok(var("HEROKU")?.is_some())
8+
}
9+
10+
/// Returns the dyno name from `DYNO`, or `None` when unset.
11+
///
12+
/// An example value may be: `"web.1"`.
13+
pub fn dyno() -> anyhow::Result<Option<String>> {
14+
var("DYNO")
15+
}
16+
17+
/// Returns the dyno UUID from `HEROKU_DYNO_ID`, or `None` when unset.
18+
///
19+
/// An example value may be: `"1vac4117-c29f-4312-521e-ba4d8638c1ac"`.
20+
pub fn dyno_id() -> anyhow::Result<Option<String>> {
21+
var("HEROKU_DYNO_ID")
22+
}
23+
24+
/// Returns the release identifier from `HEROKU_RELEASE_VERSION`, or `None` when
25+
/// unset.
26+
///
27+
/// An example value may be: `"v42"`.
28+
pub fn release_version() -> anyhow::Result<Option<String>> {
29+
var("HEROKU_RELEASE_VERSION")
30+
}
31+
32+
/// Returns the application UUID from `HEROKU_APP_ID`, or `None` when unset.
33+
///
34+
/// An example value may be: `"9daa2797-e49b-4624-932f-ec3f9688e3da"`.
35+
pub fn app_id() -> anyhow::Result<Option<String>> {
36+
var("HEROKU_APP_ID")
37+
}
38+
39+
/// Returns the release timestamp from `HEROKU_RELEASE_CREATED_AT`, or `None`
40+
/// when unset.
41+
///
42+
/// An example value may be: `"2015-04-02T18:00:42Z"`.
43+
pub fn release_created_at() -> anyhow::Result<Option<String>> {
44+
var("HEROKU_RELEASE_CREATED_AT")
45+
}
46+
547
/// Returns the Git SHA of the currently deployed commit.
648
///
749
/// This function tries `HEROKU_BUILD_COMMIT` first (the current standard),

src/bin/crates-io/background_worker.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use crates_io::Emails;
1616
use crates_io::cloudfront::CloudFront;
1717
use crates_io::config::SharedConfig;
1818
use crates_io::db;
19+
use crates_io::metrics::consts::METER_NAME;
20+
use crates_io::metrics::{WorkerMetrics, meter_provider};
1921
use crates_io::ssh;
2022
use crates_io::storage::Storage;
2123
use crates_io::worker::{RunnerExt, WorkerContext};
@@ -56,6 +58,10 @@ pub fn run() -> anyhow::Result<()> {
5658
// increase the statement timeout a bit…
5759
config.db.primary.statement_timeout = Duration::from_secs(4 * 60 * 60);
5860

61+
let meter_provider = meter_provider(&config);
62+
let meter = meter_provider.meter(METER_NAME);
63+
let worker_metrics = WorkerMetrics::new(&meter);
64+
5965
let runtime = tokio::runtime::Builder::new_multi_thread()
6066
.enable_all()
6167
.build()
@@ -79,7 +85,9 @@ pub fn run() -> anyhow::Result<()> {
7985

8086
let user_agent = crates_io_version::user_agent();
8187
let http_client = Client::builder().user_agent(user_agent).build()?;
82-
let datadog = config.datadog.client(http_client.clone()).map(Arc::new);
88+
let datadog = (!config.metrics.otlp_enabled)
89+
.then(|| config.datadog.client(http_client.clone()).map(Arc::new))
90+
.flatten();
8391

8492
let cloudfront = CloudFront::from_environment();
8593
let storage = Arc::new(Storage::from_config(&config.storage));
@@ -103,9 +111,11 @@ pub fn run() -> anyhow::Result<()> {
103111
let sync_github_app = build_sync_github_app()?;
104112

105113
let deadpool = db::create_pool(&config.db.primary);
114+
worker_metrics.track_db_pool("worker", &deadpool);
106115

107116
let ctx = WorkerContext::builder()
108117
.config(Arc::new(config))
118+
.metrics(worker_metrics)
109119
.repository_config(repository_config)
110120
.maybe_cloudfront(cloudfront)
111121
.maybe_fastly(fastly)
@@ -143,7 +153,12 @@ pub fn run() -> anyhow::Result<()> {
143153

144154
runtime.block_on(async {
145155
let handle = runner.start();
146-
crates_io::metrics::datadog::spawn(&ctx.config, ctx.deadpool.clone(), datadog);
156+
crates_io::metrics::datadog::spawn(
157+
&ctx.config,
158+
ctx.deadpool.clone(),
159+
ctx.metrics.clone(),
160+
datadog,
161+
);
147162

148163
info!("Runner booted, running jobs");
149164
handle.wait_for_shutdown().await

src/bin/crates-io/server.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crates_io::config::SharedConfig;
2+
use crates_io::metrics::consts::METER_NAME;
3+
use crates_io::metrics::{LogEncoder, ServerMetrics};
24
use crates_io::middleware::normalize_path::normalize_path;
3-
use crates_io::{Emails, ServerContext, metrics::LogEncoder};
5+
use crates_io::{Emails, ServerContext};
46
use std::{sync::Arc, time::Duration};
57

68
use axum::ServiceExt;
@@ -25,6 +27,8 @@ pub fn run() -> anyhow::Result<()> {
2527
let _span = info_span!("server.run");
2628

2729
let config = SharedConfig::from_environment()?;
30+
let meter_provider = crates_io::metrics::meter_provider(&config);
31+
let meter = meter_provider.meter(METER_NAME);
2832

2933
let emails = Emails::from_environment(&config);
3034

@@ -41,10 +45,16 @@ pub fn run() -> anyhow::Result<()> {
4145
.trustpub_providers(&list("TRUSTPUB_PROVIDERS")?)
4246
.emails(emails)
4347
.storage_from_config(&config.storage)
48+
.metrics(ServerMetrics::new(&meter))
4449
.rate_limiter_from_config(config.rate_limits.actions.clone())
4550
.config(Arc::new(config))
4651
.build();
4752

53+
ctx.metrics.track_db_pool("primary", &ctx.primary_database);
54+
if let Some(pool) = &ctx.replica_database {
55+
ctx.metrics.track_db_pool("replica", pool);
56+
}
57+
4858
// Start the background thread periodically logging instance metrics.
4959
log_instance_metrics_thread(ctx.clone());
5060

0 commit comments

Comments
 (0)