{"id":15667627,"url":"https://github.com/mimiquate/tower","last_synced_at":"2025-05-16T02:07:22.419Z","repository":{"id":243278949,"uuid":"810315298","full_name":"mimiquate/tower","owner":"mimiquate","description":"🏰 Vendor-Agnostic Error Tracking and Reporting in Elixir","archived":false,"fork":false,"pushed_at":"2025-04-16T15:33:30.000Z","size":382,"stargazers_count":159,"open_issues_count":3,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-10T12:40:07.240Z","etag":null,"topics":["elixir","error-handling","error-monitoring","error-reporting","error-tracking","tower"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/tower","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mimiquate.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-06-04T13:05:16.000Z","updated_at":"2025-05-09T14:02:16.000Z","dependencies_parsed_at":"2024-08-19T19:05:36.990Z","dependency_job_id":"f0ad094e-9e4e-4623-ae2e-608db3948ca3","html_url":"https://github.com/mimiquate/tower","commit_stats":{"total_commits":144,"total_committers":4,"mean_commits":36.0,"dds":0.08333333333333337,"last_synced_commit":"9b74abf43eaa5f123fcac83952935a69ad714dbd"},"previous_names":["mimiquate/tower"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mimiquate%2Ftower","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mimiquate%2Ftower/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mimiquate%2Ftower/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mimiquate%2Ftower/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mimiquate","download_url":"https://codeload.github.com/mimiquate/tower/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254453652,"owners_count":22073617,"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":["elixir","error-handling","error-monitoring","error-reporting","error-tracking","tower"],"created_at":"2024-10-03T14:04:33.875Z","updated_at":"2025-05-16T02:07:22.408Z","avatar_url":"https://github.com/mimiquate.png","language":"Elixir","readme":"# 🏰 Tower\n\n[![ci](https://github.com/mimiquate/tower/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mimiquate/tower/actions?query=branch%3Amain)\n[![Hex.pm](https://img.shields.io/hexpm/v/tower.svg)](https://hex.pm/packages/tower)\n[![Documentation](https://img.shields.io/badge/Documentation-purple.svg)](https://hexdocs.pm/tower)\n\nTower is a flexible exception tracker for elixir applications.\n\nIt **listens** for **exceptions** in an elixir application **and informs** about them to\nthe configured list of **reporters** (one or many).\n\nAny captured exception by `Tower` will be passed along to the list of\nconfigured reporters, which can be set using the `:reporters` config key. For example:\n\n```elixir\nconfig :tower, :reporters, [TowerEmail]\n```\n\nYou can pick any of the following reporters or [build your own](https://hexdocs.pm/tower/Tower.html#module-writing-a-custom-reporter).\n\n\nReport to | Tower reporter | Package dependency\n:-----| :---------------| :---------\nIn memory | `Tower.EphemeralReporter` | Built-In\nTransactional E-mail | `TowerEmail` | [tower_email]\n[Slack.com](https://slack.com) [Webhook](https://api.slack.com/messaging/webhooks) | `TowerSlack` | [tower_slack]\nSelf-hosted [ErrorTracker](https://github.com/elixir-error-tracker/error-tracker) | `TowerErrorTracker` | [tower_error_tracker]\n[BugSnag.com](https://bugsnag.com) | `TowerBugsnag` | [tower_bugsnag]\n[Honeybadger.io](https://honeybadger.io) | `TowerHoneybadger` | [tower_honeybadger]\n[Rollbar.com](https://rollbar.com) | `TowerRollbar` | [tower_rollbar]\n[Sentry.io](https://sentry.io) | `TowerSentry` | [tower_sentry]\n\n[tower_bugsnag]: https://github.com/mimiquate/tower_bugsnag\n[tower_email]: https://github.com/mimiquate/tower_email\n[tower_error_tracker]: https://github.com/mimiquate/tower_error_tracker\n[tower_honeybadger]: https://github.com/mimiquate/tower_honeybadger\n[tower_rollbar]: https://github.com/mimiquate/tower_rollbar\n[tower_sentry]: https://github.com/mimiquate/tower_sentry\n[tower_slack]: https://github.com/mimiquate/tower_slack\n\nCommunity supported:\n\n- [`ivanhercaz/tower_telegram`](https://github.com/ivanhercaz/tower_telegram)\n- [`KristerV/tower_discord`](https://github.com/KristerV/tower_discord)\n\nFollow each reporter's README to get `Tower` installed and configured properly.\n\n## Motivation\n\n\u003e Decoupled error capturing and error reporting in Elixir.\n\nSay you need to add error tracking to your elixir app:\n\n  - You decide what service you will use to send your errors to\n  - You look for a good elixir library for that service\n  - You configure it, deploy and start receiving errors there\n\nNormally these libraries have to take care of a few responsibilities:\n\n1. Capturing of errors (specific to language and runtime, i.e. Elixir and BEAM)\n    - Automatic capturing via (at least one of):\n        - Logger backend\n        - Logger handler\n        - Error logger handler\n        - Telemetry event handler\n        - Plugs\n    - Manual capturing by providing a few public API functions the programmer to call if needed\n1. Transform these errors into some format for the remote service (specific to remote service), e.g.\n    - JSON for an HTTP API request\n    - Subject and body for an e-mail message\n1. Make a remote call (e.g. an HTTP request with the payload) to the remote service (specific to remote service)\n\n```mermaid\nflowchart LR\n  A(Elixir App) --\u003e B(Capture)\n  subgraph Service Library\n  B --\u003e C(\"Format\")\n  C --\u003e D(\"Report\")\n  end\n  D --\u003e E(\"ErrorTrackingService\")\n```\n\n`Tower`, instead, takes care of capturing errors (number 1), giving them a well defined shape (`Tower.Event` struct)\nand pass along this event to pre-configured but separate reporters which take care of the error reporting steps\n(number 2 and 3) depending on which service or remote system they report to.\n\n```mermaid\nflowchart LR\n  A(Elixir App) --\u003e B(Capture)\n  subgraph Tower\n  B --\u003e C(\"Build\u003cbr /\u003eTower.Event\")\n  end\n  subgraph A Tower.Reporter\n  C --\u003e D(\"Format\")\n  D --\u003e E(\"Report\")\n  end\n  E --\u003e F(\"ErrorTrackingService\")\n```\n\n### Consequences of this approach\n\n#### 1. Capture once, report many\n\nYou can capture once and report to as many places as you want.\n\nPossibly most will end up with just one reporter. But that doesn't mean you shouldn't be able to\neasily have many, either temporarily or permanently if you need it.\n\nMaybe you just need to have a backup in case one service goes downs or something unexpected happens.\n\nMaybe you're trying out different providers and you want to report to the two for a while and compare\nhow they work, what features they have and how they display the information for you.\n\nMaybe you're planning to switch, and you want to configure the new one without stopping to report to the\nold one, at least for a while.\n\n```mermaid\nflowchart LR\n  A(Elixir App) --\u003e B(Capture)\n  subgraph Tower\n  B --\u003e C(\"Build\u003cbr /\u003eTower.Event\")\n  end\n  subgraph Tower.Reporter 1\n  C --\u003e D(\"Format\")\n  D --\u003e E(\"Report\")\n  end\n  subgraph Tower.Reporter 2\n  C --\u003e F(\"Format\")\n  F --\u003e G(\"Report\")\n  end\n  E --\u003e H(\"ErrorTrackingService 1\")\n  G --\u003e I(\"ErrorTrackingService 2\")\n```\n\n#### 2. Ease of switching services\n\nYou can switch from Error Tracking service provider without making any changes to your application error\ncapturing configuration or expect any change or regression with respect with capturing behavior.\n\nYou switch the reporter package, but tower still part of your application, and all the configuration specific\nto tower and error capturing tactics is still valid and unchanged.\n\n#### 3. Response to changes in Elixir and BEAM\n\nNecessary future changes caused by deprecations and/or changes in error handling behavior in the BEAM or Elixir can be just\nmade in `Tower` without need to change any of the service specific reporters.\n\n## Configuration\n\n### `reporters`\n\nList of reporters Tower should report events to.\n\nDefault: `[Tower.EphemeralReporter]`\n\nExample:\n\n```elixir\nconfig :tower, reporters: [TowerEmail]\n```\n\n### `log_level`\n\n`Logger` messages this level and above will be reported.\n\nPossible values are any of defined `Logger` levels (https://hexdocs.pm/logger/Logger.html#module-levels) or\n`:none` to disable reporting of `Logger` messages.\n\nDefault: `:critical`\n\nExample:\n\n```elixir\nconfig :tower, log_level: :error\n```\n\n### `ignored_exceptions`\n\nList of exceptions that Tower should ignore and not report.\n\nDefault: `[]`\n\nExample:\n\n```elixir\nconfig :tower, ignored_exceptions: [DBConnection.ConnectionError]\n```\n\n### `logger_metadata`\n\nList of keys that Tower should pick up from the current process `Logger.metadata` when reporting events.\n\nDefault: `[]`\n\nExample:\n\nA common use case is setting `Logger.metadata(user_id: user.id)` at the start of your plugs or controller actions and\nconfigure Tower:\n\n```elixir\nconfig :tower, logger_metadata: [:user_id]\n```\n\nso that it's included in the reported exception or message event as extra metadata.\n\nAlso if using Phoenix you can\n\n```elixir\nconfig :tower, logger_metadata: [:request_id]\n```\n\nso that you can co-relate your exceptions reports to the request id in your application logs.\n\nMore about Logger metadata:\n - https://hexdocs.pm/logger/Logger.html#module-metadata\n - https://hexdocs.pm/logger/Logger.html#metadata/1\n\n## License\n\nCopyright 2024 Mimiquate\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmimiquate%2Ftower","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmimiquate%2Ftower","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmimiquate%2Ftower/lists"}