Trace is a stream of events plus meta data.
It can be viewed as an input channel. In fact, Trace.t
is an abstract data type usually inhabited with codata, i.e., some entity with hidden state. The Trace
may be an interface to a remote server, virtual machine or just a file. So treat the trace as something that works as an input channel.
Since it is worthwhile to know whether a particular event is not the trace because it didn't occur during program execution, but not because it wasn't detected by a trace tool or dropped by a given transport, we provide supports
function, to query whether the given event type is really supported (and thus might occur) by a given trace.
The meta information is also represented using value
type, and thus can contain virtually any data. Meta information is indexed with tag
value. Unlike the events, that are codata, meta is a regular data, obtained from a trace source at the time of trace creation and is not changed magically in the trace lifetime.
type error = [
| io_error
| `No_provider
No provider for a given URI
| `Ambiguous_uri
More than one provider for a given URI
]
Serialization
Serialization is dispatched by an URI describing data source or destination. URI contains enough information to uniquely designate data format and transporting options.
load ~monitor uri
fetches trace from a provided uri
. monitor
is fail_on_error by default.
save uri
pushes trace to a provided uri
Creating
create tool next
creates a new trace from the observer next
.
Meta information relates to the whole trace.
Trace global unique identifier.
set_attr trace attr value
updates trace
meta attribute attr
with a provided value.
get_attr trace attr
retrieves a value of a given attribute attr
has_attr trace attr
evaluates to true
if trace
has a given attribute attr
tool trace
returns a descriptor of a tool that was used to create the trace
.
meta trace
returns all trace
attributes as a dictionary
set_meta trace meta
substitutes meta attributes of a trace
with attributes taken from a dictionary meta
.
Querying data
supports trace feature
is true
if a tool that was used to generate the trace, as well as transporting protocol and underlying format support the given feature.
read_all trace tag
reads all event of the a given type
read_all_matching trace matcher
reads all events matching with a provided matcher
.
read_events trace
reads a sequence of events from the trace
.
next trace tag
reads and discards events until an event with a given tag is found.
val next_event : t -> event option
next_event trace
reads next event from the trace
next_matching trace matcher
reads and discards trace events until an event matching with the matcher
is found.
filter_map t ~f
will return a trace where all events a filter-mapped with the provided function f
Extension mechanism
A trace is a collaborative work of several underlying layers:
- a trace tool itself
- a transport, that delivers data from the
tool
- a protocol that is used to deliver and interpret data.
For example, a tools is an instrumented qemu-user, a transport can be just a file, and protocol can be Google protobuf.
Ideally, this three instances should be totally orthogonal, so that one can match them. In real life, we will strive to support only specific combinations.
The extension mechanism allows a user to add support for new transports and protocols. The separation between transport and protocol is left beyond the scope of this interface. A user is welcome to built its own protocol stacks and reify them into explicit API.
The interface is designed to support both static and dynamic trace tools. Although, the interface to control a dynamic tool is also left outside of the trace interface.
In order to establish a correspondence between a concrete trace instance and a trace generator a unique id is used. Each time a trace is opened a fresh new unique id is generated that is passed to both sides: to the trace (accessible via id
function) and to the trace reader (passed as a parameter). This id
can be used from the client side to dynamically control a trace tool.
module type S = sig ... end
module type P = sig ... end
val register_proto : (module P) -> proto
type step = [
| `Stop
| `Skip
| `Fail
| `Make of event
]
Monitor defines an error handling policy.