Skip to content

Commit a0af9ab

Browse files
pietroalbiniJoshua Nelson
authored andcommitted
web: add metrics for the rustdoc rendering times
1 parent 1dc79b8 commit a0af9ab

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/web/metrics.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ lazy_static::lazy_static! {
7272
)
7373
.unwrap();
7474

75+
pub static ref RUSTDOC_RENDERING_TIMES: HistogramVec = register_histogram_vec!(
76+
"docsrs_rustdoc_rendering_time",
77+
"The time it takes to render a rustdoc page",
78+
&["step"]
79+
)
80+
.unwrap();
81+
7582
pub static ref FAILED_DB_CONNECTIONS: IntCounter = register_int_counter!(
7683
"docsrs_failed_db_connections",
7784
"Number of attempted and failed connections to the database"
@@ -197,6 +204,47 @@ impl iron::Handler for RequestRecorder {
197204
}
198205
}
199206

207+
struct RenderingTime {
208+
start: Instant,
209+
step: &'static str,
210+
}
211+
212+
pub(crate) struct RenderingTimesRecorder {
213+
metric: &'static HistogramVec,
214+
current: Option<RenderingTime>,
215+
}
216+
217+
impl RenderingTimesRecorder {
218+
pub(crate) fn new(metric: &'static HistogramVec) -> Self {
219+
Self {
220+
metric,
221+
current: None,
222+
}
223+
}
224+
225+
pub(crate) fn step(&mut self, step: &'static str) {
226+
self.record_current();
227+
self.current = Some(RenderingTime {
228+
start: Instant::now(),
229+
step,
230+
});
231+
}
232+
233+
fn record_current(&mut self) {
234+
if let Some(current) = self.current.take() {
235+
self.metric
236+
.with_label_values(&[current.step])
237+
.observe(duration_to_seconds(current.start.elapsed()));
238+
}
239+
}
240+
}
241+
242+
impl Drop for RenderingTimesRecorder {
243+
fn drop(&mut self) {
244+
self.record_current();
245+
}
246+
}
247+
200248
#[cfg(test)]
201249
mod tests {
202250
use crate::test::{assert_success, wrapper};

src/web/rustdoc.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use super::crate_details::CrateDetails;
44
use super::error::Nope;
55
use super::file::File;
6+
use super::metrics;
67
use super::page::Page;
78
use super::pool::Pool;
89
use super::redirect_base;
@@ -215,6 +216,9 @@ pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {
215216
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
216217
/// also crate-specific.
217218
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
219+
let mut rendering_time =
220+
metrics::RenderingTimesRecorder::new(&metrics::RUSTDOC_RENDERING_TIMES);
221+
218222
// Get the request parameters
219223
let router = extension!(req, Router);
220224

@@ -246,6 +250,8 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
246250
Ok(super::redirect(url))
247251
};
248252

253+
rendering_time.step("match version");
254+
249255
// Check the database for releases with the requested version while doing the following:
250256
// * If both the name and the version are an exact match, return the version of the crate.
251257
// * If there is an exact match, but the requested crate name was corrected (dashes vs. underscores), redirect to the corrected name.
@@ -275,6 +281,8 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
275281
return Err(IronError::new(Nope::ResourceNotFound, status::NotFound));
276282
};
277283

284+
rendering_time.step("crate details");
285+
278286
// Get the crate's details from the database
279287
let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
280288

@@ -284,6 +292,8 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
284292
return redirect(&name, &version, &req_path[1..]);
285293
}
286294

295+
rendering_time.step("fetch from storage");
296+
287297
// Add rustdoc prefix, name and version to the path for accessing the file stored in the database
288298
req_path.insert(0, "rustdoc");
289299
req_path.insert(1, &name);
@@ -311,9 +321,12 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
311321

312322
// Serve non-html files directly
313323
if !path.ends_with(".html") {
324+
rendering_time.step("serve asset");
314325
return Ok(file.serve());
315326
}
316327

328+
rendering_time.step("parse html");
329+
317330
let file_content = ctry!(String::from_utf8(file.0.content));
318331
// Extract the head and body of the rustdoc file so that we can insert it into our own html
319332
let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
@@ -326,6 +339,8 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
326339
body_class.push_str(" container-rustdoc");
327340
}
328341

342+
rendering_time.step("serve html");
343+
329344
let latest_release = crate_details.latest_release();
330345

331346
// Get the latest version of the crate

0 commit comments

Comments
 (0)