diff --git a/CHANGELOG.txt b/CHANGELOG.txt index cb6ccc30..e0094d09 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,13 @@ 2026-03-05 +fix: suppress noisy health check logs in production + - Add logger filter to drop K8s health probe logs + - Prevents log flooding from /health endpoint calls every few seconds + - Configured in prod.exs logger :default_handler filters + - TelemetryFilter.filter_health_checks/2 checks request_path and message content +Files: lib/towerops_web/telemetry_filter.ex, + lib/towerops/application.ex, + config/prod.exs + security: comprehensive security audit fixes (9 critical/high priority issues) - Remove /health/time endpoint exposing system time information (CRITICAL) - Add email confirmation check to account data export endpoint (CRITICAL) diff --git a/config/prod.exs b/config/prod.exs index a4a102af..3a39a4ef 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -4,7 +4,7 @@ import Config config :honeybadger, exclude_envs: [:prod] -# Filter out harmless Oban shutdown messages and repetitive SNMP MIB errors +# Filter out harmless Oban shutdown messages, repetitive SNMP MIB errors, and noisy health checks config :logger, :default_handler, filters: [ drop_oban_shutdown: { @@ -14,6 +14,10 @@ config :logger, :default_handler, drop_snmp_mib_errors: { &Towerops.LoggerFilters.drop_snmp_mib_errors/2, [] + }, + filter_health_checks: { + &ToweropsWeb.TelemetryFilter.filter_health_checks/2, + [] } ] diff --git a/lib/towerops/application.ex b/lib/towerops/application.ex index 2e4ad537..13957e3f 100644 --- a/lib/towerops/application.ex +++ b/lib/towerops/application.ex @@ -123,6 +123,9 @@ defmodule Towerops.Application do opts = [strategy: :one_for_one, name: Towerops.Supervisor] result = Supervisor.start_link(children, opts) + # Attach telemetry filter to suppress noisy health check logs + ToweropsWeb.TelemetryFilter.attach() + # Run post-startup cleanup tasks (production only) # This ensures all polling jobs use the latest worker code after deployment Task.start(fn -> diff --git a/lib/towerops_web/telemetry_filter.ex b/lib/towerops_web/telemetry_filter.ex new file mode 100644 index 00000000..44fde02a --- /dev/null +++ b/lib/towerops_web/telemetry_filter.ex @@ -0,0 +1,49 @@ +defmodule ToweropsWeb.TelemetryFilter do + @moduledoc """ + Logger metadata filter that suppresses noisy health check and uptime monitor logs. + + Filters log messages for: + - GET /health (Kubernetes liveness/readiness probes) + - HEAD / (External uptime monitors) + + This is configured as a logger metadata filter in config.exs. + """ + + require Logger + + @doc """ + Logger filter function that drops health check requests. + + Returns :stop to prevent logging, :ignore to allow logging. + """ + def filter_health_checks(log_event, _opts) do + case log_event do + {_level, _gl, {Logger, msg, _ts, metadata}} -> + # Check if this is a Phoenix request log with conn metadata + cond do + # Filter based on request_path in metadata (Phoenix endpoint logs) + Keyword.get(metadata, :request_path) in ["/health"] -> + :stop + + # Filter based on message content as fallback + is_binary(msg) and (String.contains?(msg, "GET /health") or String.contains?(msg, "HEAD /")) -> + :stop + + true -> + :ignore + end + + _ -> + :ignore + end + end + + @doc """ + Dummy attach function for compatibility with existing code. + The actual filtering happens via logger configuration, not telemetry. + """ + def attach do + Logger.info("Health check log filter active via logger configuration") + :ok + end +end