diff --git a/Cargo.lock b/Cargo.lock
index 71b98d2cd5c4c33054cad756f7d510005faca202..4f4e0a988cecbea1b8cc055d92ed1f7f364a9e1b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14381,6 +14381,8 @@ dependencies = [
  "sp-offchain",
  "sp-runtime",
  "sp-runtime-interface 24.0.0",
+ "sp-std 14.0.0",
+ "sp-tracing 16.0.0",
  "sp-version",
  "staging-chain-spec-builder",
  "staging-node-cli",
@@ -19530,6 +19532,7 @@ dependencies = [
 name = "sp-api"
 version = "26.0.0"
 dependencies = [
+ "docify",
  "hash-db",
  "log",
  "parity-scale-codec",
diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml
index 10c0912116711ad9f43364c207255f9cd92c2429..ee603f8c49465d79040dbc712051960c5696234a 100644
--- a/docs/sdk/Cargo.toml
+++ b/docs/sdk/Cargo.toml
@@ -89,6 +89,8 @@ pallet-babe = { path = "../../substrate/frame/babe" }
 
 # Primitives
 sp-io = { path = "../../substrate/primitives/io" }
+sp-std = { path = "../../substrate/primitives/std" }
+sp-tracing = { path = "../../substrate/primitives/tracing" }
 sp-runtime-interface = { path = "../../substrate/primitives/runtime-interface" }
 sp-api = { path = "../../substrate/primitives/api" }
 sp-core = { path = "../../substrate/primitives/core" }
diff --git a/docs/sdk/src/reference_docs/frame_logging.rs b/docs/sdk/src/reference_docs/frame_logging.rs
new file mode 100644
index 0000000000000000000000000000000000000000..301fa7ef83f827c3115a6a30bb8d1ad35b5bfd83
--- /dev/null
+++ b/docs/sdk/src/reference_docs/frame_logging.rs
@@ -0,0 +1,116 @@
+//! # FRAME Logging
+//!
+//! This reference docs briefly explores how to do logging and printing runtimes, mainly
+//! FRAME-based.
+//!
+//! ## Using `println!`
+//!
+//! To recap, as with standard Rust, you can use `println!` _in your tests_, but it will only print
+//! out if executed with `--nocapture`, or if the test panics.
+//!
+//! ```
+//! fn it_print() {
+//! 	println!("Hello, world!");
+//! }
+//! ```
+//!
+//! within the pallet, if you want to use the standard `println!`, it needs to be wrapped in
+//! [`sp_std::if_std`]. Of course, this means that this print code is only available to you in the
+//! `std` compiler flag, and never present in a wasm build.
+//!
+//! ```
+//! // somewhere in your pallet. This is not a real pallet code.
+//! mod pallet {
+//! 	struct Pallet;
+//! 	impl Pallet {
+//! 		fn print() {
+//! 			sp_std::if_std! {
+//! 				println!("Hello, world!");
+//! 			}
+//! 		}
+//! 	}
+//! }
+//! ```
+//!
+//! ## Using `log`
+//!
+//! First, ensure you are familiar with the `log` crate. In short, each log statement has:
+//!
+//! 1. `log-level`, signifying how important it is
+//! 2. `log-target`, signifying to which component it belongs.
+//!
+//! Add log statements to your pallet as such:
+//!
+//! You can add the log crate to the `Cargo.toml` of the pallet.
+//!
+//! ```text
+//! #[dependencies]
+//! log = { version = "x.y.z", default-features = false }
+//!
+//! #[features]
+//! std = [
+//! 	// snip -- other pallets
+//! 	"log/std"
+//! ]
+//! ```
+//!
+//! More conveniently, the `frame` umbrella crate re-exports the log crate as [`frame::log`].
+//!
+//! Then, the pallet can use this crate to emit log statements. In this statement, we use the info
+//! level, and the target is `pallet-example`.
+//!
+//! ```
+//! mod pallet {
+//! 	struct Pallet;
+//!
+//! 	impl Pallet {
+//! 		fn logs() {
+//! 			frame::log::info!(target: "pallet-example", "Hello, world!");
+//! 		}
+//! 	}
+//! }
+//! ```
+//!
+//! This will in itself just emit the log messages, **but unless if captured by a logger, they will
+//! not go anywhere**. [`sp_api`] provides a handy function to enable the runtime logging:
+//!
+//! ```
+//! // in your test
+//! fn it_also_prints() {
+//! 	sp_api::init_runtime_logger();
+//! 	// call into your pallet, and now it will print `log` statements.
+//! }
+//! ```
+//!
+//! Alternatively, you can use [`sp_tracing::try_init_simple`].
+//!
+//! `info`, `error` and `warn` logs are printed by default, but if you want lower level logs to also
+//! be printed, you must to add the following compiler flag:
+//!
+//! ```text
+//! RUST_LOG=pallet-example=trace cargo test
+//! ```
+//!
+//! ## Enabling Logs in Production
+//!
+//! All logs from the runtime are emitted by default, but there is a feature flag in [`sp_api`],
+//! called `disable-logging`, that can be used to disable all logs in the runtime. This is useful
+//! for production chains to reduce the size and overhead of the wasm runtime.
+#![doc = docify::embed!("../../substrate/primitives/api/src/lib.rs", init_runtime_logger)]
+//!
+//! Similar to the above, the proper `RUST_LOG` must also be passed to your compiler flag when
+//! compiling the runtime.
+//!
+//! ## Log Target Prefixing
+//!
+//! Many [`crate::polkadot_sdk::frame_runtime`] pallets emit logs with log target `runtime::<name of
+//! pallet>`, for example `runtime::system`. This then allows one to run a node with a wasm blob
+//! compiled with `LOG_TARGET=runtime=debug`, which enables the log target of all pallets who's log
+//! target starts with `runtime`.
+//!
+//! ## Low Level Primitives
+//!
+//! Under the hood, logging is another instance of host functions under the hood (as defined in
+//! [`crate::reference_docs::wasm_meta_protocol`]). The runtime uses a set of host functions under
+//! [`sp_io::logging`] and [`sp_io::misc`] to emit all logs and prints. You typically do not need to
+//! use these APIs directly.
diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs
index 51150a5583758c93cbdbc6d2e2233b0f88844a4f..688339b7e3806c0ed86db5caabc253b0d45e7c41 100644
--- a/docs/sdk/src/reference_docs/mod.rs
+++ b/docs/sdk/src/reference_docs/mod.rs
@@ -93,6 +93,9 @@ pub mod frame_offchain_workers;
 /// together.
 pub mod frame_pallet_coupling;
 
+/// Learn about how to do logging in FRAME-based runtimes.
+pub mod frame_logging;
+
 /// Learn about the Polkadot Umbrella crate that re-exports all other crates.
 pub mod umbrella_crate;
 
diff --git a/docs/sdk/src/reference_docs/umbrella_crate.rs b/docs/sdk/src/reference_docs/umbrella_crate.rs
index 9751b0ad5ad6d94a20e027e902ac055fa9e49181..0b3445cfc4bc0ce27b6dcb144618dd7001e6f20a 100644
--- a/docs/sdk/src/reference_docs/umbrella_crate.rs
+++ b/docs/sdk/src/reference_docs/umbrella_crate.rs
@@ -28,8 +28,9 @@
 //!   `node` feature. For docs.rs the manifest contains specific configuration to make it show up
 //!   all re-exports.
 //!
-//! There is a specific `zepter` check in place to ensure that the features of the umbrella are
-//! correctly configured. This check is run in CI and locally when running `zepter`.
+//! There is a specific [`zepter`](https://github.com/ggwpez/zepter) check in place to ensure that
+//! the features of the umbrella are correctly configured. This check is run in CI and locally when
+//! running `zepter`.
 //!
 //! ## Generation
 //!
diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml
index f48480f398d00729a5fb10e0c9bcfba5d62f9776..b334880785f2fd0195d197b878a3d6fc2252c5a7 100644
--- a/substrate/primitives/api/Cargo.toml
+++ b/substrate/primitives/api/Cargo.toml
@@ -33,6 +33,7 @@ scale-info = { version = "2.11.1", default-features = false, features = [
 ] }
 sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true }
 log = { workspace = true }
+docify = { version = "0.2.1" }
 
 [dev-dependencies]
 sp-test-primitives = { path = "../test-primitives" }
diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs
index 20f989c4882e35fe06d5496f851b4adec2c6f1c0..cd8da8ba2374e142835967c8f304c62b1d0bf250 100644
--- a/substrate/primitives/api/src/lib.rs
+++ b/substrate/primitives/api/src/lib.rs
@@ -532,6 +532,7 @@ pub trait ConstructRuntimeApi<Block: BlockT, C: CallApiAt<Block>> {
 	fn construct_runtime_api(call: &C) -> ApiRef<Self::RuntimeApi>;
 }
 
+#[docify::export]
 /// Init the [`RuntimeLogger`](sp_runtime::runtime_logger::RuntimeLogger).
 pub fn init_runtime_logger() {
 	#[cfg(not(feature = "disable-logging"))]