{"id":22511154,"url":"https://github.com/renderedtext/ex-watchman","last_synced_at":"2025-08-03T14:32:23.237Z","repository":{"id":62027378,"uuid":"65913074","full_name":"renderedtext/ex-watchman","owner":"renderedtext","description":"Watchman is your friend who monitors your processes so you don't have to","archived":false,"fork":false,"pushed_at":"2024-03-15T12:30:48.000Z","size":97,"stargazers_count":3,"open_issues_count":1,"forks_count":2,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-04-10T06:55:32.900Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","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/renderedtext.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}},"created_at":"2016-08-17T14:13:15.000Z","updated_at":"2024-04-10T06:55:32.900Z","dependencies_parsed_at":"2023-11-24T17:29:00.652Z","dependency_job_id":"8e1f0aaa-8bc7-410d-8325-b6959edab49b","html_url":"https://github.com/renderedtext/ex-watchman","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-watchman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-watchman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-watchman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-watchman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/renderedtext","download_url":"https://codeload.github.com/renderedtext/ex-watchman/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228548583,"owners_count":17935226,"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","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-07T02:09:40.806Z","updated_at":"2025-08-03T14:32:23.227Z","avatar_url":"https://github.com/renderedtext.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Watchman\n\nWatchman is your friend who monitors your processes so you don't have to.\n\n## Installation\n\nAdd the following to the list of your dependencies:\n\n``` elixir\ndef deps do\n  [\n    {:watchman, github: \"renderedtext/ex-watchman\"}\n  ]\nend\n```\n\nAlso, add it to the list of your applications:\n\n``` elixir\ndef application do\n  [applications: [:watchman]]\nend\n```\n\n## Setup\n\nFirst, set up the host and the port of the metrics server, and the prefix you\nwant to use. Example:\n\n``` elixir\nconfig :watchman,\n  host: \"statistics.example.com\",\n  port: 22001,\n  prefix: \"my-service.prod\"\n```\n\n## Usage\n\nNever name metric with variable:\n\n```elixir\nWatchman.submit(\"user.#{id}.count\", 30)\n```\n\nIf you need something like that, you probably need [tags](#tags)!\n\n### Heartbeat\n\nTo keep track if the application is running, use the heartbeat feature. Define\na child process in the supervisor with a defined interval between notifications\n(in seconds), like so:\n\n``` elixir\nworker(Watchman.Heartbeat, [[interval: 1]])\n```\n\n### Submitting simple values\n\nTo submit a simple value from your service:\n\n``` elixir\nWatchman.submit(\"users.count\", 30)\n```\n\nTo submit a timing value:\n\n``` elixir\nWatchman.submit(\"installation.duration\", 30, :timing)\n```\n\n### Counting\n\nTo increment a simple value from your service:\n\n``` elixir\nWatchman.increment(\"users.count\")\n```\n\nto decrement:\n\n``` elixir\nWatchman.decrement(\"users.count\")\n```\n\nYou can also use the count annotation. Placed in front of a method, it will\ncount the number of times the method was called.\n\nTo count a method with an auto generated key in your module:\n```elixir\ndefmodule Example do\n  use Watchman.Count\n\n  @count(key: :auto)\n  def test\n    :timer.sleep(10)\n  end\n\nend\n```\n\nTo count a method while giving the metric a key:\n```elixir\ndefmodule Example do\n  use Watchman.Count\n\n  @count(key: \"lazy.test.function.that.only.sleeps.count\")\n  def test\n    :timer.sleep(10)\n  end\n\nend\n```\n\n### Benchmarking\n\nTo benchmark a part of your service:\n\n``` elixir\nWatchman.benchmark(\"sleep.duration\", fn -\u003e\n  IO.puts \"Sleeping\"\n  :timer.sleep(10000)\n  IO.puts \"Wake up\"\nend)\n```\n\nTo benchmark a function with an auto generated key in your module:\n\n``` elixir\ndefmodule Example do\n  use Watchman.Benchmark\n\n  @benchmark(key: :auto)\n  def test\n    :timer.sleep(10)\n  end\n\nend\n```\n\nTo benchmark a function while giving the metric a key:\n\n``` elixir\ndefmodule Example do\n  use Watchman.Benchmark\n\n  @benchmark(key: \"lazy.test.function.that.only.sleeps.benchmark\")\n  def test\n    :timer.sleep(10)\n  end\n\nend\n```\n\nPlease note that if the key is manually given, it cannot contain blank spaces.\n\nTo benchmark functions with multiple bodies, use only a single annotation:\n\n``` elixir\ndefmodule Example do\n  use Watchman.Benchmark\n\n  @benchmark(key: :auto)\n  def sum(a, b) when is_integer(a) and is_integer(b) do\n    a + b\n  end\n  def sum(a, b) when is_list(a) and is_list(b) do\n    a ++ b\n  end\n  def sum(a, b) when is_binary(a) and is_binary(b) do\n    a \u003c\u003e b\n  end\n\nend\n```\n\n## Tags\nIf metrics family is needed, something like:\n```\nuser.1.count\nuser.2.count\nuser.3.count\n...\n```\n\n**NEVER** name metric like this:\n```elixir\nWatchman.increment(\"user.#{id}.count\")\n```\ninstead use tags, like this:\n```elixir\nWatchman.increment({\"user.count\", [\"#{id}\"]})\n```\n\nSecond example will create 1 measurement in InfluxDB with tag value `\"#{id}\"`.\nAnd it is right thing to do.\n\nThere can be 3 tag values at the most.\n(If you need more - shout.)\n\n## System metrics\n\nYou can gather system metrics simply by adding a `Watchman.System` worker to\nyour supervisor.\n\nThe following will send a bundle of metrics to your metrics server every `60`\nseconds:\n\n``` elixir\nworker(Watchman.System, [[interval: 60]])\n```\n\nThe following metrics are sent:\n\n- system.memory.total\n- system.memory.processes\n- system.memory.processes_used\n- system.memory.atom\n- system.memory.atom_used\n- system.memory.binary\n- system.memory.code\n- system.memory.ets\n\n## Ecto Metrics\n\nWatchman.Ecto is a custom built ecto logger that submits transaction data\nto StatsD servers.\n\nTo use the logger add this Logger to your ecto configuration.\n\nExample setup from `config/config.ex`:\n\n```\nrepo_name = \"example_repo\"\n\nconfig :my_app, MyApp.Repo,\n  loggers: [\n    {Ecto.LogEntry, :log, [:debug]},\n    {Watchman.Ecto, :log, [repo_name]}\n  ]\n```\n\nWhen set up, this will generate the following metrics:\n\n```\n1. total transaction counter\n\u003cwatchman-prefix\u003e.transaction.count, with tags: [repo_name, table_name]\n\n2. the time spent executing the query in DB native units (nanosecs)\n\u003cwatchman-prefix\u003e.transaction.duration, with tags: [repo_name, table_name, \"query\"]\n\n3. the time spent to check the connection out in DB native units (nanosecs)\n\u003cwatchman-prefix\u003e.transaction.duration, with tags: [repo_name, table_name, \"queue\"]\n\n4. the time spent decoding the result in DB native units (nanosecs)\n\u003cwatchman-prefix\u003e.transaction.duration, with tags: [repo_name, table_name, \"decode\"]\n\n5. total time spend for the transaction in DB native units (nanosecs)\n\u003cwatchman-prefix\u003e.transaction.duration, with tags: [repo_name, table_name, \"total\"]\n```\n\n## Advanced configuration\n\n### Buffer Size\n\nWatchman has a limited buffer size for unprocessed messages (metrics that are\nwaiting to be submitted via UDP).\n\nThis limit is set in order to avoid accidental accumulation of messages in\nWatchman.Server's message box.\n\nThe default value is unprocessed 10_000 messages.\n\nTo change the default value, set a new value in the config:\n\n``` elixir\nconfig :watchman,\n  host: \"statistics.example.com\",\n  port: 22001,\n  prefix: \"my-service.prod\"\n  max_buffer_size: 50            # \u003c----- sets the buffer to 50 messages\n```\n\n### Metric channels\n\nFor filtering and custom metric names in different enviorments of metrics with\nwatchman you can set up a `send_only` optional config field with `:internal`, `:external`, and `:always`\nand send your metrics as tuples with channel name in prefix:\n\n``` elixir\nWatchman.increment(external: \"user.count\")\nWatchman.increment(internal: {\"user.count\", [\"#{id}\"]})\n## or you can merge into one\nWatchman.increment(external: \"user.count\", internal: {\"user.count\", [\"#{id}\"]})\n```\n\n### Metrics UDP format\n\nThere is two available UDP formats for messages:\n- `:statsd_graphite` suitable for statsd with graphite backend \n``` elixir\n\"tagged.#{prefix}.#{tags}.#{name}:#{value}|#{type}\"\n# basic line protocol \n# \u003cmetricname\u003e:\u003cvalue\u003e|\u003ctype\u003e\n```\n- `:aws_cloudwatch` suitable for aws cloudwatch backend\n``` elixir\n\"#{prefix}.#{name}:#{value}|#{type}|##{tags}\" \n# evaulates to \n#MetricName:value|type|@sample_rate|#tag1:value,tag1...\n```\n\n## License\n\nThis software is licensed under [the Apache 2.0 license](LICENSE).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderedtext%2Fex-watchman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenderedtext%2Fex-watchman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderedtext%2Fex-watchman/lists"}