{"id":32165049,"url":"https://github.com/intellection/zexbox","last_synced_at":"2026-02-05T11:06:34.675Z","repository":{"id":191582122,"uuid":"658762442","full_name":"Intellection/zexbox","owner":"Intellection","description":"Logging, Metrics and Feature Flagging in Elixir. Brought to you by Zappi.","archived":false,"fork":false,"pushed_at":"2026-02-03T14:24:49.000Z","size":159,"stargazers_count":15,"open_issues_count":1,"forks_count":0,"subscribers_count":17,"default_branch":"master","last_synced_at":"2026-02-04T01:17:02.374Z","etag":null,"topics":["elixir","feature-flags","internal-tooling","library","logging","metrics","platform-ops","telemetry"],"latest_commit_sha":null,"homepage":"https://www.zappi.io/web/","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Intellection.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-06-26T12:47:29.000Z","updated_at":"2026-02-03T14:27:07.000Z","dependencies_parsed_at":"2026-02-03T14:01:29.296Z","dependency_job_id":null,"html_url":"https://github.com/Intellection/zexbox","commit_stats":{"total_commits":124,"total_committers":5,"mean_commits":24.8,"dds":0.6451612903225806,"last_synced_commit":"b643c546cfa22731bfcfb8781f7b97363b4ac80a"},"previous_names":["intellection/exbox","intellection/zexbox"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/Intellection/zexbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Intellection%2Fzexbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Intellection%2Fzexbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Intellection%2Fzexbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Intellection%2Fzexbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Intellection","download_url":"https://codeload.github.com/Intellection/zexbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Intellection%2Fzexbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29120483,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T10:47:47.471Z","status":"ssl_error","status_checked_at":"2026-02-05T10:45:08.119Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["elixir","feature-flags","internal-tooling","library","logging","metrics","platform-ops","telemetry"],"created_at":"2025-10-21T14:58:29.860Z","updated_at":"2026-02-05T11:06:34.669Z","avatar_url":"https://github.com/Intellection.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zexbox\n\n[![Hex.pm](https://img.shields.io/hexpm/v/zexbox.svg)](https://hex.pm/packages/zexbox)\n[![CI](https://github.com/Intellection/zexbox/actions/workflows/ci.yml/badge.svg)](https://github.com/Intellection/zexbox/actions/workflows/ci.yml)\n[![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/zexbox/api-reference.html)\n\n## Installation\n\n```elixir\ndef deps do\n  [\n    {:zexbox, \"~\u003e 1.4.1\"}\n  ]\nend\n```\n\n## LaunchDarkly Feature Flags\n\nThe Zexbox library provides an idiomatic Elixir wrapper around the LaunchDarkly Erlang SDK with support for contexts, multi-contexts, and all modern LaunchDarkly features.\n\n### Configuration\n\nConfiguration is fairly simple, with the only required piece of configuration being the `sdk_key`. For production environments we recommend also including `:email` as a private attribute:\n\n```elixir\nconfig :zexbox, :flags,\n  sdk_key: System.fetch_env!(\"LAUNCH_DARKLY_SDK_KEY\"),\n  private_attributes: [:email]\n```\n\nFor local development and testing you'll probably want to [read flags from a local file](https://docs.launchdarkly.com/sdk/features/flags-from-files) and ensure there is no interaction with the LaunchDarkly API. While the two configurations will be very similar you should have different ones to put to different files. You're configurations will look something like this following:\n\n```elixir\nconfig :zexbox, :flags,\n  sdk_key: \"dev-launch-darkly-key\",\n  file_datasource: true,\n  send_events: false,\n  file_auto_update: true,\n  file_poll_interval: 1000,\n  feature_store: :ldclient_storage_map,\n  file_paths: [\"flags.json\"]\n```\n\n### Implementing\n\nIn order to use feature flags you need to start the LaunchDarkly client. You should do this in the `start/2` function of your `Application` module:\n\n```elixir\ndef start(_type, _args) do\n  Zexbox.Flags.start()\n  ...\nend\n```\n\nThis will initialise a LauncDarkly client with the `:default` tag and using the configuration you've defined in your app.\n\nIf you wish to use a different tag you can make use of `Zexbox.Flags.start/1`\n\n```elixir\nZexbox.Flags.start(:my_tag)\n```\n\nAdditionally, if you don't want to make use of the application config you can use `Zexbox.Flags.start/2`\n\n```elixir\nZexbox.Flags.start(\n  %{\n    sdk_key: \"my-sdk-key\", # This key is required\n    private_attributes: [:email]\n  },\n  :my_tag\n)\n```\n\nYou can then shut the `:default` client down when your app does in the `Zexbox.Flags.stop/0` function of your `Application` module:\n\n```elixir\ndef stop(_type, _args) do\n  Zexbox.Flags.stop()\nend\n```\n\nStopping a client with a custom tag can be done using the `Zexbox.Flags.stop/1` function.\n\n### Using Contexts\n\nContexts are the recommended way to evaluate feature flags. They provide type safety and support for multi-entity targeting:\n\n```elixir\nalias Zexbox.Flags.Context\n\n# Simple user context\ncontext = Context.new(\"user-123\")\nZexbox.Flags.variation(\"my-flag\", context, false)\n\n# Context with attributes\ncontext =\n  Context.new(\"user-123\")\n  |\u003e Context.set(\"email\", \"user@example.com\")\n  |\u003e Context.set(\"plan\", \"enterprise\")\n  |\u003e Context.set_private_attributes([\"email\"])\n\nZexbox.Flags.variation(\"premium-feature\", context, false)\n\n# Multi-context (target based on user AND organization)\nuser = Context.new(\"user-123\", \"user\")\norg = Context.new(\"org-456\", \"organization\")\nmulti = Context.new_multi([user, org])\n\nZexbox.Flags.variation(\"enterprise-feature\", multi, false)\n```\n\n**Backward Compatibility**: Raw maps are still supported:\n\n```elixir\nZexbox.Flags.variation(\n  \"my-flag\",\n  %{key: \"user-hash\", email: \"user@email.com\"},\n  \"my_default_value\"\n)\n```\n\nFor more details, see the [Context Module Guide](CONTEXT_MODULE_GUIDE.md).\n\n## Logging\n\nDefault logging can be attached to your controllers by calling `Zexbox.Logging.attach_controller_logs!` in the `start/2` function of your `Application` module:\n\n```elixir\ndef start(_type, _args) do\n  Zexbox.Logging.attach_controller_logs!()\n  ...\nend\n```\n\nThis sets up handlers for the `[:phoenix, :endpoint, :start]` and `[:phoenix, :endpoint, :stop]` [events](https://hexdocs.pm/phoenix/1.4.12/Phoenix.Endpoint.html#module-instrumentation) which are dispatched by `Plug.Telemetry` at the beginning and end of each request. The handlers are named `phoenix_controller_logs_stop` and `phoenix_controller_logs_start` respectively. The handlers log structured data (reports) in the following form `[info] [event: \u003cevent_params\u003e, measurements: \u003cmeasurement_data\u003e, metadata: \u003cmetadat\u003e, config: \u003cconfig\u003e]`.\n\n### Adding your own logs\n\nAdding your own logs is as simple as calling the `Zexbox.Telementry.attach/4` (which is just a wrapper around `:telemetry.attach/4`)\n\n```elixir\nZexbox.Telemetry.attach(:my_event, [:my, :event], \u0026MyAppHandler.my_handler/3, nil)\n```\n\n## Metrics\n\nIn order to setup metrics with InfluxDB you'll need to add the following configuration:\n\n```elixir\nconfig :zexbox, Zexbox.Metrics.Connection,\n  auth: [\n    method: :token,\n    token: \"token\"\n  ],\n  host: \"localhost\",\n  port: \"8086\",\n  version: :v2,\n  org: \"zappi\",\n  bucket: \"my_app\"\n```\n\nA more indepth explanation on the configuration can be found in the `Instream.Connection` [hexdocs](https://hexdocs.pm/instream/Instream.html).\n\nIn order to make use of metrics you'll need to add the `Zexbox` module to your application's `Supervisor` tree\n\n```elixir\ndefmodule MyApp.Application do\n  use Application\n\n  @impl Application\n  def start(_type, args) do\n    ...\n    children = [\n      ...\n      {Zexbox.Metrics, []}\n    ]\n    ...\n    Supervisor.start_link(children, opts)\n  end\nend\n```\n\nThis will write metrics to InfluxDB after every Phoenix DB request. The structure of the metrics is defined by the  `Zexbox.Metrics.ControllerSeries` module.\n\n### Adding Custom Controller Metrics\n\nYou can easily add your own controller metrics using the `Zexbox.Metrics.Client` module\n\n```elixir\nmetric = %Zexbox.Metrics.Series{\n  measurement: \"my_measurement\",\n  fields: %{\n    \"my_field\" =\u003e 1\n  },\n  tags: %{\n    \"my_tag\" =\u003e \"my_value\"\n  }\n}\nZexbox.Metrics.Client.write_metric(metric)\n```\n\n### Disabling Metrics For a Single Request/Process\n\nIf you want to suppress metrics for a specific request (for example: test traffic, synthetic checks, or health probes), disable metrics for the **current process**:\n\n```elixir\nZexbox.Metrics.disable_for_process()\n```\n\nAll metric writes from that process will be skipped (including the default controller metrics and any custom calls to `Zexbox.Metrics.Client.write_metric/1`). If you spawn tasks using `Task.async/1`, the disabled state is also respected in the spawned task via the caller chain.\n\nTo re-enable metrics for the current process:\n\n```elixir\nZexbox.Metrics.enable_for_process()\n```\n\n## Copyright and License\n\nCopyright (c) 2024, Zappistore.\n\nZexbox source code is licensed under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellection%2Fzexbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintellection%2Fzexbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellection%2Fzexbox/lists"}