Skip to content

Do not store error if context/occurrence is not valid #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions guides/Getting Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ The `ErrorTracker.set_context/1` function stores the given context in the curren
ErrorTracker.set_context(%{user_id: conn.assigns.current_user.id})
```

There are some requirements on the type of data that can be included in the context, so we recommend taking a look at `set_context/1` documentation

## Manual error tracking

If you want to report custom errors that fall outside the default integration scope, you may use `ErrorTracker.report/2`. This allows you to report an exception yourself:
Expand Down
43 changes: 33 additions & 10 deletions lib/error_tracker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ defmodule ErrorTracker do
can gather, but aside from that, you can also add your own information. You can
do this in a per-process basis or in a per-call basis (or both).

There are some requirements on the type of data that can be included in the
context, so we recommend taking a look at `set_context/1` documentation.

**Per process**

This allows you to set a general context for the current process such as a Phoenix
Expand Down Expand Up @@ -152,6 +155,17 @@ defmodule ErrorTracker do

That means that any existing data on deep levels for he current context will
be replaced if the first level key is received on the new contents.

## Content serialization

The content stored on the context should be serializable using the JSON library
used by the application (usually `Jason`), so it is rather recommended to use
primitive types (strings, numbers, booleans...).

If you still need to pass more complex data types to your context, please test
that they can be encoded to JSON or storing the errors will fail. In the case
of `Jason` that may require defining an Encoder for that data type if not
included by default.
"""
@spec set_context(context()) :: context()
def set_context(params) when is_map(params) do
Expand Down Expand Up @@ -188,16 +202,25 @@ defmodule ErrorTracker do
existing_status =
Repo.one(from e in Error, where: [fingerprint: ^error.fingerprint], select: e.status)

error =
Repo.insert!(error,
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]],
conflict_target: :fingerprint
)

occurrence =
error
|> Ecto.build_assoc(:occurrences, stacktrace: stacktrace, context: context, reason: reason)
|> Repo.insert!()
{:ok, {error, occurrence}} =
Repo.transaction(fn ->
error =
Repo.insert!(error,
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]],
conflict_target: :fingerprint
)

occurrence =
error
|> Ecto.build_assoc(:occurrences,
stacktrace: stacktrace,
context: context,
reason: reason
)
|> Repo.insert!()

{error, occurrence}
end)

# If the error existed and was marked as resolved before this exception,
# sent a Telemetry event
Expand Down
4 changes: 4 additions & 0 deletions lib/error_tracker/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ defmodule ErrorTracker.Repo do
dispatch(:aggregate, [queryable, aggregate], opts)
end

def transaction(fun_or_multi, opts \\ []) do
dispatch(:transaction, [fun_or_multi], opts)
end

def with_adapter(fun) do
adapter =
case repo().__adapter__() do
Expand Down