-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathoccurrence.ex
More file actions
85 lines (68 loc) · 2.28 KB
/
occurrence.ex
File metadata and controls
85 lines (68 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
defmodule ErrorTracker.Occurrence do
@moduledoc """
Schema to store a particular instance of an error in a given time.
It contains all the metadata available about the moment and the environment
in which the exception raised.
"""
import Ecto.Changeset
use Ecto.Schema
require Logger
@type t :: %__MODULE__{}
schema "error_tracker_occurrences" do
field :reason, :string
field :context, :map
field :breadcrumbs, {:array, :string}
embeds_one :stacktrace, ErrorTracker.Stacktrace
belongs_to :error, ErrorTracker.Error
timestamps(type: :utc_datetime_usec, updated_at: false)
end
@doc false
def changeset(occurrence, attrs) do
occurrence
|> cast(attrs, [:context, :reason, :breadcrumbs])
|> maybe_put_stacktrace()
|> validate_required([:reason, :stacktrace])
|> validate_context()
|> foreign_key_constraint(:error)
end
# This function validates if the context can be serialized to JSON before
# storing it to the DB.
#
# If it cannot be serialized a warning log message is emitted and an error
# is stored in the context.
#
defp validate_context(changeset) do
if changeset.valid? do
context = get_field(changeset, :context, %{})
db_json_encoder =
ErrorTracker.Repo.with_adapter(fn
:postgres -> Application.get_env(:postgrex, :json_library)
:mysql -> Application.get_env(:myxql, :json_library)
:sqlite -> Application.get_env(:ecto_sqlite3, :json_library)
end)
validated_context =
try do
json_encoder = db_json_encoder || ErrorTracker.__default_json_encoder__()
_iodata = json_encoder.encode_to_iodata!(context)
context
rescue
_e ->
Logger.warning(
"[ErrorTracker] Context has been ignored: it is not serializable to JSON."
)
%{
error:
"Context not stored because it contains information not serializable to JSON."
}
end
put_change(changeset, :context, validated_context)
else
changeset
end
end
defp maybe_put_stacktrace(changeset) do
if stacktrace = Map.get(changeset.params, "stacktrace"),
do: put_embed(changeset, :stacktrace, stacktrace),
else: changeset
end
end