Skip to content

Add support for MySQL/MariaDB #89

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 1 commit into from
Sep 11, 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
15 changes: 15 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
mariadb:
image: mariadb:11
ports: ["3306:3306"]
env:
MARIADB_ROOT_PASSWORD: root
options: >-
--health-cmd "healthcheck.sh --connect --innodb_initialized"
--health-interval 10s
--health-timeout 5s
--health-retries 5
name: Elixir v${{ matrix.elixir }}, Erlang v${{ matrix.erlang }}
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -83,3 +93,8 @@ jobs:
run: mix test
env:
DB: postgres

- name: Run Tests - MySQL/MariaDB
run: mix test
env:
DB: mysql
10 changes: 10 additions & 0 deletions config/dev.example.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ config :error_tracker, :ecto_adapter, :postgres
config :error_tracker, ErrorTrackerDev.Repo,
url: "ecto://postgres:[email protected]/error_tracker_dev"

# MySQL/MariaDB adapter
#
# To use MySQL/MariaDB on your local development machine uncomment these lines and
# comment the lines of other adapters.

# config :error_tracker, :ecto_adapter, :mysql

# config :error_tracker, ErrorTrackerDev.Repo,
# url: "ecto://root:[email protected]/error_tracker_dev"

# SQLite3 adapter
#
# To use SQLite3 on your local development machine uncomment these lines and
Expand Down
7 changes: 7 additions & 0 deletions config/test.example.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ config :error_tracker, ErrorTracker.Test.Repo,
pool: Ecto.Adapters.SQL.Sandbox,
log: false

config :error_tracker, ErrorTracker.Test.MySQLRepo,
url: "ecto://root:[email protected]/error_tracker_test",
pool: Ecto.Adapters.SQL.Sandbox,
log: false,
# Use the same migrations as the PostgreSQL repo
priv: "priv/repo"

config :error_tracker, ErrorTracker.Test.LiteRepo,
database: "priv/lite_repo/test.db",
pool: Ecto.Adapters.SQL.Sandbox,
Expand Down
1 change: 1 addition & 0 deletions dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Config.Reader.read!("config/config.exs", env: :dev)
adapter =
case Application.get_env(:error_tracker, :ecto_adapter) do
:postgres -> Ecto.Adapters.Postgres
:mysql -> Ecto.Adapters.MyXQL
:sqlite3 -> Ecto.Adapters.SQLite3
end

Expand Down
2 changes: 1 addition & 1 deletion guides/Getting Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This guide is an introduction to ErrorTracker, an Elixir-based built-in error tr

In this guide we will learn how to install ErrorTracker in an Elixir project so you can start reporting errors as soon as possible. We will also cover more advanced topics such as how to report custom errors and how to add extra context to reported errors.

**This guide requires you to have set up Ecto with PostgreSQL or SQLite3 beforehand.**
**This guide requires you to have set up Ecto with PostgreSQL, MySQL/MariaDB or SQLite3 beforehand.**

## Installing ErrorTracker as a dependency

Expand Down
18 changes: 13 additions & 5 deletions lib/error_tracker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule ErrorTracker do
## Requirements

ErrorTracker requires Elixir 1.15+, Ecto 3.11+, Phoenix LiveView 0.19+, and
PostgreSQL or SQLite3 as database.
PostgreSQL, MySQL/MariaDB or SQLite3 as database.

## Integrations

Expand Down Expand Up @@ -221,10 +221,18 @@ defmodule ErrorTracker do
{:ok, {error, occurrence}} =
Repo.transaction(fn ->
error =
Repo.insert!(error,
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]],
conflict_target: :fingerprint
)
ErrorTracker.Repo.with_adapter(fn
:mysql ->
Repo.insert!(error,
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]]
)

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

occurrence =
error
Expand Down
1 change: 1 addition & 0 deletions lib/error_tracker/migration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ defmodule ErrorTracker.Migration do
defp migrator do
ErrorTracker.Repo.with_adapter(fn
:postgres -> ErrorTracker.Migration.Postgres
:mysql -> ErrorTracker.Migration.MySQL
:sqlite -> ErrorTracker.Migration.SQLite
adapter -> raise "ErrorTracker does not support #{adapter}"
end)
Expand Down
33 changes: 33 additions & 0 deletions lib/error_tracker/migration/mysql.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule ErrorTracker.Migration.MySQL do
@moduledoc false

@behaviour ErrorTracker.Migration

use Ecto.Migration
alias ErrorTracker.Migration.SQLMigrator

@initial_version 3
@current_version 3

@impl ErrorTracker.Migration
def up(opts) do
opts = with_defaults(opts, @current_version)
SQLMigrator.migrate_up(__MODULE__, opts, @initial_version)
end

@impl ErrorTracker.Migration
def down(opts) do
opts = with_defaults(opts, @initial_version)
SQLMigrator.migrate_down(__MODULE__, opts, @initial_version)
end

@impl ErrorTracker.Migration
def current_version(opts) do
opts = with_defaults(opts, @initial_version)
SQLMigrator.current_version(opts)
end

defp with_defaults(opts, version) do
Enum.into(opts, %{version: version})
end
end
47 changes: 47 additions & 0 deletions lib/error_tracker/migration/mysql/v03.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
defmodule ErrorTracker.Migration.MySQL.V03 do
@moduledoc false

use Ecto.Migration

def up(_opts) do
create table(:error_tracker_meta, primary_key: [name: :key, type: :string]) do
add :value, :string, null: false
end

create table(:error_tracker_errors, primary_key: [name: :id, type: :bigserial]) do
add :kind, :string, null: false
add :reason, :text, null: false
add :source_line, :text, null: false
add :source_function, :text, null: false
add :status, :string, null: false
add :fingerprint, :string, null: false
add :last_occurrence_at, :utc_datetime_usec, null: false

timestamps(type: :utc_datetime_usec)
end

create unique_index(:error_tracker_errors, [:fingerprint])

create table(:error_tracker_occurrences, primary_key: [name: :id, type: :bigserial]) do
add :context, :map, null: false
add :reason, :text, null: false
add :stacktrace, :map, null: false

add :error_id,
references(:error_tracker_errors, on_delete: :delete_all, column: :id, type: :bigserial),
null: false

timestamps(type: :utc_datetime_usec, updated_at: false)
end

create index(:error_tracker_occurrences, [:error_id])

create index(:error_tracker_errors, [:last_occurrence_at])
end

def down(_opts) do
drop table(:error_tracker_occurrences)
drop table(:error_tracker_errors)
drop table(:error_tracker_meta)
end
end
7 changes: 7 additions & 0 deletions lib/error_tracker/migration/sql_migrator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ defmodule ErrorTracker.Migration.SQLMigrator do
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
"""

:mysql ->
execute """
INSERT INTO error_tracker_meta (`key`, value)
VALUES ('migration_version', '#{version}'), ('migration_timestamp', '#{timestamp}')
ON DUPLICATE KEY UPDATE value = VALUES(value)
"""

_other ->
execute """
INSERT INTO error_tracker_meta (key, value)
Expand Down
1 change: 1 addition & 0 deletions lib/error_tracker/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ defmodule ErrorTracker.Repo do
adapter =
case repo().__adapter__() do
Ecto.Adapters.Postgres -> :postgres
Ecto.Adapters.MyXQL -> :mysql
Ecto.Adapters.SQLite3 -> :sqlite
end

Expand Down
1 change: 1 addition & 0 deletions lib/error_tracker/schemas/occurrence.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ defmodule ErrorTracker.Occurrence do
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)
end)

Expand Down
5 changes: 3 additions & 2 deletions lib/error_tracker/web/live/dashboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do

defp paginate_errors(socket) do
%{page: page, search: search} = socket.assigns

offset = (page - 1) * @per_page
query = filter(Error, search)

total_errors = Repo.aggregate(query, :count)
Expand All @@ -68,7 +68,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do
Repo.all(
from query,
order_by: [desc: :last_occurrence_at],
offset: (^page - 1) * @per_page,
offset: ^offset,
limit: @per_page
)

Expand Down Expand Up @@ -115,6 +115,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do
# strings. SQLite3 only supports LIKE, which is case-insensitive for ASCII characters.
Repo.with_adapter(fn
:postgres -> where(query, [error], ilike(field(error, ^field), ^"%#{value}%"))
:mysql -> where(query, [error], like(field(error, ^field), ^"%#{value}%"))
:sqlite -> where(query, [error], like(field(error, ^field), ^"%#{value}%"))
end)
end
Expand Down
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ defmodule ErrorTracker.MixProject do
{:phoenix_ecto, "~> 4.6"},
{:plug, "~> 1.10"},
{:postgrex, ">= 0.0.0", optional: true},
{:myxql, ">= 0.0.0", optional: true},
{:ecto_sqlite3, ">= 0.0.0", optional: true},
# Dev dependencies
{:bun, "~> 1.3", only: :dev},
Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"myxql": {:hex, :myxql, "0.6.4", "1502ea37ee23c31b79725b95d4cc3553693c2bda7421b1febc50722fd988c918", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a3307f4671f3009d3708283649adf205bfe280f7e036fc8ef7f16dbf821ab8e9"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
Expand Down
4 changes: 4 additions & 0 deletions test/support/mysql_repo.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule ErrorTracker.Test.MySQLRepo do
@moduledoc false
use Ecto.Repo, otp_app: :error_tracker, adapter: Ecto.Adapters.MyXQL
end
14 changes: 11 additions & 3 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Use the appropriate repo for the desired database
repo =
case System.get_env("DB") do
"sqlite" -> ErrorTracker.Test.LiteRepo
"postgres" -> ErrorTracker.Test.Repo
_other -> raise "Please run either `DB=sqlite mix test` or `DB=postgres mix test`"
"sqlite" ->
ErrorTracker.Test.LiteRepo

"mysql" ->
ErrorTracker.Test.MySQLRepo

"postgres" ->
ErrorTracker.Test.Repo

_other ->
raise "Please run either `DB=sqlite mix test`, `DB=postgres mix test` or `DB=mysql mix test`"
end

Application.put_env(:error_tracker, :repo, repo)
Expand Down
Loading