diff --git a/CHANGELOG.md b/CHANGELOG.md index c83954473..a4f4ad2b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ All notable changes to this project will be documented in this file. From versio - Add config `client_error_verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824 - Add `Vary` header to responses by @develop7 in #4609 +### Fixed + +- Fix not logging SIGTERM and SIGINT by @steve-chavez in #4728 + ### Changed - All responses now include a `Vary` header by @develop7 in #4609 diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index bbf6e0700..2938e6184 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -80,7 +80,7 @@ run appState = do AppState.schemaCacheLoader appState -- Loads the initial SchemaCache (mainSocket, adminSocket) <- initSockets conf - Unix.installSignalHandlers (AppState.getMainThreadId appState) (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState) + Unix.installSignalHandlers observer (AppState.getMainThreadId appState) (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState) Listener.runListener appState @@ -283,4 +283,3 @@ initSockets AppConfig{..} = do Nothing -> pure Nothing pure (sock, adminSock) - diff --git a/src/PostgREST/Logger.hs b/src/PostgREST/Logger.hs index 22bae60a9..bbfcc6a1a 100644 --- a/src/PostgREST/Logger.hs +++ b/src/PostgREST/Logger.hs @@ -228,6 +228,8 @@ observationMessages = \case pure "Looked up a JWT in JWT cache" JwtCacheEviction -> pure "Evicted entry from JWT cache" + TerminationUnixSignalObs signal -> + pure $ "Received termination unix signal " <> signal WarpErrorObs txt -> pure $ "Warp server error: " <> txt where diff --git a/src/PostgREST/Observation.hs b/src/PostgREST/Observation.hs index e7d848ab4..e96c86748 100644 --- a/src/PostgREST/Observation.hs +++ b/src/PostgREST/Observation.hs @@ -54,6 +54,7 @@ data Observation | PoolRequestFullfilled | JwtCacheLookup Bool | JwtCacheEviction + | TerminationUnixSignalObs Text | WarpErrorObs Text data ObsFatalError = ServerAuthError | ServerPgrstBug | ServerError42P05 | ServerError08P01 diff --git a/src/PostgREST/Unix.hs b/src/PostgREST/Unix.hs index 2027cac02..2128c6cb9 100644 --- a/src/PostgREST/Unix.hs +++ b/src/PostgREST/Unix.hs @@ -11,26 +11,27 @@ import qualified System.Posix.Signals as Signals import System.Posix.Types (FileMode) import System.PosixCompat.Files (setFileMode) -import Data.String (String) -import qualified Network.Socket as NS +import Data.String (String) +import qualified Network.Socket as NS +import qualified PostgREST.Observation as Observation import Protolude -import System.Directory (removeFile) -import System.IO.Error (isDoesNotExistError) +import System.Directory (removeFile) +import System.IO.Error (isDoesNotExistError) -- | Set signal handlers, only for systems with signals -installSignalHandlers :: ThreadId -> IO () -> IO () -> IO () +installSignalHandlers :: Observation.ObservationHandler -> ThreadId -> IO () -> IO () -> IO () #ifndef mingw32_HOST_OS -installSignalHandlers tid usr1 usr2 = do +installSignalHandlers observer tid usr1 usr2 = do let interrupt = throwTo tid UserInterrupt - install Signals.sigINT interrupt - install Signals.sigTERM interrupt + install Signals.sigINT $ observer (Observation.TerminationUnixSignalObs "SIGINT") >> interrupt + install Signals.sigTERM $ observer (Observation.TerminationUnixSignalObs "SIGTERM") >> interrupt install Signals.sigUSR1 usr1 install Signals.sigUSR2 usr2 where install signal handler = void $ Signals.installHandler signal (Signals.Catch handler) Nothing #else -installSignalHandlers _ _ _ = pass +installSignalHandlers _ _ _ _ = pass #endif -- | Create a unix domain socket and bind it to the given path. diff --git a/test/io/test_io.py b/test/io/test_io.py index be7923fd6..e0c4da4ab 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -127,6 +127,24 @@ def test_graceful_shutdown_waits_for_in_flight_request(defaultenv): t.join() +def test_termination_unix_signal_logging(defaultenv): + "Server logs when handling termination unix signals." + + with run(env=defaultenv) as postgrest: + postgrest.process.send_signal(signal.SIGTERM) + lines = postgrest.read_stdout(nlines=1) + wait_until_exit(postgrest) + + assert any("SIGTERM" in line for line in lines) + + with run(env=defaultenv) as postgrest: + postgrest.process.send_signal(signal.SIGINT) + lines = postgrest.read_stdout(nlines=1) + wait_until_exit(postgrest) + + assert any("SIGINT" in line for line in lines) + + def test_random_port_bound(defaultenv): "PostgREST should bind to a random port when PGRST_SERVER_PORT is 0."