blob: f1f68e6921e08fadf8df890f4fea2867866963bb [file] [log] [blame] [edit]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.diagnostics;
using zx;
/// The maximum number of parameters that can be sent in one `Set` call.
@available(added=HEAD)
const MAX_SAMPLE_PARAMETERS_PER_SET uint64 = 100;
/// `RuntimeError` indicates errors that manifest after the Sample server has
/// begun periodically sampling data. Clients can ignore these errors, though
/// they could potentially indicate that no `SampleReady` request will ever arrive,
/// or that the batch iterator might behave in unexpected ways, such as hanging.
@available(added=HEAD)
type RuntimeError = flexible enum {
/// There was some error when starting a batch iterator server.
/// Check Archivist's logs for more information.
BATCH_ITERATOR_FAILED = 1;
};
/// `SampleReady` carries the data for a ready-to-consume sample.
@available(added=HEAD)
type SampleReady = resource table {
/// `batch_iter` is the `BatchIterator` over the set of data.
1: batch_iter client_end:BatchIterator;
/// `seconds_since_start` is `ticks * interval_secs` for the current
/// polling period.
///
/// This can be used to check whether a value in the batch corresponds
/// to a `SampleDatum`, assuming you have not registered the same selector
/// with different `SampleStrategy` types. The procedure is:
///
/// 1) Resolve `batch_iter` into a set of Inspect hierarchies.
/// 2) Filter the set of `SampleDatum`s committed to this server with
/// the predicate `seconds_since_start % datum.interval_secs == 0`.
/// 3) Any selector from the filtered `SampleDatum`s that matches data
/// in the resolved Inspect hierarchies is valid.
///
/// If you DO have one selector registered twice with different strategies,
/// you must maintain a local cache and check the value yourself.
2: seconds_since_start zx.DurationMono;
};
@available(added=HEAD)
type SampleSinkResult = flexible resource union {
/// `SampleReady` provides a `BatchIterator` for the client containing all
/// ready samples.
///
/// This will include all `SampleStrategy::ALWAYS` samples and all
/// `SampleStrategy::ON_DIFF` for which there was a changed value.
1: ready SampleReady;
/// `error` provides an interface for receiving runtime errors from the
/// sample server.
2: error RuntimeError;
};
/// `SampleSink` is served by the client, in order to be notified when samples
/// are ready.
@available(added=HEAD)
open protocol SampleSink {
flexible OnSampleReadied(resource struct {
event SampleSinkResult;
});
/// `OnNowOrNever` initiates a final sample of all data in this server, and
/// exits after the next `OnSampleReadied` event is drained.
///
/// It ignores polling periods but not diffing behavior.
-> OnNowOrNever();
};
/// `SampleStrategy` instructs Archivist on the circumstances under which you
/// want to receive data for the given `SampleDatum`.
@available(added=HEAD)
type SampleStrategy = flexible enum : uint8 {
/// `ON_DIFF` causes the server to keep a cache of previous values.
/// At each sample period, it compares the new value to the old one
/// and only alerts if there is a change.
ON_DIFF = 1;
/// `ALWAYS` alerts at each sample period it finds data, whether it
/// has changed or not.
///
/// Note: it does NOT alert if there is no data at all.
ALWAYS = 2;
};
@available(added=HEAD)
type SampleDatum = table {
/// The selector to check.
1: selector SelectorArgument;
/// The strategy by which the server decides to notify the client.
2: strategy SampleStrategy;
/// The interval at which this datum should be sampled.
///
/// Each `SampleDatum` has its own specified interval. It is preferred to send
/// as many selectors on one `Sample` connection as possible, to allow
/// Archivist to batch requests. However, Archivist will query at a period that
/// is the greatest common divisor of all intervals. So, balance the desire for
/// a small number of `Sample` connections with keeping the intervals compatible.
///
/// Example: two data with intervals of 3 and 4 respectively would check for work
/// every second. Archivist won't actually sample if neither batch is ready, but
/// it will check.
///
/// Example: two data with intervals of 10 and 5 respectively would only check for
/// work every 5 seconds.
///
/// (In practice, the calculated sample period must be valid. See
/// MINIMUM_SAMPLE_PERIOD_SECONDS above.)
3: interval_secs zx.DurationMono;
};
/// The data for one Sample server.
@available(added=HEAD)
type SampleParameters = table {
/// The set of data to sample.
///
/// These samples will be batched by the intervals in each SampleDatum.
/// You should use `MAX_SAMPLE_PARAMETERS_PER_SET` to paginate inputs; it should
/// generally be well-sized for most selectors.
1: data vector<SampleDatum>:MAX_SAMPLE_PARAMETERS_PER_SET;
};
/// ConfigurationError indicates a bad setting in `Sample::Set`. This value
/// is returned before the first sample is taken.
@available(added=HEAD)
type ConfigurationError = flexible enum {
/// This indicates that when calculating the sample period, it was less than
/// `MINIMUM_SAMPLE_PERIOD_SECONDS`.
SAMPLE_PERIOD_TOO_SMALL = 1;
/// This indicates that there was an invalid setting in `SampleParameters`.
/// Check Archivist's logs for more information.
SAMPLE_PARAMETERS_INVALID = 2;
/// Indicates that an invalid selector was sent. Check Archivist's logs for more
/// information.
INVALID_SELECTORS = 3;
};
/// Configure Archivist to alert you periodically about the state of data
/// provided via `SampleParameters`.
///
/// If the given configuration results in a hit, a `BatchIterator` is sent
/// over the `sink` provided. That iterator may be drained, and then the
/// `sink` will go quiet until the next hit.
///
/// Archivist does not inform the client which data result in a success,
/// because it has not inherent advantaged ability to do so. Clients who
/// need to know which data was queried should cache their selectors and
/// use `selectors::select_from_hierarchy` (or similar in C++).
@discoverable(server="platform")
@available(added=HEAD)
open protocol Sample {
/// Add sample parameters.
///
/// Since this is limited by channel size, this API paginates at 300
/// items. That should fit in a channel unless a selector is particularly
/// gigantic.
///
/// Use `Commit` to indicate that all samples are sent over.
flexible Set(resource struct {
/// The data configuration for this sample server.
sample_parameters SampleParameters;
});
/// `Commit` returns errors quickly, as all configuration is validated
/// before the first sample is taken.
flexible Commit(resource struct {
/// Where results are sent.
sink client_end:SampleSink;
}) -> () error ConfigurationError;
};