Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Logs and statistics

Logs

Spire logs through tracing, with one target per crate, so each can be turned up or down on its own:

TargetLogs
spire_coreThe crawl: starting and stopping, requests failing or retried, hosts slowed down or paused, robots.txt, revisits
spireRouting and the built-in handlers: links followed, items collected, sitemaps
spire_redbThe redb store: unreadable seeds, pending changes
spire_thirtyfourBrowser sessions starting and quitting

At info and above, a crawl logs what an operator wants to see: the crawl starting and stopping, tags aborted, hosts paused for Retry-After, and robots.txt it could not fetch. Requests that fail for good are warn. Every request and every decision, such as a host’s concurrency or gap changing, is debug.

Install a subscriber to see them, e.g. with tracing-subscriber and its env-filter feature:

tracing_subscriber::fmt()
    .with_env_filter("spire_core=info,spire=info")
    .init();

Each request runs in a request span with its method, URI, tag, depth and attempt, so a subscriber that prints spans shows which request a line belongs to.

Statistics

run returns Stats once the crawl is over, and stats() returns them while it runs, e.g. to report progress from another task:

FieldCounts
requestsRequests handled, every attempt counted
succeededRequests that finished with Continue or Stop
failedRequests that failed for good
retriedRequests the frontier took back for another attempt
skippedRequests not crawled on purpose: robots.txt, an aborted tag
cancelledRequests still in flight when a shutdown grace period ended
unchangedPages the server answered 304 Not Modified, see Recrawls
elapsedHow long the crawl has run
use std::sync::Arc;
use std::time::Duration;

use spire::backend::ReqwestBackend;
use spire::{Crawler, Result, Router};
async fn page() {}

async fn crawl() -> Result<()> {
let crawler = Arc::new(Crawler::new(ReqwestBackend::default(), Router::new().fallback(page)));

let progress = Arc::clone(&crawler);
tokio::spawn(async move {
    loop {
        tokio::time::sleep(Duration::from_secs(10)).await;
        let stats = progress.stats();
        println!("{} requests, {} failed", stats.requests, stats.failed);
    }
});

let stats = crawler.run().await?;
println!("done in {:?}", stats.elapsed);
Ok(())
}