From 6acb01d335a2a17cee6f09eee7f9e89cecb79014 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Mon, 9 Mar 2026 15:30:47 -0600 Subject: [PATCH] healthckeck improvements --- .gitea/workflows/pipeline.yml | 2 +- config/config.exs | 14 ++++---- lib/elixir_ai/application.ex | 36 +++++++++++++++++++ lib/elixir_ai_web/endpoint.ex | 1 - lib/elixir_ai_web/health_check_filter.ex | 15 -------- .../plugs/health_check_logger.ex | 19 ---------- mix.lock | 2 ++ 7 files changed, 45 insertions(+), 44 deletions(-) delete mode 100644 lib/elixir_ai_web/health_check_filter.ex delete mode 100644 lib/elixir_ai_web/plugs/health_check_logger.ex diff --git a/.gitea/workflows/pipeline.yml b/.gitea/workflows/pipeline.yml index 0fad642..2a8d44f 100644 --- a/.gitea/workflows/pipeline.yml +++ b/.gitea/workflows/pipeline.yml @@ -23,7 +23,7 @@ jobs: - name: Build and push backend image run: | - docker build -t alexmickelson/ai-liveview:$GITHUB_RUN_NUMBER . + docker build -q -t alexmickelson/ai-liveview:$GITHUB_RUN_NUMBER . docker push -q alexmickelson/ai-liveview:$GITHUB_RUN_NUMBER - name: Deploy to Kubernetes diff --git a/config/config.exs b/config/config.exs index 16138da..6faa410 100644 --- a/config/config.exs +++ b/config/config.exs @@ -20,7 +20,8 @@ config :elixir_ai, ElixirAiWeb.Endpoint, layout: false ], pubsub_server: ElixirAi.PubSub, - live_view: [signing_salt: "4UG1IVt+"] + live_view: [signing_salt: "4UG1IVt+"], + log: false # Configure esbuild (the version is required) config :esbuild, @@ -46,12 +47,7 @@ config :tailwind, # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", - metadata: [:request_id], - filters: [:health_check_filter] - -config :logger, :health_check_filter, - module: ElixirAiWeb.HealthCheckFilter, - function: :filter + metadata: [:request_id] # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason @@ -59,7 +55,9 @@ config :phoenix, :json_library, Jason # Lower the BEAM node-down detection window from the default 60s. # Nodes send ticks every (net_ticktime / 4)s; a node is declared down # after 4 missed ticks (net_ticktime total). 5s means detection in ≤5s. -config :kernel, net_ticktime: 2 +if System.get_env("RELEASE_MODE") do + config :kernel, net_ticktime: 2 +end # Libcluster — Gossip strategy works for local dev and Docker Compose # (UDP multicast, zero config). Overridden to Kubernetes.DNS in runtime.exs for prod. diff --git a/lib/elixir_ai/application.ex b/lib/elixir_ai/application.ex index dae08e4..de14ab3 100644 --- a/lib/elixir_ai/application.ex +++ b/lib/elixir_ai/application.ex @@ -4,6 +4,14 @@ defmodule ElixirAi.Application do @impl true def start(_type, _args) do + # Attach custom logger that filters health checks + :telemetry.attach( + "phoenix-endpoint-logger", + [:phoenix, :endpoint, :stop], + &__MODULE__.log_request/4, + %{} + ) + children = [ ElixirAiWeb.Telemetry, ElixirAi.Repo, @@ -39,4 +47,32 @@ defmodule ElixirAi.Application do ElixirAiWeb.Endpoint.config_change(changed, removed) :ok end + + # Custom request logger that filters health check endpoint + require Logger + + def log_request(_event, measurements, %{conn: conn}, _config) do + # Skip logging for health check endpoint + if conn.request_path != "/health" do + duration = System.convert_time_unit(measurements.duration, :native, :microsecond) + + Logger.info( + fn -> + [conn.method, " ", conn.request_path] + end, + request_id: conn.assigns[:request_id] + ) + + Logger.info( + fn -> + ["Sent ", to_string(conn.status), " in ", format_duration(duration)] + end, + request_id: conn.assigns[:request_id] + ) + end + end + + defp format_duration(μs) when μs < 1000, do: "#{μs}µs" + defp format_duration(μs) when μs < 1_000_000, do: "#{div(μs, 1000)}ms" + defp format_duration(μs), do: "#{Float.round(μs / 1_000_000, 2)}s" end diff --git a/lib/elixir_ai_web/endpoint.ex b/lib/elixir_ai_web/endpoint.ex index 7a89052..f5bd0c5 100644 --- a/lib/elixir_ai_web/endpoint.ex +++ b/lib/elixir_ai_web/endpoint.ex @@ -38,7 +38,6 @@ defmodule ElixirAiWeb.Endpoint do cookie_key: "request_logger" plug Plug.RequestId - plug ElixirAiWeb.Plugs.HealthCheckLogger plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] plug Plug.Parsers, diff --git a/lib/elixir_ai_web/health_check_filter.ex b/lib/elixir_ai_web/health_check_filter.ex deleted file mode 100644 index 31122a4..0000000 --- a/lib/elixir_ai_web/health_check_filter.ex +++ /dev/null @@ -1,15 +0,0 @@ -defmodule ElixirAiWeb.HealthCheckFilter do - @moduledoc """ - Logger filter to suppress health check endpoint logs. - """ - - def filter(%{meta: meta}, _config) when is_map(meta) do - if Map.get(meta, :health_check) == true do - :stop - else - :ignore - end - end - - def filter(_log_event, _config), do: :ignore -end diff --git a/lib/elixir_ai_web/plugs/health_check_logger.ex b/lib/elixir_ai_web/plugs/health_check_logger.ex deleted file mode 100644 index bfc5bbf..0000000 --- a/lib/elixir_ai_web/plugs/health_check_logger.ex +++ /dev/null @@ -1,19 +0,0 @@ -defmodule ElixirAiWeb.Plugs.HealthCheckLogger do - @moduledoc """ - Plug that marks health check requests for filtering. - """ - @behaviour Plug - require Logger - - @impl true - def init(opts), do: opts - - @impl true - def call(%Plug.Conn{path_info: ["health"]} = conn, _opts) do - # Mark this as a health check for logger filtering - Logger.metadata(health_check: true) - conn - end - - def call(conn, _opts), do: conn -end diff --git a/mix.lock b/mix.lock index 24beea3..bdbc9fa 100644 --- a/mix.lock +++ b/mix.lock @@ -1,8 +1,10 @@ %{ "acceptor_pool": {:hex, :acceptor_pool, "1.0.1", "d88c2e8a0be9216cf513fbcd3e5a4beb36bee3ff4168e85d6152c6f899359cdb", [:rebar3], [], "hexpm", "f172f3d74513e8edd445c257d596fc84dbdd56d2c6fa287434269648ae5a421e"}, "bandit": {:hex, :bandit, "1.10.3", "1e5d168fa79ec8de2860d1b4d878d97d4fbbe2fdbe7b0a7d9315a4359d1d4bb9", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "99a52d909c48db65ca598e1962797659e3c0f1d06e825a50c3d75b74a5e2db18"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "castore": {:hex, :castore, "1.0.17", "4f9770d2d45fbd91dcf6bd404cf64e7e58fed04fadda0923dc32acca0badffa2", [:mix], [], "hexpm", "12d24b9d80b910dd3953e165636d68f147a31db945d2dcb9365e441f8b5351e5"}, "chatterbox": {:hex, :ts_chatterbox, "0.15.1", "5cac4d15dd7ad61fc3c4415ce4826fc563d4643dee897a558ec4ea0b1c835c9c", [:rebar3], [{:hpack, "~> 0.3.0", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "4f75b91451338bc0da5f52f3480fa6ef6e3a2aeecfc33686d6b3d0a0948f31aa"}, + "credo": {:hex, :credo, "1.7.17", "f92b6aa5b26301eaa5a35e4d48ebf5aa1e7094ac00ae38f87086c562caf8a22f", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1eb5645c835f0b6c9b5410f94b5a185057bcf6d62a9c2b476da971cde8749645"}, "ctx": {:hex, :ctx, "0.6.0", "8ff88b70e6400c4df90142e7f130625b82086077a45364a78d208ed3ed53c7fe", [:rebar3], [], "hexpm", "a14ed2d1b67723dbebbe423b28d7615eb0bdcba6ff28f2d1f1b0a7e1d4aa5fc2"}, "db_connection": {:hex, :db_connection, "2.9.0", "a6a97c5c958a2d7091a58a9be40caf41ab496b0701d21e1d1abff3fa27a7f371", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "17d502eacaf61829db98facf6f20808ed33da6ccf495354a41e64fe42f9c509c"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},