blob: e8881c70e5f1c4549ab20d7b38f4da74dfce49c3 [file] [log] [blame] [view] [edit]
# Diagnostics and monitoring
Connecting to FIDL protocols within components is a combination of capability
routing and directory serving. This means that diagnosing connection issues can
cover a few different layers:
* Client requests the protocol capability in its manifest.
* Provider exposes the protocol capability in its manifest.
* Component topology routes the capability from the provider to the client.
* Provider is serving the protocol on the correct handle.
* Client is attempting to connect to the correct protocol handle.
In this section, you'll explore some APIs and tools to help you find and fix
problems with component connections, and monitor the long-term health of your
components.
## Verifying capability routes
The `ffx scrutiny` utility provides a host of features for auditing system
security, including an audit of the capability routes in the static component
topology. The `verify routes` subcommand discovers and reports routing errors,
which can help you find any missing `offer` or `expose` declarations in your
manifest.
```posix-terminal
ffx scrutiny verify routes
```
This enables you to perform initial validation of your declarations before you
even run the components!
```none {:.devsite-disable-click-to-copy}
[
{
"capability_type": "protocol",
"results": {
"errors": [
{
"capability": "fidl.examples.echo.Echo",
"error": "no offer declaration for `/core` with name `fidl.examples.echo.Echo`",
"using_node": "/core/echo_client"
}
]
}
}
]
```
## Monitoring FIDL connections
The `fidlcat` tool allows you to monitor and debug FIDL connections to trace
individual FIDL messages sent and received by your component. Similar to the
Fuchsia debugger (`zxdb`), `fidlcat` connects to a running `debug_agent`
component on the target device and monitors running processes.
![Diagram showing how "fidlcat" interacts with the debug_agent service running
on a Fuchsia device to monitor and debug FIDL calls for a given process.]
(images/fidlcat.png){: width="592"}
Setting up the monitoring session requires the following high-level steps:
1. Run the `debug_agent` component on the target device.
1. Run the `fidlcat` client and connect to the target device.
The simplest method to start a debug session is to use the `fx fidlcat`
command, which does all of these in the context of your local Fuchsia build.
However, these steps can also be performed manually if you need to configure
them separately.
Below is an example `fidlcat` message for a FIDL protocol request. The trace
output contains helpful information for each translation, including:
* The component or process name
* The system call invoked
* The FIDL library, protocol, and method name
* Message payload containing parameters or return values
```none {:.devsite-disable-click-to-copy}
echo-client.cm 256109:256122 zx_channel_read(handle:handle: e4c7c57f, options:uint32: 0, num_bytes:uint32: 48, num_handles:uint32: 0)
-> ZX_OK
received response fidl.examples.echo/Echo.EchoString = {
response: string = "hello world!"
}
```
Note: For complete details on `fidlcat` usage and options, see
[Monitor and debug your FIDL calls](/docs/development/monitoring/fidlcat).
## Using Inspect
Component Inspection enables Fuchsia components to expose structured diagnostic
information about themselves using the Inspect API. Fuchsia provides this
information through the developer tools and bug reports to assist in diagnosing
issues or monitoring performance.
Components expose inspection metrics as a tree of named **Nodes**, each
containing a set of **Properties** as key/value pairs. Properties support a
variety of numeric, string, and array data types. The component inspector
libraries provide an interface to your component's **root node** where you can
attach additional properties of interest to your application.
![Tree diagram showing how component inspection provides structured metrics
data as a tree of "nodes," where each node can contain one or more key/value
"properties."](images/component-inspect.png){: width="583"}
You can retrieve the current set of metrics published to Inspect using the
developer tools:
* `ffx inspect`: Lets you interactively query the Inspect state using
component selectors. This is helpful for debugging components during
development.
* `ffx target snapshot`: Captures a debug snapshot archive of the entire
system, which contains the Inspect data in JSON format.
```posix-terminal
ffx inspect show core/foo-example
```
```none {:.devsite-disable-click-to-copy}
core/foo-example:
metadata:
filename = fuchsia.inspect.Tree
component_url = fuchsia-pkg://fuchsia.com/foo-example#meta/foo-example.cm
timestamp = 55457379176
payload:
root:
version = 1.0
request_metrics:
request_count = 3
error = timeout
```
Note: For more details on using the Inspect API, see
[Fuchsia component inspection](/docs/development/diagnostics/inspect).
## Exercise: Monitoring provider components
In this section, you'll use the diagnostics tools to monitor the health and
behavior of the echo server component.
### Monitor FIDL traffic
You can use `fidlcat` to monitor and debug the FIDL connections in your
components. Launch `fidlcat` and configure it to monitor the echo server
component:
```posix-terminal
fx fidlcat --remote-name=echo_server.cm
```
```none {:.devsite-disable-click-to-copy}
Checking for debug agent on [fe80::d6c5:4526:c282:fb6%qemu]:2345.
Debug agent not found. Starting one.
INFO: [main.cc(238)] Connected to symbol server gs://fuchsia-artifacts-release/debug
INFO: [main.cc(122)] Connecting to port 2345 on fe80::d6c5:4526:c282:fb6%qemu...
INFO: [main.cc(92)] Connected!
```
<aside class="key-point">
The <code>--remote-name</code> parameter configures <code>fidlcat</code> to
watch for a matching process name and attach as soon as it is discovered. You
can use <code>--remote-pid</code> to attach to an existing process.
</aside>
Initiate a FIDL connection to the server by starting an echo client instance:
```posix-terminal
ffx component bind /core/ffx-laboratory:echo-realm/echo_client
```
The client binds to the server component and communicates using the `Echo`
FIDL protocol. Review the `fidlcat` output to see a list of the FIDL
transactions handled by echo server:
```none {:.devsite-disable-click-to-copy}
Monitoring echo_server.cm
echo_server.cm 58694:58696 zx_channel_read_etc(handle: handle = fb9b5273, options: uint32 = 0, num_bytes: uint32 = 512, num_handles: uint32 = 4)
-> ZX_OK
received request fuchsia.io/Directory.Open = { flags: uint32 = 3, mode: uint32 = 493, path: string = "svc/fidl.examples.routing.echo.Echo", object: handle = Channel:f93b597b(ZX_RIGHT_TRANSFER | ZX_RIGHT_READ | ZX_RIGHT_WRITE | ZX_RIGHT_SIGNAL | ZX_RIGHT_SIGNAL_PEER | ZX_RIGHT_WAIT | ZX_RIGHT_INSPECT)(channel:0:svc/fidl.examples.routing.echo.Echo) }
echo_server.cm 58694:58696 zx_channel_read_etc(handle: handle = Channel:f93b597b(channel:0:svc/fidl.examples.routing.echo.Echo), options: uint32 = 0, num_bytes: uint32 = 512, num_handles: uint32 = 4)
-> ZX_OK
received request fidl.examples.routing.echo/Echo.EchoString = { value: string = "Hello, Fuchsia" }
echo_server.cm 58694:58696 zx_channel_write_etc(handle: handle = Channel:f93b597b(channel:0:svc/fidl.examples.routing.echo.Echo), options: uint32 = 0)
sent response fidl.examples.routing.echo/Echo.EchoString = { response: string = "Hello, Fuchsia" }
-> ZX_OK
echo_server.cm 58694:58696 zx_channel_read_etc(handle: handle = Channel:f93b597b(channel:0:svc/fidl.examples.routing.echo.Echo), options: uint32 = 0, num_bytes: uint32 = 512, num_handles: uint32 = 4)
-> ZX_ERR_PEER_CLOSED
echo_server.cm 58694:58696 zx_handle_close(handle: handle = Channel:f93b597b(channel:0:svc/fidl.examples.routing.echo.Echo))
-> ZX_OK
```
Notice the sequence of events:
1. A channel to the protocol implementation opens at
`svc/fidl.examples.routing.echo.Echo`.
1. The server receives an `Echo.EchoString` request over the open channel,
containing the string payload sent by the client.
1. The server sends a corresponding response with the same string payload.
1. The channel closes.
By tracing the FIDL connections between your components, `fidlcat` enables you
to find and diagnose potential issues such as failed connections or invalid
data payloads.
<aside class="key-point">
<b>Extra credit</b>
<p>Monitor the FIDL connections in <code>echo-client.cm</code> using
<code>fidlcat</code>. Do you see anything different from the messages recorded
from echo server?</p>
</aside>
### Add request tracking
Component inspection allows you to publish diagnostic information from your
components to assist in debugging. You'll use the Inspect API to track some
usage statistics for the echo server component.
Update the `handle_echo_request()` handler function in `main.rs` to accept a new
struct containing numeric Inspect properties for request count and bytes
processed. The handler increments these properties on each incoming request:
`echo-server/src/main.rs`:
```rust
// Inspect properties managed by the server
struct EchoConnectionStats {
total_requests: fuchsia_inspect::UintProperty,
bytes_processed: fuchsia_inspect::UintProperty,
}
// Handler for incoming service requests
async fn handle_echo_request(mut stream: EchoRequestStream, stats: &EchoConnectionStats) {
while let Some(event) = stream.try_next().await.expect("failed to serve echo service") {
let EchoRequest::EchoString { value, responder } = event;
responder.send(value.as_ref().map(|s| &**s)).expect("failed to send echo response");
if let Some(message) = value {
// Update Inspect property values
stats.total_requests.add(1);
stats.bytes_processed.add(message.len() as u64);
}
}
}
```
Add the following code to `main()` to initialize the Inspect propertes and pass
them to the updated handler:
`echo-server/src/main.rs`:
```rust
async fn main() -> Result<(), anyhow::Error> {
// ...
// Component is serving and ready to handle incoming requests
component::health().set_ok();
{{ '<strong>' }}// Create request tracking properties {{ '</strong>' }}
{{ '<strong>' }}let root_node = component::inspector().root(); {{ '</strong>' }}
{{ '<strong>' }}let stats = EchoConnectionStats { {{ '</strong>' }}
{{ '<strong>' }}total_requests: root_node.create_uint("total_requests", 0), {{ '</strong>' }}
{{ '<strong>' }}bytes_processed: root_node.create_uint("bytes_processed", 0), {{ '</strong>' }}
{{ '<strong>' }}}; {{ '</strong>' }}
// Attach request handler for incoming requests
service_fs
.for_each_concurrent(None, |_request: IncomingRequest| async {
match _request {
{{ '<strong>' }}IncomingRequest::Echo(stream) => handle_echo_request(stream, &stats).await, {{ '</strong>' }}
}
})
.await;
Ok(())
}
```
<aside class="key-point">
<b>Health checks</b>
<p>The component template includes code that sets the
<code>component::health()</code> status. This is a standardized inspection
metric for component health, which provides a convenient way to report whether
your component is running well or experiencing an issue. You'll find this status
reported under <code>fuchsia.inspect.Health</code> in the Inspect tree.</p>
<p>For more details on this metric, see
<a href="/docs/concepts/diagnostics/inspect/health">Health check</a>.</p>
</aside>
Finally, update the imports in `main.rs` to include the new Inspect libraries:
`echo-server/src/main.rs`:
```rust
use anyhow::{self, Context};
use fidl_fidl_examples_routing_echo::{EchoRequest, EchoRequestStream};
use fuchsia_component::server::ServiceFs;
use fuchsia_inspect::{component, health::Reporter};
use fuchsia_inspect::NumericProperty;
use futures::prelude::*;
```
Run `fx build` again to rebuild the component:
```posix-terminal
fx build
```
### Verify the Inspect data
Stop the current `echo-server` component instance. This allows the component to
resolve the latest version from the package server the next time it starts.
```posix-terminal
ffx component stop /core/ffx-laboratory:echo-realm/echo_server
```
Run the echo client component multiple times. This causes the request count in
`echo-server` to increment with each connection:
```posix-terminal
ffx component bind /core/ffx-laboratory:echo-realm/echo_client
ffx component bind /core/ffx-laboratory:echo-realm/echo_client
ffx component bind /core/ffx-laboratory:echo-realm/echo_client
```
View the available Inspect data for the echo server component with
`ffx inspect`. You'll see the values for request count and bytes processed in
the tree under the `root` node alongside the component health status:
```posix-terminal
ffx inspect show 'core/ffx-laboratory\:echo-realm/echo_server'
```
```none {:.devsite-disable-click-to-copy}
core/ffx-laboratory\:echo-realm/echo_server:
metadata:
filename = fuchsia.inspect.Tree
component_url = #meta/echo_server.cm
timestamp = 1476246046122
payload:
root:
bytes_processed = 42
total_requests = 3
fuchsia.inspect.Health:
start_timestamp_nanos = 1467828507317
status = OK
```
Publishing health and behavior information using Inspect enables you to observe
the current state of your components and diagnose issues on production devices.
<aside class="key-point">
<b>Extra credit</b>
<p>Use <code>ffx target snapshot</code> tool to capture a debug snapshot from
the target device. This archive also contains the Inspect data in a JSON
format. Can you locate the same echo server data returned using
<code>ffx inspect</code>?</p>
</aside>
## What's next?
Congratulations! You've successfully built a Fuchsia IPC interface using FIDL,
and connected two components together using that interface.
You have completed all the modules in this course! Take your newfound
understanding to the next level and dive deeper into the:
<a class="button button-primary"
href="/docs/concepts">Fuchsia concepts</a>