grzuy

grzuy

Tower - Agnostic Error Tracking in Elixir

:castle: Tower is an Elixir library that provides a standard interface for Exception Tracking and Reporting, agnostic/neutral to which services or destinations you prefer to report to.

  • Automatically listens for and reports un-handled exceptions occurring in any process.
  • Provides small set of public functions for you to manually report any handled exception (Tower.report_exception and Tower.report_message, among a few more)
  • Reports to one or many of your preferred services or destinations (separate package reporters/adapters) you configured with config :tower, reporters: [...].

Reporters/adapters currently supported:

Why?

  • De-coupling of error capturing from error reporting.
  • Be able to easily report to more than one place, either temporarily in case of transitioning from services, or for back-up reasons.
  • Easier to switch or try out new services or destinations
  • Having capturing logic implemented once may make it easier to respond to future changes in BEAM and Elixir, that benefit multiple reporter packages.

More at mimiquate/tower#Motivation.

Example Scenarios

Scenario #1

You want to report to Sentry.

  • You include tower_sentry .
  • Set a few Sentry-specific config setting.
  • Set config :tower, reporters: [TowerSentry]

Automatic reporting of exceptions will “just work”.

Manually report by calling Tower.report_exception anywhere you like in your application code, like so:

  try do
    # possibly raising code
  rescue
    exception ->
      Tower.report_exception(exception, __STACKTRACE__)
  end

Scenario #2

You need/want to switch service from Sentry to Honeybadger.

  • Replace tower_sentry with tower_honeybadger in your dependencies.
  • Replace config :tower, reporters: [TowerSentry] with config :tower, reporters: [TowerHoneybadger]
  • Remove Sentry-specific configs.
  • Add Honeybadger-specific config, like setting API Key.
  • Automatic reporting of exceptions continue to “just work” without any changes.
  • Manual report calls to Tower.report_exception throughout your application code unchanged.

Scenario #3

You are reporting to Sentry and you want to test ErrorTracker while continuing to report to Sentry.

  • Add tower_error_tracker.
  • Follow a few ErrorTracker specific configs.
  • Update config :tower, reporters: [TowerSentry] to config :tower, reporters: [TowerSentry, TowerErrorTracker] .
  • Automatic reporting of exceptions continue to “just work” without any changes.
  • Manual report calls to Tower.report_exception throughout your application code unchanged.
  • Now you will have exceptions reported to both Sentry and ErrorTracker.

The Ephemeral Reporter

You can include the built-in Tower.EphemeralReporter in the reporters: config list. It will keep the last 50 heard exceptions stored in naive Agent state. Useful for testing, development, and occasional production debugging.

iex(1)> Tower.EphemeralReporter.events()
[]
iex(2)> Task.start(fn -> raise "exception within an async task" end)
{:ok, #PID<0.344.0>}

11:52:12.684 [error] Task #PID<0.344.0> started from #PID<0.343.0> terminating
** (RuntimeError) exception within an async task
    (elixir 1.17.3) src/elixir.erl:386: :elixir.eval_external_handler/3
Function: #Function<43.39164016/0 in :erl_eval.expr/6>
    Args: []
iex(3)> Tower.EphemeralReporter.events()
[
  %Tower.Event{
    id: "019290aa-4c2a-7853-85f9-e9171e16ef04",
    similarity_id: 9949489,
    datetime: ~U[2024-10-15 14:52:12.684704Z],
    level: :error,
    kind: :error,
    reason: %RuntimeError{message: "exception within an async task"},
    ...
  }
]

Support for more services?

We may write reporters for new services.

But we strongly encourage others to help and write and publish new reporters/adapters as you see fit and value.

Links

What’s next?

We plan to continue polishing, maturing and improving it. But we also need the community :slightly_smiling_face:

Any feedback is in any form very much appreciated!
Please comment, use it, find and report bugs.
Ideas or feature requests are encouraged in the GitHub repo Discussions.

Thank you for taking the time to read!

https://github.com/mimiquate/tower

Most Liked

grzuy

grzuy

For what is worth, sharing a related recent blog post that goes into a little more detail Tower: Universal and Agnostic Elixir Exception Tracker.

KristerV

KristerV

i tried switching from ErrorTracker to Tower (plus tower_error_tracker) to collect Logger.error() logs. buuuut it seems that that’s not actually supported? I saw the LoggerHandler module and assumed that’s what it’s for.

i can get so far that exeptions are caught, but not Logger logs. what’s the procedure there?

edit: @JonRowe figured it out. the conf has to have this value:

config :tower, log_level: :error

otherwise the LoggerHandler gets attached, but all messages are filtered out. doesn’t look like there’s anything in the docs about this, will raise an issue.

grzuy

grzuy

Indeed, was not well documented.
Hopefully it is now: docs: clarifies configuration options by grzuy · Pull Request #128 · mimiquate/tower · GitHub.

Thank you.

Note that LoggerHandler does listen for BOTH “logger messages” and “unhandled exceptions/crashes”.

Unhandled exception/crashes should actually land in the LoggerHandler as just “logger messages” with the special metadata key “crash_reason” (see :crash_reason listed in Logger — Logger v1.20.2).

Where Next?

Popular in Announcing Top

josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
Qqwy
Today I realized that it would be possible to implement currying-capability in Elixir, using some clever anonymous function creation. (‘c...
New
woutdp
Hi! I wanted to introduce my latest project LiveSvelte. It allows you to render Svelte inside LiveView with end-to-end reactivity. It’s ...
New
ahamez
Hi everyone, I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
fuelen
Hey folks! Want to present a toolkit for writing command-line user interfaces. It provides a convenient interface for colorizing text...
New
michalmuskala
Hello everybody. I have just released Jason - a new JSON library. You might be wondering, why do we need a new library? The primary foc...
New
anshuman23
Hello all, I have been working on my proposed project called Tensorflex as part of Google Summer of Code 2018.. Tensorflex can be used f...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement