Skip to content
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
26 changes: 26 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,35 @@ let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("
let livePath = document.querySelector("meta[name='live-path']").getAttribute("content");
let liveTransport = document .querySelector("meta[name='live-transport']") .getAttribute("content");

const Hooks = {
JsonPrettyPrint: {
mounted() {
this.formatJson();
},
updated() {
this.formatJson();
},
formatJson() {
try {
// Get the raw JSON content
const rawJson = this.el.textContent.trim();
// Parse and stringify with indentation
const formattedJson = JSON.stringify(JSON.parse(rawJson), null, 2);
// Update the element content
this.el.textContent = formattedJson;
} catch (error) {
console.error("Error formatting JSON:", error);
// Keep the original content if there's an error
}
}
}
};

let liveSocket = new LiveView.LiveSocket(livePath, Phoenix.Socket, {
transport: liveTransport === "longpoll" ? Phoenix.LongPoll : WebSocket,
params: { _csrf_token: csrfToken },
hooks: Hooks

});

// Show progress bar on live navigation and form submits
Expand Down
31 changes: 25 additions & 6 deletions lib/error_tracker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,13 @@ defmodule ErrorTracker do

## 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...).
The content stored on the context should be serializable using the JSON library used by the
application (usually `JSON` for Elixir 1.18+ and `Jason` for older versions), so it is
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.
that they can be encoded to JSON or storing the errors will fail. You may need to define a
custom 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 @@ -384,4 +383,24 @@ defmodule ErrorTracker do
Telemetry.new_occurrence(occurrence, muted)
occurrence
end

@default_json_encoder (cond do
Code.ensure_loaded?(JSON) ->
JSON

Code.ensure_loaded?(Jason) ->
Jason

true ->
raise """
No JSON encoder found. Please add Jason to your dependencies:

{:jason, "~> 1.1"}

Or upgrade to Elixir 1.18+.
"""
end)

@doc false
def __default_json_encoder__, do: @default_json_encoder
end
40 changes: 23 additions & 17 deletions lib/error_tracker/schemas/occurrence.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,32 @@ defmodule ErrorTracker.Occurrence do
if changeset.valid? do
context = get_field(changeset, :context, %{})

json_encoder =
db_json_encoder =
ErrorTracker.Repo.with_adapter(fn
:postgres -> Application.get_env(:postgrex, :json_library, Jason)
:mysql -> Application.get_env(:myxql, :json_library, Jason)
:sqlite -> Application.get_env(:ecto_sqlite3, :json_library, Jason)
:postgres -> Application.get_env(:postgrex, :json_library)
:mysql -> Application.get_env(:myxql, :json_library)
:sqlite -> Application.get_env(:ecto_sqlite3, :json_library)
end)

case json_encoder.encode_to_iodata(context) do
{:ok, _} ->
put_change(changeset, :context, context)

{:error, _} ->
Logger.warning(
"[ErrorTracker] Context has been ignored: it is not serializable to JSON."
)

put_change(changeset, :context, %{
error: "Context not stored because it contains information not serializable to JSON."
})
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
Expand Down
8 changes: 7 additions & 1 deletion lib/error_tracker/web/live/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@
</.section>

<.section title="Context">
<pre class="overflow-auto text-sm p-4 rounded-lg bg-gray-300/10 border border-gray-900"><%= Jason.encode!(@occurrence.context, pretty: true) %></pre>
<pre
id="context"
class="overflow-auto text-sm p-4 rounded-lg bg-gray-300/10 border border-gray-900"
phx-hook="JsonPrettyPrint"
>
<%= ErrorTracker.__default_json_encoder__().encode_to_iodata!(@occurrence.context) %>
</pre>
</.section>
</div>

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ defmodule ErrorTracker.MixProject do
[
{:ecto_sql, "~> 3.13"},
{:ecto, "~> 3.13"},
{:jason, "~> 1.1"},
{:phoenix_live_view, "~> 1.0"},
{:phoenix_ecto, "~> 4.6"},
{:plug, "~> 1.10"},
{:jason, "~> 1.1", optional: true},
{:postgrex, ">= 0.0.0", optional: true},
{:myxql, ">= 0.0.0", optional: true},
{:ecto_sqlite3, ">= 0.0.0", optional: true},
Expand Down
2 changes: 1 addition & 1 deletion priv/static/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading