Rocket/core/lib/src/lib.rs
Sergio Benitez 926e06ef3c Finalize 'tracing' migration.
This commit complete the migration to 'tracing' for all logging. Below
is a summary of all relevant commits, including this one:

Log improvements:
  - All log (trace) messages are structured which means they contain fields
    that can formatted by any subscriber.
  - Logging can be disabled entirely by disabling the default `trace` feature.
  - Routes and catchers now contain location (file/line) information.
  - Two log format kinds: pretty and compact via ROCKET_LOG_FORMAT
  - Coloring is not disabled globally. Thus applications can color even if
    Rocket is configured not to.
  - Rocket is more conservative about 'warn' and 'error' messages, reserving
    those log levels for messages useful in production.
  - Errors from guards logged by codegen now use the 'Display' implementation of
    those errors when one exists.
  - Secrets are never logged, even when directly asked for.

New features:
  - Many Rocket types know how to trace themselves via a new `Trace` trait.
  - `Either` types can now be used in `uri!()` calls.
  - A `RequestIdLayer` tags all requests with a unique ID.

Breaking changes to configuration:
  - `Config::log_level` is of type `Option<Level>`. `None` disables tracing.
  - `log_level` now uses the traditional log level names: "off", "error",
    "warn", "info", "debug", "trace", or 0-5. This replace the Rocket-specific
    "normal", "debug", "critical".
  - A new option, `log_format`, which is either `compact` or `pretty`,
    determines how Rocket's tracing subscriber log trace messages.

Breaking changes:
  - Hidden `rocket::Either` is now publicly available at `rocket::either::Either`.
  - `rocket::Error` no longer panics when dropped.
  - `main` generated by `#[launch]` returns an `ExitCode`.
  - `FromParam` `Err` now always returns the actual error as opposed to the
    string that failed to parse. To recover the original string, use `Either<T,
    &str>`, where `T: FromParam`, as a parameter guard.
  - Many types that implemented `Display` now instead implement `Trace`.
  - `Error::pretty_print()` was removed. Use `Error::trace()` via `Trace` impl.

Internal improvements:
  - Made more space in CI machines for tasks.
  - Cleaned up testbench code using `inventory`.

Resolves #21.
2024-06-03 15:02:44 -07:00

368 lines
12 KiB
Rust

#![recursion_limit="256"]
#![doc(html_root_url = "https://api.rocket.rs/master")]
#![doc(html_favicon_url = "https://rocket.rs/images/favicon.ico")]
#![doc(html_logo_url = "https://rocket.rs/images/logo-boxed.png")]
#![cfg_attr(nightly, feature(doc_cfg))]
#![cfg_attr(nightly, feature(decl_macro))]
//! # Rocket - Core API Documentation
//!
//! Hello, and welcome to the core Rocket API documentation!
//!
//! This API documentation is highly technical and is purely a reference.
//! There's an [overview] of Rocket on the main site as well as a [full,
//! detailed guide]. If you'd like pointers on getting started, see the
//! [quickstart] or [getting started] chapters of the guide.
//!
//! [overview]: https://rocket.rs/master/overview
//! [full, detailed guide]: https://rocket.rs/master/guide
//! [quickstart]: https://rocket.rs/master/guide/quickstart
//! [getting started]: https://rocket.rs/master/guide/getting-started
//!
//! ## Usage
//!
//! Depend on `rocket` in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rocket = "0.6.0-dev"
//! ```
//!
//! <small>Note that development versions, tagged with `-dev`, are not published
//! and need to be specified as [git dependencies].</small>
//!
//! See the [guide](https://rocket.rs/master/guide) for more information on how
//! to write Rocket applications. Here's a simple example to get you started:
//!
//! [git dependencies]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories
//!
//! ```rust,no_run
//! #[macro_use] extern crate rocket;
//!
//! #[get("/")]
//! fn hello() -> &'static str {
//! "Hello, world!"
//! }
//!
//! #[launch]
//! fn rocket() -> _ {
//! rocket::build().mount("/", routes![hello])
//! }
//! ```
//!
//! ## Features
//!
//! To avoid compiling unused dependencies, Rocket feature-gates optional
//! functionality, some enabled by default:
//!
//! | Feature | Default? | Description |
//! |-----------------|----------|---------------------------------------------------------|
//! | `trace` | Yes | Enables the default Rocket tracing [subscriber]. |
//! | `http2` | Yes | Support for HTTP/2 (enabled by default). |
//! | `secrets` | No | Support for authenticated, encrypted [private cookies]. |
//! | `tls` | No | Support for [TLS] encrypted connections. |
//! | `mtls` | No | Support for verified clients via [mutual TLS]. |
//! | `json` | No | Support for [JSON (de)serialization]. |
//! | `msgpack` | No | Support for [MessagePack (de)serialization]. |
//! | `uuid` | No | Support for [UUID value parsing and (de)serialization]. |
//! | `tokio-macros` | No | Enables the `macros` feature in the exported `tokio` |
//! | `http3-preview` | No | Experimental preview support for [HTTP/3]. |
//!
//! Disabled features can be selectively enabled in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rocket = { version = "0.6.0-dev", features = ["secrets", "tls", "json"] }
//! ```
//!
//! Conversely, HTTP/2 can be disabled:
//!
//! ```toml
//! [dependencies]
//! rocket = { version = "0.6.0-dev", default-features = false }
//! ```
//!
//! [subscriber]: crate::trace::subscriber
//! [JSON (de)serialization]: crate::serde::json
//! [MessagePack (de)serialization]: crate::serde::msgpack
//! [UUID value parsing and (de)serialization]: crate::serde::uuid
//! [private cookies]: https://rocket.rs/master/guide/requests/#private-cookies
//! [TLS]: https://rocket.rs/master/guide/configuration/#tls
//! [mutual TLS]: crate::mtls
//! [HTTP/3]: crate::listener::quic
//!
//! ## Configuration
//!
//! Rocket offers a rich, extensible configuration system built on [Figment]. By
//! default, Rocket applications are configured via a `Rocket.toml` file
//! and/or `ROCKET_{PARAM}` environment variables, but applications may
//! configure their own sources. See the [configuration guide] for full details.
//!
//! ## Testing
//!
//! The [`local`] module contains structures that facilitate unit and
//! integration testing of a Rocket application. The top-level [`local`] module
//! documentation and the [testing guide] include detailed examples.
//!
//! [configuration guide]: https://rocket.rs/master/guide/configuration/
//! [testing guide]: https://rocket.rs/master/guide/testing/#testing
//! [Figment]: https://docs.rs/figment
// Allows using Rocket's codegen in Rocket itself.
extern crate self as rocket;
/// These are public dependencies! Update docs if these are changed, especially
/// figment's version number in docs.
#[doc(hidden)]
pub use yansi;
#[doc(hidden)]
pub use async_stream;
pub use futures;
pub use tokio;
pub use figment;
pub use time;
pub use tracing;
pub use either;
#[macro_use]
pub mod trace;
#[macro_use]
pub mod outcome;
#[macro_use]
pub mod data;
#[doc(hidden)]
pub mod sentinel;
pub mod local;
pub mod request;
pub mod response;
pub mod config;
pub mod form;
pub mod fairing;
pub mod error;
pub mod catcher;
pub mod route;
pub mod serde;
pub mod shield;
pub mod fs;
pub mod http;
pub mod listener;
pub mod shutdown;
#[cfg(feature = "tls")]
#[cfg_attr(nightly, doc(cfg(feature = "tls")))]
pub mod tls;
#[cfg(feature = "mtls")]
#[cfg_attr(nightly, doc(cfg(feature = "mtls")))]
pub mod mtls;
#[path = "rocket.rs"]
mod rkt;
mod util;
mod server;
mod lifecycle;
mod state;
mod router;
mod phase;
mod erased;
#[doc(inline)] pub use rocket_codegen::*;
#[doc(inline)] pub use crate::response::Response;
#[doc(inline)] pub use crate::data::Data;
#[doc(inline)] pub use crate::config::Config;
#[doc(inline)] pub use crate::catcher::Catcher;
#[doc(inline)] pub use crate::route::Route;
#[doc(inline)] pub use crate::phase::{Phase, Build, Ignite, Orbit};
#[doc(inline)] pub use crate::error::Error;
#[doc(inline)] pub use crate::sentinel::Sentinel;
#[doc(inline)] pub use crate::request::Request;
#[doc(inline)] pub use crate::rkt::Rocket;
#[doc(inline)] pub use crate::shutdown::Shutdown;
#[doc(inline)] pub use crate::state::State;
/// Retrofits support for `async fn` in trait impls and declarations.
///
/// Any trait declaration or trait `impl` decorated with `#[async_trait]` is
/// retrofitted with support for `async fn`s:
///
/// ```rust
/// # use rocket::*;
/// #[async_trait]
/// trait MyAsyncTrait {
/// async fn do_async_work();
/// }
///
/// #[async_trait]
/// impl MyAsyncTrait for () {
/// async fn do_async_work() { /* .. */ }
/// }
/// ```
///
/// All `impl`s for a trait declared with `#[async_trait]` must themselves be
/// decorated with `#[async_trait]`. Many of Rocket's traits, such as
/// [`FromRequest`](crate::request::FromRequest) and
/// [`Fairing`](crate::fairing::Fairing) are `async`. As such, implementations
/// of said traits must be decorated with `#[async_trait]`. See the individual
/// trait docs for trait-specific details.
///
/// For more details on `#[async_trait]`, see [`async_trait`](mod@async_trait).
#[doc(inline)]
pub use async_trait::async_trait;
const WORKER_PREFIX: &str = "rocket-worker";
/// Creates a [`Rocket`] instance with the default config provider: aliases
/// [`Rocket::build()`].
pub fn build() -> Rocket<Build> {
Rocket::build()
}
/// Creates a [`Rocket`] instance with a custom config provider: aliases
/// [`Rocket::custom()`].
pub fn custom<T: figment::Provider>(provider: T) -> Rocket<Build> {
Rocket::custom(provider)
}
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)]
pub fn async_run<F, R>(fut: F, workers: usize, sync: usize, force_end: bool, name: &str) -> R
where F: std::future::Future<Output = R>
{
let runtime = tokio::runtime::Builder::new_multi_thread()
.thread_name(name)
.worker_threads(workers)
.max_blocking_threads(sync)
.enable_all()
.build()
.expect("create tokio runtime");
let result = runtime.block_on(fut);
if force_end {
runtime.shutdown_timeout(std::time::Duration::from_millis(500));
}
result
}
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)]
pub fn async_test<R>(fut: impl std::future::Future<Output = R>) -> R {
async_run(fut, 1, 32, true, &format!("{WORKER_PREFIX}-test-thread"))
}
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)]
pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
fn bail<T, E: crate::trace::Trace>(e: E) -> T {
e.trace_error();
panic!("aborting due to error")
}
// FIXME: We need to run `fut` to get the user's `Figment` to properly set
// up the async env, but we need the async env to run `fut`. So we're stuck.
// Tokio doesn't let us take the state from one async env and migrate it to
// another, so we need to use one, making this impossible.
//
// So as a result, we only use values from Rocket's figment. These
// values won't reflect swaps of `Rocket` in attach fairings with different
// config values, or values from non-Rocket configs. See tokio-rs/tokio#3329
// for a necessary resolution in `tokio`.
let fig = Config::figment();
let workers = fig.extract_inner(Config::WORKERS).unwrap_or_else(bail);
let max_blocking = fig.extract_inner(Config::MAX_BLOCKING).unwrap_or_else(bail);
let force = fig.focus(Config::SHUTDOWN).extract_inner("force").unwrap_or_else(bail);
async_run(fut, workers, max_blocking, force, &format!("{WORKER_PREFIX}-thread"))
}
/// Executes a `future` to completion on a new tokio-based Rocket async runtime.
///
/// The runtime is terminated on shutdown, and the future's resolved value is
/// returned.
///
/// # Considerations
///
/// This function is a low-level mechanism intended to be used to execute the
/// future returned by [`Rocket::launch()`] in a self-contained async runtime
/// designed for Rocket. It runs futures in exactly the same manner as
/// [`#[launch]`](crate::launch) and [`#[main]`](crate::main) do and is thus
/// _never_ the preferred mechanism for running a Rocket application. _Always_
/// prefer to use the [`#[launch]`](crate::launch) or [`#[main]`](crate::main)
/// attributes. For example [`#[main]`](crate::main) can be used even when
/// Rocket is just a small part of a bigger application:
///
/// ```rust,no_run
/// #[rocket::main]
/// async fn main() {
/// # let should_start_server_in_foreground = false;
/// # let should_start_server_in_background = false;
/// let rocket = rocket::build();
/// if should_start_server_in_foreground {
/// rocket::build().launch().await;
/// } else if should_start_server_in_background {
/// rocket::tokio::spawn(rocket.launch());
/// } else {
/// // do something else
/// }
/// }
/// ```
///
/// See [Rocket#launching] for more on using these attributes.
///
/// # Example
///
/// Build an instance of Rocket, launch it, and wait for shutdown:
///
/// ```rust,no_run
/// use rocket::fairing::AdHoc;
///
/// let rocket = rocket::build()
/// .attach(AdHoc::on_liftoff("Liftoff Printer", |_| Box::pin(async move {
/// println!("Stalling liftoff for a second...");
/// rocket::tokio::time::sleep(std::time::Duration::from_secs(1)).await;
/// println!("And we're off!");
/// })));
///
/// rocket::execute(rocket.launch());
/// ```
///
/// Launch a pre-built instance of Rocket and wait for it to shutdown:
///
/// ```rust,no_run
/// use rocket::{Rocket, Ignite, Phase, Error};
///
/// fn launch<P: Phase>(rocket: Rocket<P>) -> Result<Rocket<Ignite>, Error> {
/// rocket::execute(rocket.launch())
/// }
/// ```
///
/// Do async work to build an instance of Rocket, launch, and wait for shutdown:
///
/// ```rust,no_run
/// use rocket::fairing::AdHoc;
///
/// // This line can also be inside of the `async` block.
/// let rocket = rocket::build();
///
/// rocket::execute(async move {
/// let rocket = rocket.ignite().await?;
/// let config = rocket.config();
/// rocket.launch().await
/// });
/// ```
pub fn execute<R, F>(future: F) -> R
where F: std::future::Future<Output = R> + Send
{
async_main(future)
}
/// Returns a future that evaluates to `true` exactly when there is a presently
/// running tokio async runtime that was likely started by Rocket.
fn running_within_rocket_async_rt() -> impl std::future::Future<Output = bool> {
use futures::FutureExt;
tokio::task::spawn_blocking(|| {
let this = std::thread::current();
this.name().map_or(false, |s| s.starts_with(WORKER_PREFIX))
}).map(|r| r.unwrap_or(false))
}