Compare commits

...

2 Commits

Author SHA1 Message Date
shibao 42e2d1c76e fix tests
continuous-integration/drone/push Build is passing Details
2023-02-05 00:51:51 -05:00
shibao 064d2d3988 improve oban logging 2023-02-05 00:51:51 -05:00
10 changed files with 117 additions and 13 deletions

View File

@ -3,6 +3,7 @@
- Improve templates - Improve templates
- Improve invites, record usage - Improve invites, record usage
- Fix padding on more pages when using chrome - Fix padding on more pages when using chrome
- Add oban metrics to server log and live dashboard
# v0.8.1 # v0.8.1
- Update dependencies - Update dependencies

View File

@ -64,8 +64,9 @@ config :cannery, CanneryWeb.Endpoint,
] ]
] ]
# Do not include metadata nor timestamps in development logs config :logger, :console,
config :logger, :console, format: "[$level] $message\n" format: "[$level] $message $metadata\n\n",
metadata: [:data]
# Set a higher stacktrace during development. Avoid configuring such # Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive. # in production as building large stacktraces may be expensive.

View File

@ -44,8 +44,6 @@ config :cannery, Cannery.Repo,
pool_size: String.to_integer(System.get_env("POOL_SIZE", "10")), pool_size: String.to_integer(System.get_env("POOL_SIZE", "10")),
socket_options: maybe_ipv6 socket_options: maybe_ipv6
config :cannery, Cannery.Accounts, registration: System.get_env("REGISTRATION", "invite")
config :cannery, CanneryWeb.Endpoint, config :cannery, CanneryWeb.Endpoint,
url: [scheme: "https", host: host, port: 443], url: [scheme: "https", host: host, port: 443],
http: [ http: [
@ -56,6 +54,10 @@ config :cannery, CanneryWeb.Endpoint,
], ],
server: true server: true
if config_env() in [:dev, :prod] do
config :cannery, Cannery.Accounts, registration: System.get_env("REGISTRATION", "invite")
end
if config_env() == :prod do if config_env() == :prod do
# The secret key base is used to sign/encrypt cookies and other secrets. # The secret key base is used to sign/encrypt cookies and other secrets.
# A default value is used in config/dev.exs and config/test.exs but you # A default value is used in config/dev.exs and config/test.exs but you

View File

@ -22,6 +22,9 @@ config :cannery, CanneryWeb.Endpoint,
# In test we don't send emails. # In test we don't send emails.
config :cannery, Cannery.Mailer, adapter: Swoosh.Adapters.Test config :cannery, Cannery.Mailer, adapter: Swoosh.Adapters.Test
# Don't require invites for signups
config :cannery, Cannery.Accounts, registration: "public"
# Print only warnings and errors during test # Print only warnings and errors during test
config :logger, level: :warn config :logger, level: :warn

View File

@ -117,6 +117,8 @@ defmodule Cannery.Accounts do
:passed :passed
""" """
@spec register_user(attrs :: map()) ::
{:ok, User.t()} | {:error, :invalid_token | User.changeset()}
@spec register_user(attrs :: map(), Invite.token() | nil) :: @spec register_user(attrs :: map(), Invite.token() | nil) ::
{:ok, User.t()} | {:error, :invalid_token | User.changeset()} {:ok, User.t()} | {:error, :invalid_token | User.changeset()}
def register_user(attrs, invite_token \\ nil) do def register_user(attrs, invite_token \\ nil) do

View File

@ -85,7 +85,9 @@ defmodule Cannery.Accounts.Invites do
end end
end end
@spec get_invite_by_token(Invite.token()) :: {:ok, Invite.t()} | {:error, :invalid_token} @spec get_invite_by_token(Invite.token() | nil) :: {:ok, Invite.t()} | {:error, :invalid_token}
defp get_invite_by_token(token) when token in [nil, ""], do: {:error, :invalid_token}
defp get_invite_by_token(token) do defp get_invite_by_token(token) do
Repo.one( Repo.one(
from i in Invite, from i in Invite,

View File

@ -4,6 +4,7 @@ defmodule Cannery.Application do
@moduledoc false @moduledoc false
use Application use Application
alias Cannery.ErrorReporter
@impl true @impl true
def start(_type, _args) do def start(_type, _args) do
@ -17,16 +18,24 @@ defmodule Cannery.Application do
# Start the Endpoint (http/https) # Start the Endpoint (http/https)
CanneryWeb.Endpoint, CanneryWeb.Endpoint,
# Add Oban # Add Oban
{Oban, oban_config()} {Oban, oban_config()},
Cannery.Repo.Migrator
# Start a worker by calling: Cannery.Worker.start_link(arg) # Start a worker by calling: Cannery.Worker.start_link(arg)
# {Cannery.Worker, arg} # {Cannery.Worker, arg}
] ]
# Automatically migrate on start in prod # Oban events logging https://hexdocs.pm/oban/Oban.html#module-reporting-errors
children = :ok =
if Application.get_env(:cannery, Cannery.Application, automigrate: false)[:automigrate], :telemetry.attach_many(
do: children ++ [Cannery.Repo.Migrator], "oban-logger",
else: children [
[:oban, :job, :exception],
[:oban, :job, :start],
[:oban, :job, :stop]
],
&ErrorReporter.handle_event/4,
[]
)
# See https://hexdocs.pm/elixir/Supervisor.html # See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options # for other strategies and supported options

View File

@ -0,0 +1,57 @@
defmodule Cannery.ErrorReporter do
@moduledoc """
Custom logger for telemetry events
Oban implementation taken from
https://hexdocs.pm/oban/Oban.html#module-reporting-errors
"""
require Logger
def handle_event([:oban, :job, :exception], measure, %{stacktrace: stacktrace} = meta, _config) do
data =
get_oban_job_data(meta, measure)
|> Map.put(:stacktrace, Exception.format_stacktrace(stacktrace))
Logger.error(meta.reason, data: pretty_encode(data))
end
def handle_event([:oban, :job, :start], measure, meta, _config) do
Logger.info("Started oban job", data: get_oban_job_data(meta, measure) |> pretty_encode())
end
def handle_event([:oban, :job, :stop], measure, meta, _config) do
Logger.info("Finished oban job", data: get_oban_job_data(meta, measure) |> pretty_encode())
end
def handle_event([:oban, :job, unhandled_event], measure, meta, _config) do
data =
get_oban_job_data(meta, measure)
|> Map.put(:event, unhandled_event)
Logger.warning("Unhandled oban job event", data: pretty_encode(data))
end
def handle_event(unhandled_event, measure, meta, config) do
data = %{
event: unhandled_event,
meta: meta,
measurements: measure,
config: config
}
Logger.warning("Unhandled telemetry event", data: pretty_encode(data))
end
defp get_oban_job_data(%{job: job}, measure) do
job
|> Map.take([:id, :args, :meta, :queue, :worker])
|> Map.merge(measure)
end
defp pretty_encode(data) do
data
|> Jason.encode!()
|> Jason.Formatter.pretty_print()
end
end

View File

@ -11,12 +11,15 @@ defmodule Cannery.Repo.Migrator do
end end
def init(_opts) do def init(_opts) do
migrate!() {:ok, if(automigrate_enabled?(), do: migrate!())}
{:ok, nil}
end end
def migrate! do def migrate! do
path = Application.app_dir(:cannery, "priv/repo/migrations") path = Application.app_dir(:cannery, "priv/repo/migrations")
Ecto.Migrator.run(Cannery.Repo, path, :up, all: true) Ecto.Migrator.run(Cannery.Repo, path, :up, all: true)
end end
defp automigrate_enabled? do
Application.get_env(:cannery, Cannery.Application, automigrate: false)[:automigrate]
end
end end

View File

@ -57,6 +57,30 @@ defmodule CanneryWeb.Telemetry do
"The time the connection spent waiting before being checked out for the query" "The time the connection spent waiting before being checked out for the query"
), ),
# Oban Metrics
counter("oban.job.exception",
tags: [:queue, :worker],
event_name: [:oban, :job, :exception],
measurement: :duration,
description: "Number of oban jobs that raised an exception"
),
counter("oban.job.start",
tags: [:queue, :worker],
event_name: [:oban, :job, :start],
measurement: :system_time,
description: "Number of oban jobs started"
),
summary("oban.job.stop.duration",
tags: [:queue, :worker],
unit: {:native, :millisecond},
description: "Length of time spent processing the oban job"
),
summary("oban.job.stop.queue_time",
tags: [:queue, :worker],
unit: {:native, :millisecond},
description: "Time the oban job spent waiting in milliseconds"
),
# VM Metrics # VM Metrics
summary("vm.memory.total", unit: {:byte, :kilobyte}), summary("vm.memory.total", unit: {:byte, :kilobyte}),
summary("vm.total_run_queue_lengths.total"), summary("vm.total_run_queue_lengths.total"),