mirror of
https://github.com/ocaml-tracing/ocaml-trace.git
synced 2026-05-05 08:54:27 -04:00
Compare commits
9 commits
41b152c789
...
8005926bfc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8005926bfc | ||
|
|
3a349e1b36 | ||
|
|
207154af0d | ||
|
|
e974c6d31b | ||
|
|
50d0656ab0 | ||
|
|
158e0ac4cd | ||
|
|
5629555a72 | ||
|
|
42bf837113 | ||
|
|
83d408355b |
15 changed files with 224 additions and 97 deletions
17
.github/workflows/format.yml
vendored
17
.github/workflows/format.yml
vendored
|
|
@ -1,28 +1,17 @@
|
||||||
name: format
|
name: format
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
name: format
|
name: format
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
ocaml-compiler:
|
|
||||||
- '5.3'
|
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
|
container: ghcr.io/c-cube/c-cube-commmon/ci-doc-5.3:latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@v6
|
||||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
|
||||||
uses: ocaml/setup-ocaml@v3
|
|
||||||
with:
|
|
||||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
|
||||||
dune-cache: true
|
|
||||||
allow-prerelease-opam: true
|
|
||||||
|
|
||||||
- run: opam install ocamlformat.0.27.0
|
|
||||||
- run: opam exec -- make format-check
|
- run: opam exec -- make format-check
|
||||||
|
|
||||||
|
|
|
||||||
17
.github/workflows/gh-pages.yml
vendored
17
.github/workflows/gh-pages.yml
vendored
|
|
@ -11,26 +11,19 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
container: ghcr.io/c-cube/c-cube-commmon/ci-doc-5.3:latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Use OCaml
|
- run: opam pin .#HEAD -y -n
|
||||||
uses: ocaml/setup-ocaml@v3
|
|
||||||
with:
|
|
||||||
ocaml-compiler: '5.1.x'
|
|
||||||
allow-prerelease-opam: true
|
|
||||||
dune-cache: true
|
|
||||||
|
|
||||||
- run: opam pin odoc 3.1.0 -y -n
|
|
||||||
# crash with 2.4, see https://github.com/ocaml/odoc/issues/1066
|
|
||||||
- name: Deps
|
- name: Deps
|
||||||
run: opam install odig thread-local-storage trace trace-tef trace-fuchsia ppx_trace
|
run: opam install thread-local-storage lwt trace trace-tef trace-fuchsia ppx_trace
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: opam exec -- odig odoc --cache-dir=_doc/ trace trace-tef trace-fuchsia ppx_trace
|
run: opam exec -- odig odoc --cache-dir=_doc/ trace trace-tef trace-fuchsia ppx_trace
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./_doc/html
|
publish_dir: ./_doc/html
|
||||||
|
|
|
||||||
47
.github/workflows/main.yml
vendored
47
.github/workflows/main.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
name: Build and Test
|
name: build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -8,28 +8,21 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run:
|
run:
|
||||||
name: build
|
name: build # build+test on various versions of OCaml, on linux
|
||||||
|
timeout-minutes: 15
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
container:
|
||||||
- ubuntu-latest
|
- ghcr.io/c-cube/c-cube-commmon/ci-4.08:latest
|
||||||
#- macos-latest
|
- ghcr.io/c-cube/c-cube-commmon/ci-4.14:latest
|
||||||
#- windows-latest
|
- ghcr.io/c-cube/c-cube-commmon/ci-5.0:latest
|
||||||
ocaml-compiler:
|
- ghcr.io/c-cube/c-cube-commmon/ci-5.4:latest
|
||||||
- '4.08.x'
|
|
||||||
- '4.14.x'
|
|
||||||
- '5.3.x'
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-latest
|
||||||
|
container: ${{ matrix.container }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@v6
|
||||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
|
||||||
uses: ocaml/setup-ocaml@v3
|
|
||||||
with:
|
|
||||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
|
||||||
dune-cache: true
|
|
||||||
allow-prerelease-opam: true
|
|
||||||
|
|
||||||
# check that trace compiles with no optional deps
|
# check that trace compiles with no optional deps
|
||||||
- run: opam install -t trace --deps-only
|
- run: opam install -t trace --deps-only
|
||||||
|
|
@ -37,24 +30,16 @@ jobs:
|
||||||
|
|
||||||
# install all packages
|
# install all packages
|
||||||
- run: opam install -t trace trace-tef trace-fuchsia --deps-only
|
- run: opam install -t trace trace-tef trace-fuchsia --deps-only
|
||||||
- run: opam install ppx_trace --deps-only # no tests
|
- run: opam install ppx_trace --deps-only
|
||||||
if: matrix.ocaml-compiler != '4.08.x'
|
if: ${{ !contains(matrix.container, 'ci-4.08') }}
|
||||||
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
||||||
- run: opam exec -- dune build '@install' -p ppx_trace
|
- run: opam exec -- dune build '@install' -p ppx_trace
|
||||||
if: matrix.ocaml-compiler != '4.08.x'
|
if: ${{ !contains(matrix.container, 'ci-4.08') }}
|
||||||
- run: opam exec -- dune runtest -p trace
|
- run: opam exec -- dune runtest -p trace
|
||||||
- run: opam install trace
|
- run: opam install trace
|
||||||
- run: opam exec -- dune runtest -p trace-tef,trace-fuchsia
|
- run: opam exec -- dune runtest -p trace-tef,trace-fuchsia
|
||||||
|
|
||||||
# with depopts
|
# with depopts
|
||||||
- run: opam install hmap thread-local-storage
|
- run: opam install thread-local-storage lwt mtime
|
||||||
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
||||||
|
- run: opam exec -- dune runtest -p trace,trace-tef,trace-fuchsia
|
||||||
- run: opam install picos_aux
|
|
||||||
if: matrix.ocaml-compiler != '4.08.x' && matrix.ocaml-compiler != '4.12.x'
|
|
||||||
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
|
||||||
if: matrix.ocaml-compiler != '4.08.x' && matrix.ocaml-compiler != '4.12.x'
|
|
||||||
|
|
||||||
- run: opam install mtime
|
|
||||||
- run: opam exec -- dune build '@install' -p trace,trace-tef,trace-fuchsia
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,14 @@
|
||||||
(synopsis
|
(synopsis
|
||||||
"A lightweight stub for tracing/observability, agnostic in how data is collected")
|
"A lightweight stub for tracing/observability, agnostic in how data is collected")
|
||||||
(description
|
(description
|
||||||
"ocaml-trace can be used to instrument libraries and programs with low overhead.\n\n It doesn't do any IO unless a collector is plugged in, which only\n the final executable should do.")
|
"ocaml-trace can be used to instrument libraries and programs with low overhead. It doesn't do any IO unless a collector is plugged in, which only the final executable should do.")
|
||||||
(depends
|
(depends
|
||||||
(ocaml
|
(ocaml
|
||||||
(>= 4.08))
|
(>= 4.08))
|
||||||
dune)
|
dune)
|
||||||
(depopts
|
(depopts
|
||||||
unix
|
unix
|
||||||
|
lwt
|
||||||
(thread-local-storage (>= 0.2))
|
(thread-local-storage (>= 0.2))
|
||||||
(mtime
|
(mtime
|
||||||
(>= 2.0)))
|
(>= 2.0)))
|
||||||
|
|
|
||||||
6
src/lwt/dune
Normal file
6
src/lwt/dune
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
(library
|
||||||
|
(name trace_lwt)
|
||||||
|
(public_name trace.lwt)
|
||||||
|
(optional) ; lwt
|
||||||
|
(libraries trace.core lwt)
|
||||||
|
(synopsis "Interface with lwt"))
|
||||||
50
src/lwt/trace_lwt.ml
Normal file
50
src/lwt/trace_lwt.ml
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
(** Optional interface with lwt.
|
||||||
|
|
||||||
|
This provides a Lwt-friendly variant of {!Trace_core.with_span}.
|
||||||
|
|
||||||
|
To track the ambient span, which can be useful for some backends or for
|
||||||
|
async spans, you can use [Ambient_context_lwt], a collector-specific ambient
|
||||||
|
span provider (eg [Opentelemetry_trace] comes with one), or define your own
|
||||||
|
like this:
|
||||||
|
|
||||||
|
{[
|
||||||
|
(* new key to track the current span in lwt context *)
|
||||||
|
let k_ambient_span : Trace_core.span Lwt.key = Lwt.new_key ()
|
||||||
|
|
||||||
|
(* ambient span provider, install it using Trace_core.set_ambient_context_provider] *)
|
||||||
|
let ambient_span_provider : Trace_core.Ambient_span_provider.t =
|
||||||
|
ASP_some
|
||||||
|
( (),
|
||||||
|
{
|
||||||
|
get_current_span = (fun () -> Lwt.get k_ambient_span);
|
||||||
|
with_current_span_set_to =
|
||||||
|
(fun () span f ->
|
||||||
|
Lwt.with_value k_ambient_span (Some span) (fun () -> f span));
|
||||||
|
} )
|
||||||
|
]}
|
||||||
|
|
||||||
|
@since NEXT_RELEASE *)
|
||||||
|
|
||||||
|
open Trace_core
|
||||||
|
|
||||||
|
(** [with_span name f] enters a span [sp], calls [f sp] which returns a Lwt
|
||||||
|
promise, and make sure to exit the span [sp] when [f sp] exits (or fails).
|
||||||
|
|
||||||
|
This is similar to {!Trace_core.with_span} but it respects the promise
|
||||||
|
semnatics of Lwt (ie. it doesn't exit the span immediately instead of
|
||||||
|
waiting for the promise to end).
|
||||||
|
|
||||||
|
To track the current span you still need to install a Lwt-friendly
|
||||||
|
{!Trace_core.Ambient_span_provider.t} (probably using {!Lwt.with_value}). *)
|
||||||
|
let with_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent ?params ?data
|
||||||
|
name (f : span -> 'a Lwt.t) : 'a Lwt.t =
|
||||||
|
if Trace_core.enabled () then (
|
||||||
|
let span =
|
||||||
|
Trace_core.enter_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent
|
||||||
|
?params ?data name
|
||||||
|
in
|
||||||
|
let fut = Trace_core.with_current_span_set_to span f in
|
||||||
|
Lwt.on_termination fut (fun () -> Trace_core.exit_span span);
|
||||||
|
fut
|
||||||
|
) else
|
||||||
|
f Trace_core.Collector.dummy_span
|
||||||
3
test/common/dune
Normal file
3
test/common/dune
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
(library
|
||||||
|
(name test_trace_common)
|
||||||
|
(libraries trace.core))
|
||||||
32
test/common/test_trace_common.ml
Normal file
32
test/common/test_trace_common.ml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
(** Shared test utilities for ambient span tests. *)
|
||||||
|
|
||||||
|
type Trace_core.span += Named of string
|
||||||
|
|
||||||
|
let make_recorder () =
|
||||||
|
let open Trace_core.Collector in
|
||||||
|
let cbs =
|
||||||
|
Callbacks.make
|
||||||
|
~enter_span:(fun
|
||||||
|
()
|
||||||
|
~__FUNCTION__:_
|
||||||
|
~__FILE__:_
|
||||||
|
~__LINE__:_
|
||||||
|
~level:_
|
||||||
|
~params:_
|
||||||
|
~data:_
|
||||||
|
~parent:_
|
||||||
|
name
|
||||||
|
-> Named name)
|
||||||
|
~exit_span:(fun () _sp -> ())
|
||||||
|
~add_data_to_span:(fun () _sp _data -> ())
|
||||||
|
~message:(fun () ~level:_ ~params:_ ~data:_ ~span:_ _msg -> ())
|
||||||
|
~metric:(fun () ~level:_ ~params:_ ~data:_ _name _m -> ())
|
||||||
|
()
|
||||||
|
in
|
||||||
|
C_some ((), cbs)
|
||||||
|
|
||||||
|
let current_name () =
|
||||||
|
match Trace_core.current_span () with
|
||||||
|
| None -> "none"
|
||||||
|
| Some (Named s) -> s
|
||||||
|
| Some _ -> "<other>"
|
||||||
21
test/lwt/dune
Normal file
21
test/lwt/dune
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
(executable
|
||||||
|
(name t_lwt)
|
||||||
|
(modules t_lwt)
|
||||||
|
(libraries
|
||||||
|
trace
|
||||||
|
test_trace_common
|
||||||
|
(select
|
||||||
|
t_lwt.ml
|
||||||
|
from
|
||||||
|
(trace.lwt lwt.unix -> t_lwt.real.ml)
|
||||||
|
(-> t_lwt.quine.ml))))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(alias runtest)
|
||||||
|
(package trace)
|
||||||
|
(action
|
||||||
|
(progn
|
||||||
|
(with-stdout-to
|
||||||
|
t_lwt.output
|
||||||
|
(run %{exe:t_lwt.exe} %{dep:t_lwt.expected}))
|
||||||
|
(diff t_lwt.expected t_lwt.output))))
|
||||||
10
test/lwt/t_lwt.expected
Normal file
10
test/lwt/t_lwt.expected
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
=== ambient span (Lwt) ===
|
||||||
|
before any span: none
|
||||||
|
sync outer: sync-outer
|
||||||
|
sync inner: sync-inner
|
||||||
|
after sync: none
|
||||||
|
lwt outer: lwt-outer
|
||||||
|
lwt inner: lwt-inner
|
||||||
|
after lwt inner: lwt-outer
|
||||||
|
after lwt outer: none
|
||||||
|
after binds: bind-test
|
||||||
10
test/lwt/t_lwt.quine.ml
Normal file
10
test/lwt/t_lwt.quine.ml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(* When trace.lwt is unavailable, echo the expected file
|
||||||
|
so the diff always passes. The file is passed as argv[1] by the dune rule. *)
|
||||||
|
let () =
|
||||||
|
let ic = open_in Sys.argv.(1) in
|
||||||
|
(try
|
||||||
|
while true do
|
||||||
|
print_char (input_char ic)
|
||||||
|
done
|
||||||
|
with End_of_file -> ());
|
||||||
|
close_in ic
|
||||||
60
test/lwt/t_lwt.real.ml
Normal file
60
test/lwt/t_lwt.real.ml
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
(* Test ambient span tracking via Lwt key provider *)
|
||||||
|
|
||||||
|
open Test_trace_common
|
||||||
|
|
||||||
|
let ( let@ ) = ( @@ )
|
||||||
|
let k_ambient_span : Trace_core.span Lwt.key = Lwt.new_key ()
|
||||||
|
|
||||||
|
let ambient_span_provider : Trace_core.Ambient_span_provider.t =
|
||||||
|
ASP_some
|
||||||
|
( (),
|
||||||
|
{
|
||||||
|
get_current_span = (fun () -> Lwt.get k_ambient_span);
|
||||||
|
with_current_span_set_to =
|
||||||
|
(fun () span f ->
|
||||||
|
Lwt.with_value k_ambient_span (Some span) (fun () -> f span));
|
||||||
|
} )
|
||||||
|
|
||||||
|
let () =
|
||||||
|
print_endline "=== ambient span (Lwt) ===";
|
||||||
|
Trace_core.set_ambient_context_provider ambient_span_provider;
|
||||||
|
let coll = make_recorder () in
|
||||||
|
let@ () = Trace_core.with_setup_collector coll in
|
||||||
|
|
||||||
|
(* sync with_span works with the Lwt provider *)
|
||||||
|
Printf.printf "before any span: %s\n" (current_name ());
|
||||||
|
|
||||||
|
(let@ _outer = Trace_core.with_span ~__FILE__ ~__LINE__ "sync-outer" in
|
||||||
|
Printf.printf "sync outer: %s\n" (current_name ());
|
||||||
|
let@ _inner = Trace_core.with_span ~__FILE__ ~__LINE__ "sync-inner" in
|
||||||
|
Printf.printf "sync inner: %s\n" (current_name ()));
|
||||||
|
|
||||||
|
Printf.printf "after sync: %s\n" (current_name ());
|
||||||
|
|
||||||
|
(* Lwt-specific tests *)
|
||||||
|
Lwt_main.run
|
||||||
|
(let open Lwt.Syntax in
|
||||||
|
(* nested Trace_lwt.with_span *)
|
||||||
|
let* () =
|
||||||
|
Trace_lwt.with_span ~__FILE__ ~__LINE__ "lwt-outer" (fun _outer ->
|
||||||
|
Printf.printf "lwt outer: %s\n" (current_name ());
|
||||||
|
let* () =
|
||||||
|
Trace_lwt.with_span ~__FILE__ ~__LINE__ "lwt-inner" (fun _inner ->
|
||||||
|
Printf.printf "lwt inner: %s\n" (current_name ());
|
||||||
|
Lwt.return_unit)
|
||||||
|
in
|
||||||
|
Printf.printf "after lwt inner: %s\n" (current_name ());
|
||||||
|
Lwt.return_unit)
|
||||||
|
in
|
||||||
|
Printf.printf "after lwt outer: %s\n" (current_name ());
|
||||||
|
|
||||||
|
(* context survives Lwt.bind chain *)
|
||||||
|
let* () =
|
||||||
|
Trace_lwt.with_span ~__FILE__ ~__LINE__ "bind-test" (fun _sp ->
|
||||||
|
let* () = Lwt.return_unit in
|
||||||
|
let* () = Lwt.return_unit in
|
||||||
|
Printf.printf "after binds: %s\n" (current_name ());
|
||||||
|
Lwt.return_unit)
|
||||||
|
in
|
||||||
|
|
||||||
|
Lwt.return_unit)
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
(modules t_tls)
|
(modules t_tls)
|
||||||
(libraries
|
(libraries
|
||||||
trace
|
trace
|
||||||
; avoid using a recent dune with `enabled-if`, by just using `select` instead.
|
test_trace_common
|
||||||
; the dummy case just echoes back the expected file.
|
|
||||||
(select
|
(select
|
||||||
t_tls.ml
|
t_tls.ml
|
||||||
from
|
from
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,9 @@
|
||||||
(* Test ambient span tracking via thread-local-storage provider *)
|
(* Test ambient span tracking via thread-local-storage provider *)
|
||||||
|
|
||||||
|
open Test_trace_common
|
||||||
|
|
||||||
let ( let@ ) = ( @@ )
|
let ( let@ ) = ( @@ )
|
||||||
|
|
||||||
(* Unique span type so we can identify spans by name *)
|
|
||||||
type Trace_core.span += Named of string
|
|
||||||
|
|
||||||
let make_recorder () =
|
|
||||||
let open Trace_core.Collector in
|
|
||||||
let cbs =
|
|
||||||
Callbacks.make
|
|
||||||
~enter_span:(fun
|
|
||||||
()
|
|
||||||
~__FUNCTION__:_
|
|
||||||
~__FILE__:_
|
|
||||||
~__LINE__:_
|
|
||||||
~level:_
|
|
||||||
~params:_
|
|
||||||
~data:_
|
|
||||||
~parent:_
|
|
||||||
name
|
|
||||||
-> Named name)
|
|
||||||
~exit_span:(fun () _sp -> ())
|
|
||||||
~add_data_to_span:(fun () _sp _data -> ())
|
|
||||||
~message:(fun () ~level:_ ~params:_ ~data:_ ~span:_ _msg -> ())
|
|
||||||
~metric:(fun () ~level:_ ~params:_ ~data:_ _name _m -> ())
|
|
||||||
()
|
|
||||||
in
|
|
||||||
C_some ((), cbs)
|
|
||||||
|
|
||||||
let current_name () =
|
|
||||||
match Trace_core.current_span () with
|
|
||||||
| None -> "none"
|
|
||||||
| Some (Named s) -> s
|
|
||||||
| Some _ -> "<other>"
|
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
print_endline "=== ambient span (TLS) ===";
|
print_endline "=== ambient span (TLS) ===";
|
||||||
Trace_thread_local_storage.setup ();
|
Trace_thread_local_storage.setup ();
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,8 @@ opam-version: "2.0"
|
||||||
version: "0.12"
|
version: "0.12"
|
||||||
synopsis:
|
synopsis:
|
||||||
"A lightweight stub for tracing/observability, agnostic in how data is collected"
|
"A lightweight stub for tracing/observability, agnostic in how data is collected"
|
||||||
description: """
|
description:
|
||||||
ocaml-trace can be used to instrument libraries and programs with low overhead.
|
"ocaml-trace can be used to instrument libraries and programs with low overhead. It doesn't do any IO unless a collector is plugged in, which only the final executable should do."
|
||||||
|
|
||||||
It doesn't do any IO unless a collector is plugged in, which only
|
|
||||||
the final executable should do."""
|
|
||||||
maintainer: ["Simon Cruanes"]
|
maintainer: ["Simon Cruanes"]
|
||||||
authors: ["Simon Cruanes"]
|
authors: ["Simon Cruanes"]
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
|
|
@ -21,6 +18,7 @@ depends: [
|
||||||
]
|
]
|
||||||
depopts: [
|
depopts: [
|
||||||
"unix"
|
"unix"
|
||||||
|
"lwt"
|
||||||
"thread-local-storage" {>= "0.2"}
|
"thread-local-storage" {>= "0.2"}
|
||||||
"mtime" {>= "2.0"}
|
"mtime" {>= "2.0"}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue