Components in Fuchsia may expose structured information about themselves
conforming to the Inspect API. This document describes the concepts of
component inspection, the interface, the C++ language implementation
of the interface, and user-facing tools for interacting with components
that expose information.

## Quick links

**Not sure where to start?**

- [Quickstart](https://fuchsia.dev/fuchsia-src/development/diagnostics/inspect/quickstart): A get-started guide for component inspection.
- [`ffx inspect`](https://fuchsia.dev/reference/tools/sdk/ffx.md#inspect): The `ffx` command for inspecting components.
- [Codelab](https://fuchsia.dev/fuchsia-src/development/diagnostics/inspect/codelab): A full codelab in C++ and Rust.
- API reference for [C++](https://fuchsia-docs.firebaseapp.com/cpp/inspect/index.html) and [Rust](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/index.html).
- [Health checks](https://fuchsia.dev/docs/development/diagnostics/inspect/health): Describes the health check subsystem.
- [Best practices](https://fuchsia.dev/fuchsia-src/development/diagnostics/inspect#best-practices): Recommendations for hierarchy design and Virtual Memory Object (VMO) sizing.

## Concepts

Components may expose a tree of **Nodes** , each of which has a set of
**Properties**.

![Figure: A tree of Nodes](https://fuchsia.dev/static/fuchsia-src/development/diagnostics/inspect/tree.png)

### Node

A node is an exported entity within a component that may have 0 or
more children. Each node has a name, and each child of a node
must have a unique name among the children.

![Figure: A Node](https://fuchsia.dev/static/fuchsia-src/development/diagnostics/inspect/node.png)

### Property

Nodes may have any number of properties. A property has a string key and a value
which may be any one of a number of types:

#### Numeric Types

- `UintProperty` - 64-bit unsigned integer.
- `IntProperty` - 64-bit signed integer.
- `DoubleProperty` - 64-bit floating point value.
- `BoolProperty` - A boolean value.

#### String Types

- `StringProperty` - UTF-8 string.
- `ByteVectorProperty` - Vector of bytes.

#### Array Types

- `UintArray`, `IntArray`, `DoubleArray` - An array of the corresponding numeric type.

#### Histogram Types

- `LinearUintHistogram`, `LinearIntHistogram`, `LinearDoubleHistogram`

A histogram with fixed-size buckets stored in an array.

- `ExponentialUintHistogram`, `ExponentialIntHistogram`, `ExponentialDoubleHistogram`

A histogram with exponentially sized buckets stored in an array.

### Inspect File Format

The [Inspect File Format](https://fuchsia.dev/docs/reference/platform-spec/diagnostics/inspect-vmo-format) is a binary format
that supports efficient insertion, modification, and deletion of Nodes and
Properties at runtime. Readers take a consistent snapshot of the contents
without communicating with writers.

### Filesystem Interface

*Top-level* nodes are exposed as VmoFiles in a component's outgoing directory
ending in the extension `.inspect`. It is customary for components to expose
their primary or root tree as `out/diagnostics/root.inspect`.

### Language Libraries

### [C++](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect)

The C++ Inspect Library provides full [writing](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/inspect.h) and
[reading](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/reader.h) support for the Inspect File Format.

Components that write inspect data should refrain from reading that data.
Reading requires traversing the entire buffer, which is very expensive.

The `Inspector` class provides a wrapper around creating a new buffer
with one root Node that can be added to. Nodes and Properties have typed
[wrappers](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/vmo/types.h) that automatically delete the underlying data from the
buffer when they go out of scope.

The [inspect_component](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/inspect/component/cpp) library provides a simple `ComponentInspector`
singleton interface to help with the common case of exposing a single
hierarchy from the component.

The [health](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/health.h) feature supports exposing structured health information
in a format known by health checking tools.

The [stats](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/inspector.h) feature supports exposing runtime Inspect
allocation metrics and buffer utilization.

The [bounded list](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/bounded_list_node.h) feature supports recording rolling event histories
in fixed-capacity FIFO node buffers.

The [test matchers](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/inspect/testing) library provides GMock matchers for verifying
data that is read out of an Inspect hierarchy in tests.

#### Reading Support

The [reading library](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/reader.h) supports parsing an Inspect File
into a [Hierarchy](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/hierarchy.h). `Hierarchy`s contain `NodeValue`s
and `PropertyValues`, which are the parsed versions of `Node`s and
`Property`s respectively.

The `Hierarchy`'s `NodeValue` is returned by `node()` and child
`Hierarchy`s are returned in a vector by `children()`. The `GetByPath`
function supports reading a specific child hierarchy by path.

The properties for a particular `NodeValue` are available through the
`properties()` accessor. You may determine if a property contains a
certain type by passing the corresponding `PropertyValue` type as the
template parameter to the `Contains<T>()` method:

      // Returns true if the first property of the hierarchy's node is an INT value.
      if (hierarchy.node().properties()[0].Contains<IntPropertyValue>()) {
        // ...
      }

Use the `Get<T>()` method to obtain the property:

      // Get the IntPropertyValue of the first property on the node.
      // Note: This causes a runtime exception if the property does not contain
      // the given type, crashing the program.
      hierarchy.node().properties()[0].Get<IntPropertyValue>();

You may also switch based on the different possible format types:

      const auto& property = hierarchy.node().properties()[0];
      switch (property.format()) {
        case FormatType::INT:
          const auto& value = property.Get<IntPropertyValue>();
          /* ... */
          break;
        /* ... */
      }

Array types may be specially formatted to contain histograms. The
`GetBuckets()` method supports returning an array of histogram buckets
from `{Int,Uint,Double}ArrayValue` types. The array will be empty if
the underlying array is not a specially formatted histogram.

### [Rust](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/lib/diagnostics/inspect/rust)

The Rust Inspect Library provides full [writing](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/struct.Inspector.html) and
[reading](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/reader/index.html) support for the Inspect File Format.

Components that write inspect data should refrain from reading that data.
Reading requires traversing the entire buffer, which is very expensive.

The `Inspector` class provides a wrapper around creating a new buffer
with one root Node that can be added to. Nodes and Properties have typed
[wrappers](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/index.html) that automatically delete the underlying data from the
buffer when they go out of scope.

The [component](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/component/index.html) module supports a simple `inspector` function to
handle the common use of exposing a single hierarchy from the component.

The [health](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/health/index.html) module supports exposing structured health information
in a format known by health checking tools.

The [stats](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/stats/index.html) module supports exposing runtime Inspect
allocation metrics and buffer utilization.

The [contrib](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect_contrib/index.html) crate provides `BoundedListNode`, `inspect_log!`, and
time utilities for timestamped event logging.

The [testing](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/testing/index.html) module supports the `assert_data_tree!` macro to
match Inspect data for testing.

## Testing

[Validator Architecture](https://fuchsia.dev/docs/reference/diagnostics/inspect/validator/README) describes an integration test framework for Inspect
language libraries.

## Userspace tools

### ffx inspect

To examine the inspect hierarchies of components, you can use the
[`ffx inspect show`](https://fuchsia.dev/reference/tools/sdk/ffx.md#ffx_inspect_show) command:

- Print all inspect hierarchies:

      ffx inspect show

- Print the inspect hierarchy of a specific component (for example,
  `core/font_provider`):

      ffx inspect show core/font_provider

`ffx inspect show` also does fuzzy matching on its inputs. For example:

    ffx inspect show archivist.cm

This prints all of the Inspect for `bootstrap/archivist` as long as this is the only component
that exposes Inspect in the system whose URL ends with `archivist.cm`.

Fuzzy matching will fail if the input is insufficiently specific to identify an individual
component; in that case, the tool will print a list of monikers that matched the query.

In general, this command accepts the following:

- A component moniker, for example, `core/network/netstack`. If only the moniker is passed,
  collection markers don't need to be escaped, though they optionally can be.

- A fuzzy search parameter, corresponding to a URL fragment, manifest fragment, or
  moniker fragment. Ie `ffx inspect show archivist.cm` for `bootstrap/archivist` with
  the manifest `archivist.cm`.

- A component selector, for example, `core/network/*`.

- A full diagnostics selector, for example, `core/network/netstack:root/path/to/*:property`. In
  the full selector case, escaping must be performed to create a valid selector.

Suppose you have the component `bootstrap/driver-hosts:driver-host-337`. An ergonomic way to avoid
escaping things as much as possible when you want a specific property might look like the following:

    ffx inspect driver-host-337 --data root/stats:my_stat

> [!NOTE]
> **Note:** The following characters in a selector must be escaped with `\\` when writing an actual diagnostics selector: `*`, `:`, `\\`, `/`, and whitespace. To learn more about selectors see [the selector format docs](https://fuchsia.dev/docs/reference/diagnostics/selectors).

### ffx target snapshot

[`ffx target snapshot`](https://fuchsia.dev/reference/tools/sdk/ffx.md#snapshot) generates a ZIP archive that contains the system's
diagnostic information, which includes inspect:

    ffx target snapshot

## Best practices

### Avoid nesting metrics from other components

When you design component diagnostics, keep each component's Inspect hierarchy
scoped strictly to the data produced by that component. Avoid forwarding or
nesting Inspect metrics from client or subordinate components under an
intermediary component's Inspect tree.

> [!NOTE]
> **Note:** This guidance targets forwarding and nesting subordinate component metrics. It does not apply to platform-level aggregation of system metrics about components (for example, `component_manager` collecting and publishing CPU metrics across all components).

Forwarding or nesting Inspect metrics under a foreign component creates several
problems for tooling, debugging, and privacy compliance:

- **Developer experience and tooling attribution** : Inspect data is attributed
  by component moniker. Diagnostic tools such as
  [`ffx inspect show`](https://fuchsia.dev/reference/tools/sdk/ffx.md#ffx_inspect_show) and automated snapshot triage query
  Inspect hierarchies using component monikers (for example,
  `core/network/netstack`). When you nest metrics from multiple components
  inside a single intermediary service, querying the producer component's
  moniker returns no data, while querying the intermediary returns an
  unmanageable aggregated hierarchy.

- **Privacy reviews and allowlist enforcement** : Fuchsia diagnostic pipelines
  and snapshot exporters enforce privacy controls using moniker-based
  [selectors](https://fuchsia.dev/docs/reference/diagnostics/selectors). Placing metrics from multiple producers under a
  foreign moniker obscures data origin, prevents granular data redaction, and
  complicates privacy review verification.

- **Lifecycle and failure isolation**: An intermediary component holding
  metrics on behalf of other components can outlive or terminate independently
  of the actual metric producers. This creates stale diagnostics or causes data
  loss if the intermediary crashes.

#### Recommended patterns

Each component should publish its own Inspect tree directly under its own
moniker.

> [!IMPORTANT]
> **Important:** Keep all Inspect metrics scoped to the component moniker that owns and produces the data.

### Size the Inspect VMO to prevent silent allocation failures

Inspect hierarchies are stored in a mapped [VMO](https://fuchsia.dev/docs/reference/kernel_objects/vm_object) using the
buddy-allocated [Inspect VMO format](https://fuchsia.dev/docs/reference/platform-spec/diagnostics/inspect-vmo-format). By default, both
the C++ and Rust libraries allocate a maximum VMO size of 256 KiB (262,144
bytes). Memory is committed in 4 KiB pages dynamically as nodes and properties
are written to the hierarchy, up to this maximum limit.

#### Silent allocation failures

If an Inspect tree exceeds its configured maximum VMO capacity, or if memory
fragmentation prevents allocating a contiguous block of the requested size, the
Inspect library fails silently by design:

- Creating new child nodes or properties fails and returns no-op objects (or
  stores a truncated prefix when a multi-extent string or bytes payload runs
  out of space on a later extent).

- Appending to bounded lists (such as `BoundedListNode`) still evicts the
  oldest entry when at capacity before attempting to allocate the new entry,
  and can drop the new entry or leave an empty or partially populated entry
  node if space runs out while recording its properties.

- In-place mutations on existing numeric properties, boolean properties,
  numeric arrays, and histograms continue to function normally.

- Updating a string property or string-array slot retains the previous value
  if the initial string block or its first overflow extent cannot be
  allocated, or stores a truncated prefix if a later overflow extent fails.
  Updating a bytes property frees its old extents first, leaving an empty
  value if the first extent fails to allocate or a truncated prefix if a later
  extent fails.

- The component does not crash or panic. Failed node and property creation is
  not logged; the Rust library logs an error only when `StringProperty::set`
  fails to allocate the initial string block or its first overflow extent, or
  when `BytesProperty::set` fails to allocate its first extent.

> [!NOTE]
> **Note:** Inspect prioritizes application reliability over diagnostic telemetry. A component must never crash or degrade its primary business logic because diagnostic data exceeds available buffer space.

However, silent allocation failures mean that missing metrics or truncated
historical event logs can go unnoticed during development and troubleshooting.

#### Detecting allocation failures with fuchsia.inspect.Stats

You can monitor Inspect memory usage and detect dropped allocations by serving
the `fuchsia.inspect.Stats` lazy node at the root of your hierarchy:

- **C++** : Call [`CreateStatsNode()`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/system/ulib/inspect/include/lib/inspect/cpp/inspector.h) on your `Inspector`.

- **Rust** : Call [`component::serve_inspect_stats()`](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/component/fn.serve_inspect_stats.html) to
  instrument the singleton component inspector, or on a custom `Inspector`
  call [`record_lazy_stats()`](https://fuchsia-docs.firebaseapp.com/rust/fuchsia_inspect/stats/trait.InspectorExt.html#tymethod.record_lazy_stats).

When you query the component with [`ffx inspect show`](https://fuchsia.dev/reference/tools/sdk/ffx.md#ffx_inspect_show), the
`fuchsia.inspect.Stats` node displays real-time allocation metrics:

    ffx inspect show <moniker>:root/fuchsia.inspect.Stats

This command outputs metrics similar to the following:

    fuchsia.inspect.Stats:
      allocated_blocks = 142
      current_size = 36864
      deallocated_blocks = 28
      failed_allocations = 0
      maximum_size = 262144
      peak_bytes_requested = 34560
      total_dynamic_children = 1
      utilization_per_ten_k = 1406

A non-zero value for `failed_allocations` indicates that Inspect has exhausted
its VMO capacity and dropped data. `peak_bytes_requested` reports the
high-watermark of concurrently requested bytes. Requests that failed still
count toward it and are never released, so repeated failed allocations
inflate the value beyond the true peak demand. You can use this value as a
hint for how large the Inspector VMO would have needed to be to avoid
failing allocations.

> [!NOTE]
> **Note:** `peak_bytes_requested` is a sizing hint, not a guarantee. Because it tracks requested block sizes without accounting for buddy allocator fragmentation or 4 KiB page boundaries, configure your VMO with additional headroom above this value.

#### Sizing recommendations and configuration

When designing component diagnostics:

- **Estimate buffer requirements** : If your component records historical event
  logs using bounded collections (such as `BoundedListNode`), calculate the
  expected memory footprint (entry count × average entry size) or inspect
  `peak_bytes_requested` in `fuchsia.inspect.Stats`, and ensure the VMO is
  sized with adequate headroom.

- **Configure custom VMO capacity**: When 256 KiB is insufficient, initialize
  the Inspector with an explicit size:

  - **C++** : Construct an `inspect::Inspector` from an
    `inspect::InspectSettings` struct with `maximum_size` set. To publish it
    through `inspect::ComponentInspector`, pass that `Inspector` in the
    `inspector` field of `inspect::PublishOptions`.

  - **Rust** : Call
    `fuchsia_inspect::component::init_inspector_with_size(max_size)` before
    any other use of the `component` singleton (`inspector()`, `health()`, or
    `serve_inspect_stats()`), or configure `InspectorConfig` via
    `Inspector::new(InspectorConfig::default().size(max_size))`.

- **Use lazy nodes for large or dynamic datasets** : Offload large collections
  (such as routing tables or detailed cache entries) to
  [lazy nodes](https://fuchsia.dev/docs/development/diagnostics/inspect/quickstart#dynamic-values) so they are computed on demand rather
  than permanently occupying VMO space.

For concrete code samples on configuring VMO size and serving stats, see
[Managing VMO size and capacity](https://fuchsia.dev/docs/development/diagnostics/inspect/quickstart#managing-vmo-size-and-capacity) in the Quickstart guide.
[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/development/diagnostics/inspect/README.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/development/diagnostics/inspect/README.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/development/diagnostics/inspect/README.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/development/diagnostics/inspect/README.md "Edit the source code of this page")