What is the use case for manual error reporting in logging libraries?

Virtually every logging library has a function for manual error reporting:

These functions are often the first to be implemented and date back to the very beginning of the project git history. The intended use case, according to docs I found, is to report handled errors (example 1, example 2)

But every time I see this I’m confused. Why would I want to report an error directly to e.g. Sentry and bypass the logging stack? If I handle an exception and still want to report it, I’m gonna reach for good old Logger.error and let Sentry pick it through the logger handler.

Have you ever seen a legitimate use case for this family of functions? Or perhaps this is the result of some limitation in legacy logging system which made it’s way to all libraries through cross-inspiration?

A database error of the sort “Could not update this record because it now breaks this unique index” is not very useful in isolation. I have used these functions to provide the error’s / exception’s message + extra context i.e. “While trying to connect this paid order to this organization” (bad example, don’t pick on it).

1 Like

Fair, but that’s also true for Logger.error? You can attach anything to a log message through metadata and it should be correctly picked up by the library handler?

Many of those APIs were not designed for Elixir, and simply mimic whatever was done in a different ecosystem.

An explicit way to report errors is the “minimal common denominator” for such services.

Then, depending on the ecosystem, functionality gets added on top to leverage the possible ways to do “automatic instrumentation”.

For Elixir, logging is one way. For Python, JS and some other languages there are some global error handlers. For Go things are mostly explicit and manual, etc etc.

2 Likes

Sometimes I want to see something in Sentry that isn’t an error. Telemetry could be used for this but it’s very easy to push a message to Sentry.

1 Like

Sometimes the error boundary set up by the tools (for instance: catching exceptions by wrapping controller actions, job perform functions etc) doesn’t meet the code’s needs. It can be useful to capture the failure at the correct boundary and send it to the service before the code takes corrective action (retrying, etc)

One benefit of doing so is that it sends the error through the same tagging / metadata-scrubbing / etc that’s already configured by the library user for “regular” errors, versus bare Logger calls.

1 Like

In embedded contexts logging (to disk) and sending data off via the network come with quite different tradeoffs so they‘re not really equal. Yes you could likely still make both work through just the logging interface, but it would be less explicit, more work and harder to understand.

1 Like

I am the co-maintainer of the ErrorTracker package and can confirm that this is the main reason for manual error tracking.

For example we call an external API service that is sometimes down. The job handles this situation gracefully and provides feedback to the user, so there is no raised error that the library can pick up. When the error happens we report it manually and then continue handling it.

Using Logger is a fine option, but the error tracking packages provide some additional functions such as:

  • Assigning particular errors to users so they can investigate them
  • Attaching comments that provide further clarification
  • Adding additional context (this is also supported by the standard Logger)
  • Marking errors as resolved, or unresolved, etc.
  • Configure notification settings for particular errors

Thanks for the info! I took a deeper look at ErrorTracker source code and it looks like it doesn’t have a logger handler at all? If that’s the case than yeah, it’s totally understandable why manual handling is needed. Logger.error will simply not go through ErrorTracker pipeline.

That’s right!ErrorTracker does not have logger handler at the moment. This is something that we are looking into.

Could you tell me what library you’re using and an example of a tag you have in mind? I’m curious to check if it’s an inherent gap in UX, or perhaps just the way a certain library context is designed.