# \[ANN\] trace 0.11

**URL:** <https://discuss.ocaml.org/t/ann-trace-0-11/17796>\
**Category:** Ecosystem\
**Tags:** announce\
**Created:** [February 11, 2026, 1:51am UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796 "2026-02-11T01:51:52Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [February 11, 2026, 1:51am UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796/1 "2026-02-11T01:51:52Z")

</div>

Dear all, I’m delighted to announce the release of [trace 0.11](https://github.com/ocaml-tracing/ocaml-trace/releases/tag/v0.11). This is a major release and hopefully the last one before 1.0.

[trace](https://github.com/ocaml-tracing/ocaml-trace/) is a lightweight foundation for instrumentation, a bit like [rust’s tracing](https://github.com/tokio-rs/tracing). It provides a _protocol_ between, one the one hand, libraries and applications that are instrumented; and a _collector_ that decides what to do with that. My hope is that projects (especially libraries) can adopt `trace` without fear because of the tiny footprint and high flexibility, the same way `logs` is used in many places. Existing collectors can produce [chrome format traces](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit), fuchsia traces, plug into [tracy](https://github.com/ocaml-tracing/ocaml-tracy), or into [opentelemetry](https://github.com/ocaml-tracing/ocaml-opentelemetry); a bridge to `Runtime_events` is planned\[1\].

[API docs for the main library](https://ocaml-tracing.github.io/ocaml-trace/trace/Trace_core/index.html)

## brief example

A simple example program from the readme:

```ocaml
let (let@) = (@@)

let run () =
  Trace.set_process_name "main";
  Trace.set_thread_name "t1";

  let n = ref 0 in

  for _i = 1 to 50 do
    let@ _sp = Trace.with_span ~ __FILE__ ~ __LINE__"outer.loop" in
    for _j = 2 to 5 do
      incr n;
      let _sp = Trace.with_span ~ __FILE__ ~ __LINE__"inner.loop" in
      Trace.messagef (fun k -> k "hello %d %d" _i _j);
      Trace.message "world";
      Trace.counter_int "n" !n;
    done
  done

let () =
  (* here we setup the collector *)
  let@ () = Trace_tef.with_setup ~out:(`File "trace.json") () in
  run ()

```

If we run the program with `TRACE=1` to enable this particular collector, we get a trace file in `trace.json` (but with actual timestamps):

```json
[{"pid":2,"name":"process_name","ph":"M","args": {"name":"main"}},
{"pid":2,"tid": 3,"name":"thread_name","ph":"M","args": {"name":"t1"}},
{"pid":2,"cat":"","tid": 3,"ts": 2.00,"name":"hello 1 2","ph":"I"},
{"pid":2,"cat":"","tid": 3,"ts": 3.00,"name":"world","ph":"I"},
{"pid":2,"tid":3,"ts":4.00,"name":"c","ph":"C","args": {"n":1}},
…

```

Opening it in [https://ui.perfetto.dev](https://ui.perfetto.dev) we get something like this:

![screenshot of perfetto UI](https://github.com/ocaml-tracing/ocaml-trace/blob/main/media/ui.png?raw=true)

## what’s new in 0.11

0.11 contains major changes, almost all of which are breaking _on the collector side_. Instrumented programs should be **mostly** unaffected, aside from many deprecation warnings.

The core change is that `Trace.span` is [now](https://ocaml-tracing.github.io/ocaml-trace/trace/Trace_core/index.html#type-span) an **open sum type** , and not `int64`. This means less global state and fewer tables needed: collectors can pick exactly what data gets carried from the `enter_span` site into the `exit_span` site, if any. In turns, collectors get simpler and faster. The notion of “manual” span is now dead (a simple alias to normal spans) and all related functions are deprecated. 1.0 will not have this notion at all.

In addition, collectors are now [a bag of callbacks+a state](https://ocaml-tracing.github.io/ocaml-trace/trace/Trace_core/Collector/index.html), rather than a first class module. `trace.subscriber` has been removed because the notion of subscriber is subsumed by the notion of collector (now more easily composable). The TEF and fuchsia collectors are now simpler and free of global state.

`user_data` is now a polymorphic variant to, for better ease of use. Metrics are an open sum type, and the previous `int` and `float` cases are just provided as constructors of this type. Dependencies on `thread-local-storage` and `hmap` are now entirely gone.

## organization note

Note: the project has moved from my gh account (c-cube) to a dedicated organization [ocaml-tracing](https://github.com/ocaml-tracing/) for telemetry and tracing projects. Other projects such as [opentelemetry](https://github.com/ocaml-tracing/ocaml-opentelemetry) have also migrated there.

* * *

1. trace is more flexible than `Runtime_events` and works on OCaml 4, but of course it should be possible to have both interoperate!

---

<div class="post-metadata">

**Author:** ![syaiful6](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/syaiful6/32/6257_2.png) [@syaiful6](https://discuss.ocaml.org/u/syaiful6)\
**Post date:** [February 11, 2026, 9:24am UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796/2 "2026-02-11T09:24:29Z")

</div>

thanks @c-cube ! this is indeed will come in handy, more libraries adopt this, the more data we can collect. I will try use it in my project, a [web framework](https://github.com/syaiful6/tapak) hopefully it doesn’t affect the performance much.

Do you have an integration with EIO events? Will take a look more how to integrate the two [EIO trace example](https://github.com/ocaml-multicore/eio/blob/main/examples/trace/main.ml).

Overall, thanks for creating this.

---

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [February 11, 2026, 2:47pm UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796/3 "2026-02-11T14:47:08Z")

</div>

Thank you! Overhead for a span per HTTP request should really be fine, ultimately it depends which collector you install (no collector = basically 0 overhead).

There is no integration with Eio. I personally think Eio should use `trace` instead of hardcoding the runtime events, but I have very little hope of this actually happening :-).

Maybe the way to go will be to define a set of `Runtime_events` types that map nicely to the `trace` collector, and install a collector emitting these events. This way the event buffer would contain both sources of data.

---

<div class="post-metadata">

**Author:** ![cvine](https://avatars.discourse-cdn.com/v4/letter/c/90db22/32.png) [@cvine](https://discuss.ocaml.org/u/cvine)\
**Post date:** [February 11, 2026, 3:40pm UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796/4 "2026-02-11T15:40:41Z")

</div>

> [@c-cube](#):
>
> ```auto
> let@ \_sp = Trace.with_span \~\ __FILE_\_ \~\__ LINE_\_ "outer.loop" in
> ...
> 
> ```

`let@` is an interesting let binding for the `(@@)`operator, that I have not come across before. Is there any chance you could desugar it so that I can more fully understand what this idiom is doing?

**Edit:** No matter, I have worked it out. Quite interesting.

---

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [February 11, 2026, 4:29pm UTC](https://discuss.ocaml.org/t/ann-trace-0-11/17796/5 "2026-02-11T16:29:46Z")

</div>

Yes, it’s a fun idiom. It’s a bit similar to [gleam’s use construct](https://tour.gleam.run/advanced-features/use/) in a way. I’ve found it immensely useful for all sort of bracketed function calls (mutex enter/exit, span enter/exit, IO resource acquire/release, etc.).
