{"id":23391451,"url":"https://github.com/ahrefs/devkit","last_synced_at":"2025-09-07T14:06:02.796Z","repository":{"id":34086298,"uuid":"37909186","full_name":"ahrefs/devkit","owner":"ahrefs","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-25T08:19:24.000Z","size":1071,"stargazers_count":32,"open_issues_count":5,"forks_count":11,"subscribers_count":31,"default_branch":"master","last_synced_at":"2025-08-28T21:27:19.756Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ahrefs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-06-23T09:17:55.000Z","updated_at":"2025-08-18T22:46:30.000Z","dependencies_parsed_at":"2023-01-15T04:33:31.279Z","dependency_job_id":"83169f76-1155-4bc2-a7f2-16c8afc073ce","html_url":"https://github.com/ahrefs/devkit","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/ahrefs/devkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahrefs%2Fdevkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahrefs%2Fdevkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahrefs%2Fdevkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahrefs%2Fdevkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ahrefs","download_url":"https://codeload.github.com/ahrefs/devkit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahrefs%2Fdevkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274046000,"owners_count":25212982,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-22T04:17:30.793Z","updated_at":"2025-09-07T14:06:02.627Z","avatar_url":"https://github.com/ahrefs.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"devkit\n======\n\n[![Build Status](https://github.com/ahrefs/devkit/actions/workflows/makefile.yml/badge.svg)](https://github.com/ahrefs/devkit/actions/workflows/makefile.yml)\n\nGeneral purpose OCaml library (development kit)\nCopyright (c) 2009 Ahrefs\nReleased under the terms of LGPL-2.1 with OCaml linking exception.\n\nUsage\n-----\n\n```sh\nopam install devkit\n```\n\n### Tracing\n\nDevkit's `Web` module includes both simple, configurable, local tracing support, as well as [distributed tracing][] support via OpenTelemetry.\n\nTo use local tracing, we use the mechanism provided by [`ocaml-trace`][]: by default, the tracing calls in devkit are a no-op; but if the top-level application containing devkit installs and configures a \"tracing backend\" at runtime, then devkit's web-requests will each produce timed traces.\n\n\u003e As an example, using `trace-tef` as a backend to produce a `json` file:\n\u003e\n\u003e ```ocaml\n\u003e open Devkit\n\u003e\n\u003e let run () =\n\u003e   let resp = Web.http_request `GET \"http://icanhazip.com\" in\n\u003e   (* ... *)\n\u003e\n\u003e let () =\n\u003e   Trace_tef.with_setup ~out:(`File \"trace.json\") () @@ fun () -\u003e\n\u003e   run ()\n\u003e ```\n\nFor distributed traces, you'll both need to configure an OpenTelemetry backend for `ocaml-trace` at runtime (to collect devkit's own traces); and you will most likely also want to ensure your own application's traces (using either `ocaml-trace` or the full `ocaml-opentelemetry`) are properly configured to correctly appear as the _parent_ of devkit's traces.\n\nConfiguring an OpenTelemetry backend for the traces themselves is as simple wrapping your top-level application in a call to `Opentelemetry_trace.`[`setup_with_otel_backend`][] or the like. That will configure both OpenTelemetry's collector and the `ocaml-trace` backend.\n\nThen, to ensure that parentage is correctly propagated across your distributed architecture, devkit can produce a W3C Trace Context [`traceparent`] HTTP header. To ensure that it produces the _correct_ `traceparent`, however, we depend upon 'ambient context'. For this to function properly, you'll need to follow the [detailed instructions in the `ocaml-ambient-context` documentation][ambient-context installation].\n\nOnce thus configured, devkit will check `Opentelemetry.Scope.`[`get_ambient_scope`][] before each HTTP request, and use the ambient tracing-span as the parent of the web-request's span; which will itself then be propagated to the remote service via the `traceparent` HTTP header.\n\n\u003e As an example, if your top-level application is using Lwt, and using cohttp as the OpenTelemetry backend:\n\u003e\n\u003e ```ocaml\n\u003e open Devkit\n\u003e\n\u003e let run () =\n\u003e   let* resp = Web.http_request_lwt `GET \"http://icanhazip.com\" in\n\u003e   (* ... *)\n\u003e\n\u003e let () =\n\u003e   Ambient_context.set_storage_provider (Ambient_context_lwt.storage ()) ;\n\u003e   Opentelemetry_trace.setup_with_otel_backend\n\u003e     (Opentelemetry_client_cohttp_lwt.create_backend ())\n\u003e   @@ fun () -\u003e\n\u003e   Lwt_main.run @@ fun () -\u003e\n\u003e   run ()\n\u003e ```\n\n  [distributed tracing]: \u003chttps://opentelemetry.io/docs/concepts/signals/traces/\u003e \"OpenTelemetry: Traces\"\n  [`ocaml-trace`]: \u003chttps://github.com/c-cube/ocaml-trace\u003e \"Simon Cruanes' ocaml-trace library\"\n  [`setup_with_otel_backend`]: \u003chttps://v3.ocaml.org/p/opentelemetry/latest/doc/Opentelemetry_trace/index.html#val-setup_with_otel_backend\u003e \"ocaml-opentelemetry: Opentelemetry_trace.setup_with_otel_backend\"\n  [`traceparent`]: \u003chttps://www.w3.org/TR/trace-context/#traceparent-header\u003e \"W3C Trace Context specification: § 3.2 Traceparent header\"\n  [ambient-context installation]: \u003chttps://github.com/ELLIOTTCABLE/ocaml-ambient-context?tab=readme-ov-file#as-a-top-level-application\u003e \"ocaml-ambient-context: Installation (as a top-level application)\"\n  [`get_ambient_scope`]: \u003chttps://v3.ocaml.org/p/opentelemetry/latest/doc/Opentelemetry/Scope/index.html#val-get_ambient_scope\u003e\n\nDevelopment\n-----------\n\nInstall OCaml dependencies in your current / global switch:\n\n    opam install . --deps-only\n\nOr to install them in a new, directory-local switch:\n\n    opam switch create . --deps-only --no-install\n    opam install . --deps-only --with-test\n\nExternal dependencies:\n\n    opam list -s -e --resolve=devkit\n\nTo update ragel-generated code:\n\n    aptitude install ragel\n    make -B gen_ragel\n\nTo update metaocaml-generated code:\n\n    opam exec --switch=4.07.1+BER -- make gen_metaocaml\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahrefs%2Fdevkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahrefs%2Fdevkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahrefs%2Fdevkit/lists"}