Compare commits
	
		
			2 Commits
		
	
	
		
			0.1.17
			...
			11a8214b94
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 11a8214b94 | |||
| 311579efd6 | 
| @@ -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.1.7 | # v0.1.7 | ||||||
| - Update dependencies | - Update dependencies | ||||||
|   | |||||||
| @@ -64,8 +64,9 @@ config :memex, MemexWeb.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. | ||||||
|   | |||||||
| @@ -42,8 +42,6 @@ config :memex, Memex.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 :memex, Memex.Accounts, registration: System.get_env("REGISTRATION", "invite") |  | ||||||
|  |  | ||||||
| config :memex, MemexWeb.Endpoint, | config :memex, MemexWeb.Endpoint, | ||||||
|   url: [scheme: "https", host: host, port: 443], |   url: [scheme: "https", host: host, port: 443], | ||||||
|   http: [ |   http: [ | ||||||
| @@ -54,6 +52,10 @@ config :memex, MemexWeb.Endpoint, | |||||||
|   ], |   ], | ||||||
|   server: true |   server: true | ||||||
|  |  | ||||||
|  | if config_env() in [:dev, :prod] do | ||||||
|  |   config :memex, Memex.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 | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ config :memex, MemexWeb.Endpoint, | |||||||
| # In test we don't send emails. | # In test we don't send emails. | ||||||
| config :memex, Memex.Mailer, adapter: Swoosh.Adapters.Test | config :memex, Memex.Mailer, adapter: Swoosh.Adapters.Test | ||||||
|  |  | ||||||
|  | # Don't require invites for signups | ||||||
|  | config :memex, Memex.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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -117,6 +117,8 @@ defmodule Memex.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 | ||||||
|   | |||||||
| @@ -85,7 +85,9 @@ defmodule Memex.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, | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ defmodule Memex.Application do | |||||||
|   @moduledoc false |   @moduledoc false | ||||||
|  |  | ||||||
|   use Application |   use Application | ||||||
|  |   alias Memex.ErrorReporter | ||||||
|  |  | ||||||
|   @impl true |   @impl true | ||||||
|   def start(_type, _args) do |   def start(_type, _args) do | ||||||
| @@ -17,16 +18,24 @@ defmodule Memex.Application do | |||||||
|       # Start the Endpoint (http/https) |       # Start the Endpoint (http/https) | ||||||
|       MemexWeb.Endpoint, |       MemexWeb.Endpoint, | ||||||
|       # Add Oban |       # Add Oban | ||||||
|       {Oban, oban_config()} |       {Oban, oban_config()}, | ||||||
|  |       Memex.Repo.Migrator | ||||||
|       # Start a worker by calling: Memex.Worker.start_link(arg) |       # Start a worker by calling: Memex.Worker.start_link(arg) | ||||||
|       # {Memex.Worker, arg} |       # {Memex.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(:memex, Memex.Application, automigrate: false)[:automigrate], |       :telemetry.attach_many( | ||||||
|         do: children ++ [Memex.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 | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								lib/memex/error_reporter.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/memex/error_reporter.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | defmodule Memex.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 | ||||||
| @@ -11,12 +11,15 @@ defmodule Memex.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(:memex, "priv/repo/migrations") |     path = Application.app_dir(:lokal, "priv/repo/migrations") | ||||||
|     Ecto.Migrator.run(Memex.Repo, path, :up, all: true) |     Ecto.Migrator.run(Lokal.Repo, path, :up, all: true) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   defp automigrate_enabled? do | ||||||
|  |     Application.get_env(:lokal, Lokal.Application, automigrate: false)[:automigrate] | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -57,6 +57,30 @@ defmodule MemexWeb.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"), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user