Skip to content

Commit 69c6ce9

Browse files
committed
refactor: use LogLevel in Logger
* remove Logger dependency on Auth.
1 parent c57ec52 commit 69c6ce9

File tree

9 files changed

+77
-64
lines changed

9 files changed

+77
-64
lines changed

src/PostgREST/Admin.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ import qualified PostgREST.Config as Config
2727
import Protolude
2828

2929
runAdmin :: AppConfig -> AppState -> Warp.Settings -> IO ()
30-
runAdmin conf@AppConfig{configAdminServerPort, configObserver=observer} appState settings =
30+
runAdmin conf@AppConfig{configAdminServerPort} appState settings =
3131
whenJust (AppState.getSocketAdmin appState) $ \adminSocket -> do
3232
observer $ AdminStartObs configAdminServerPort
3333
void . forkIO $ Warp.runSettingsSocket settings adminSocket adminApp
3434
where
3535
adminApp = admin appState conf
36+
observer = AppState.getObserver appState
3637

3738
-- | PostgREST admin application
3839
admin :: AppState.AppState -> AppConfig -> Wai.Application
@@ -42,7 +43,7 @@ admin appState appConfig req respond = do
4243
isConnectionUp <-
4344
if configDbChannelEnabled appConfig
4445
then AppState.getIsListenerOn appState
45-
else isRight <$> AppState.usePool appState appConfig (SQL.sql "SELECT 1")
46+
else isRight <$> AppState.usePool appState (SQL.sql "SELECT 1")
4647

4748
case Wai.pathInfo req of
4849
["ready"] ->

src/PostgREST/App.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ type Handler = ExceptT Error
6262

6363
run :: AppState -> IO ()
6464
run appState = do
65-
conf@AppConfig{configObserver=observer, ..} <- AppState.getConfig appState
65+
let observer = AppState.getObserver appState
66+
conf@AppConfig{..} <- AppState.getConfig appState
6667

6768
observer $ AppServerStartObs prettyVersion
6869

@@ -97,7 +98,7 @@ postgrest logLevel appState connWorker =
9798
traceHeaderMiddleware appState .
9899
Cors.middleware appState .
99100
Auth.middleware appState .
100-
Logger.middleware logLevel $
101+
Logger.middleware logLevel Auth.getRole $
101102
-- fromJust can be used, because the auth middleware will **always** add
102103
-- some AuthResult to the vault.
103104
\req respond -> case fromJust $ Auth.getResult req of

src/PostgREST/AppState.hs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ module PostgREST.AppState
2727
, reReadConfig
2828
, connectionWorker
2929
, runListener
30+
, getObserver
3031
) where
3132

3233
import qualified Data.Aeson as JSON
@@ -43,6 +44,7 @@ import qualified Hasql.Transaction.Sessions as SQL
4344
import qualified Network.HTTP.Types.Status as HTTP
4445
import qualified Network.Socket as NS
4546
import qualified PostgREST.Error as Error
47+
import qualified PostgREST.Logger as Logger
4648
import PostgREST.Observation
4749
import PostgREST.Version (prettyVersion)
4850
import System.TimeIt (timeItT)
@@ -57,7 +59,6 @@ import Data.IORef (IORef, atomicWriteIORef, newIORef,
5759
import Data.Time.Clock (UTCTime, getCurrentTime)
5860

5961
import PostgREST.Config (AppConfig (..),
60-
LogLevel (..),
6162
addFallbackAppName,
6263
readAppConfig)
6364
import PostgREST.Config.Database (queryDbSettings,
@@ -109,19 +110,26 @@ data AppState = AppState
109110
, stateSocketREST :: NS.Socket
110111
-- | Network socket for the admin UI
111112
, stateSocketAdmin :: Maybe NS.Socket
113+
-- | Logger state
114+
, stateLogger :: Logger.LoggerState
115+
-- | Observation handler
116+
, stateObserver :: ObservationHandler
112117
}
113118

114119
type AppSockets = (NS.Socket, Maybe NS.Socket)
115120

116121
init :: AppConfig -> IO AppState
117-
init conf = do
122+
init conf@AppConfig{configLogLevel} = do
123+
loggerState <- Logger.init
124+
let observer = Logger.observationLogger loggerState configLogLevel
118125
pool <- initPool conf
119126
(sock, adminSock) <- initSockets conf
120-
state' <- initWithPool (sock, adminSock) pool conf
121-
pure state' { stateSocketREST = sock, stateSocketAdmin = adminSock }
127+
state' <- initWithPool (sock, adminSock) pool conf loggerState observer
128+
pure state' { stateSocketREST = sock, stateSocketAdmin = adminSock}
129+
130+
initWithPool :: AppSockets -> SQL.Pool -> AppConfig -> Logger.LoggerState -> ObservationHandler -> IO AppState
131+
initWithPool (sock, adminSock) pool conf loggerState observer = do
122132

123-
initWithPool :: AppSockets -> SQL.Pool -> AppConfig -> IO AppState
124-
initWithPool (sock, adminSock) pool conf = do
125133
appState <- AppState pool
126134
<$> newIORef minimumPgVersion -- assume we're in a supported version when starting, this will be corrected on a later step
127135
<*> newIORef Nothing
@@ -136,6 +144,8 @@ initWithPool (sock, adminSock) pool conf = do
136144
<*> C.newCache Nothing
137145
<*> pure sock
138146
<*> pure adminSock
147+
<*> pure loggerState
148+
<*> pure observer
139149

140150
debWorker <-
141151
let decisecond = 100000 in
@@ -193,17 +203,16 @@ initPool AppConfig{..} =
193203
(toUtf8 $ addFallbackAppName prettyVersion configDbUri)
194204

195205
-- | Run an action with a database connection.
196-
usePool :: AppState -> AppConfig -> SQL.Session a -> IO (Either SQL.UsageError a)
197-
usePool AppState{..} AppConfig{configLogLevel, configObserver=observer} sess = do
206+
usePool :: AppState -> SQL.Session a -> IO (Either SQL.UsageError a)
207+
usePool AppState{stateObserver=observer,..} sess = do
198208
res <- SQL.use statePool sess
199209

200-
when (configLogLevel > LogCrit) $ do
201-
whenLeft res (\case
202-
SQL.AcquisitionTimeoutUsageError -> observer $ PoolAcqTimeoutObs SQL.AcquisitionTimeoutUsageError
203-
error
204-
-- TODO We're using the 500 HTTP status for getting all internal db errors but there's no response here. We need a new intermediate type to not rely on the HTTP status.
205-
| Error.status (Error.PgError False error) >= HTTP.status500 -> observer $ QueryErrorCodeHighObs error
206-
| otherwise -> pure ())
210+
whenLeft res (\case
211+
SQL.AcquisitionTimeoutUsageError -> observer $ PoolAcqTimeoutObs SQL.AcquisitionTimeoutUsageError
212+
error
213+
-- TODO We're using the 500 HTTP status for getting all internal db errors but there's no response here. We need a new intermediate type to not rely on the HTTP status.
214+
| Error.status (Error.PgError False error) >= HTTP.status500 -> observer $ QueryErrorCodeHighObs error
215+
| otherwise -> pure ())
207216

208217
return res
209218

@@ -281,19 +290,22 @@ getSchemaCacheLoaded = readIORef . stateSchemaCacheLoaded
281290
putSchemaCacheLoaded :: AppState -> Bool -> IO ()
282291
putSchemaCacheLoaded = atomicWriteIORef . stateSchemaCacheLoaded
283292

293+
getObserver :: AppState -> ObservationHandler
294+
getObserver = stateObserver
295+
284296
-- | Schema cache status
285297
data SCacheStatus
286298
= SCLoaded
287299
| SCOnRetry
288300
| SCFatalFail
289301

290302
-- | Load the SchemaCache by using a connection from the pool.
291-
loadSchemaCache :: AppState -> AppConfig -> IO SCacheStatus
292-
loadSchemaCache appState AppConfig{configObserver=observer} = do
303+
loadSchemaCache :: AppState -> IO SCacheStatus
304+
loadSchemaCache appState@AppState{stateObserver=observer} = do
293305
conf@AppConfig{..} <- getConfig appState
294306
(resultTime, result) <-
295307
let transaction = if configDbPreparedStatements then SQL.transaction else SQL.unpreparedTransaction in
296-
timeItT $ usePool appState conf (transaction SQL.ReadCommitted SQL.Read $ querySchemaCache conf)
308+
timeItT $ usePool appState (transaction SQL.ReadCommitted SQL.Read $ querySchemaCache conf)
297309
case result of
298310
Left e -> do
299311
case checkIsFatal e of
@@ -333,12 +345,12 @@ data ConnectionStatus
333345
-- program.
334346
-- 3. Obtains the sCache. If this fails, it goes back to 1.
335347
internalConnectionWorker :: AppState -> IO ()
336-
internalConnectionWorker appState = work
348+
internalConnectionWorker appState@AppState{stateObserver=observer} = work
337349
where
338350
work = do
339-
config@AppConfig{configObserver=observer, ..} <- getConfig appState
351+
AppConfig{..} <- getConfig appState
340352
observer DBConnectAttemptObs
341-
connected <- establishConnection appState config
353+
connected <- establishConnection appState
342354
case connected of
343355
FatalConnectionError reason ->
344356
-- Fatal error when connecting
@@ -356,7 +368,7 @@ internalConnectionWorker appState = work
356368
-- this could be fail because the connection drops, but the loadSchemaCache will pick the error and retry again
357369
-- We cannot retry after it fails immediately, because db-pre-config could have user errors. We just log the error and continue.
358370
when configDbConfig $ reReadConfig False appState
359-
scStatus <- loadSchemaCache appState config
371+
scStatus <- loadSchemaCache appState
360372
case scStatus of
361373
SCLoaded ->
362374
-- do nothing and proceed if the load was successful
@@ -378,8 +390,8 @@ internalConnectionWorker appState = work
378390
--
379391
-- The connection tries are capped, but if the connection times out no error is
380392
-- thrown, just 'False' is returned.
381-
establishConnection :: AppState -> AppConfig -> IO ConnectionStatus
382-
establishConnection appState config@AppConfig{configObserver=observer} =
393+
establishConnection :: AppState -> IO ConnectionStatus
394+
establishConnection appState@AppState{stateObserver=observer} =
383395
retrying retrySettings shouldRetry $
384396
const $ flushPool appState >> getConnectionStatus
385397
where
@@ -389,7 +401,7 @@ establishConnection appState config@AppConfig{configObserver=observer} =
389401

390402
getConnectionStatus :: IO ConnectionStatus
391403
getConnectionStatus = do
392-
pgVersion <- usePool appState config (queryPgVersion False) -- No need to prepare the query here, as the connection might not be established
404+
pgVersion <- usePool appState (queryPgVersion False) -- No need to prepare the query here, as the connection might not be established
393405
case pgVersion of
394406
Left e -> do
395407
observer $ ConnectionPgVersionErrorObs e
@@ -418,12 +430,12 @@ establishConnection appState config@AppConfig{configObserver=observer} =
418430

419431
-- | Re-reads the config plus config options from the db
420432
reReadConfig :: Bool -> AppState -> IO ()
421-
reReadConfig startingUp appState = do
422-
config@AppConfig{configObserver=observer, ..} <- getConfig appState
433+
reReadConfig startingUp appState@AppState{stateObserver=observer} = do
434+
AppConfig{..} <- getConfig appState
423435
pgVer <- getPgVersion appState
424436
dbSettings <-
425437
if configDbConfig then do
426-
qDbSettings <- usePool appState config (queryDbSettings (dumpQi <$> configDbPreConfig) configDbPreparedStatements)
438+
qDbSettings <- usePool appState (queryDbSettings (dumpQi <$> configDbPreConfig) configDbPreparedStatements)
427439
case qDbSettings of
428440
Left e -> do
429441
observer ConfigReadErrorObs
@@ -439,15 +451,15 @@ reReadConfig startingUp appState = do
439451
pure mempty
440452
(roleSettings, roleIsolationLvl) <-
441453
if configDbConfig then do
442-
rSettings <- usePool appState config (queryRoleSettings pgVer configDbPreparedStatements)
454+
rSettings <- usePool appState (queryRoleSettings pgVer configDbPreparedStatements)
443455
case rSettings of
444456
Left e -> do
445457
observer $ QueryRoleSettingsErrorObs e
446458
pure (mempty, mempty)
447459
Right x -> pure x
448460
else
449461
pure mempty
450-
readAppConfig dbSettings configFilePath (Just configDbUri) roleSettings roleIsolationLvl observer >>= \case
462+
readAppConfig dbSettings configFilePath (Just configDbUri) roleSettings roleIsolationLvl >>= \case
451463
Left err ->
452464
if startingUp then
453465
panic err -- die on invalid config if the program is starting up
@@ -468,7 +480,7 @@ runListener conf@AppConfig{configDbChannelEnabled} appState = do
468480
-- NOTIFY <db-channel> - with an empty payload - is done, it refills the schema
469481
-- cache. It uses the connectionWorker in case the LISTEN connection dies.
470482
listener :: AppState -> AppConfig -> IO ()
471-
listener appState conf@AppConfig{configObserver=observer, ..} = do
483+
listener appState@AppState{stateObserver=observer} conf@AppConfig{..} = do
472484
let dbChannel = toS configDbChannel
473485

474486
-- The listener has to wait for a signal from the connectionWorker.

src/PostgREST/CLI.hs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,14 @@ import PostgREST.Version (prettyVersion)
2525
import qualified PostgREST.App as App
2626
import qualified PostgREST.AppState as AppState
2727
import qualified PostgREST.Config as Config
28-
import qualified PostgREST.Logger as Logger
2928

3029
import Protolude hiding (hPutStrLn)
3130

3231

3332
main :: CLI -> IO ()
3433
main CLI{cliCommand, cliPath} = do
35-
loggerState <- Logger.init
36-
3734
conf@AppConfig{..} <-
38-
either panic identity <$> Config.readAppConfig mempty cliPath Nothing mempty mempty (Logger.observationLogger loggerState)
35+
either panic identity <$> Config.readAppConfig mempty cliPath Nothing mempty mempty
3936

4037
-- Per https://github.com/PostgREST/postgrest/issues/268, we want to
4138
-- explicitly close the connections to PostgreSQL on shutdown.
@@ -56,7 +53,7 @@ dumpSchema appState = do
5653
conf@AppConfig{..} <- AppState.getConfig appState
5754
result <-
5855
let transaction = if configDbPreparedStatements then SQL.transaction else SQL.unpreparedTransaction in
59-
AppState.usePool appState conf
56+
AppState.usePool appState
6057
(transaction SQL.ReadCommitted SQL.Read $ querySchemaCache conf)
6158
case result of
6259
Left e -> do

src/PostgREST/Config.hs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ import PostgREST.Config.Proxy (Proxy (..),
6464
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier, dumpQi,
6565
toQi)
6666

67-
import PostgREST.Observation
68-
6967
import Protolude hiding (Proxy, toList)
7068

7169

@@ -114,7 +112,6 @@ data AppConfig = AppConfig
114112
, configRoleSettings :: RoleSettings
115113
, configRoleIsoLvl :: RoleIsolationLvl
116114
, configInternalSCSleep :: Maybe Int32
117-
, configObserver :: ObservationHandler
118115
}
119116

120117
data LogLevel = LogCrit | LogError | LogWarn | LogInfo
@@ -213,13 +210,13 @@ instance JustIfMaybe a (Maybe a) where
213210

214211
-- | Reads and parses the config and overrides its parameters from env vars,
215212
-- files or db settings.
216-
readAppConfig :: [(Text, Text)] -> Maybe FilePath -> Maybe Text -> RoleSettings -> RoleIsolationLvl -> ObservationHandler -> IO (Either Text AppConfig)
217-
readAppConfig dbSettings optPath prevDbUri roleSettings roleIsolationLvl observer = do
213+
readAppConfig :: [(Text, Text)] -> Maybe FilePath -> Maybe Text -> RoleSettings -> RoleIsolationLvl -> IO (Either Text AppConfig)
214+
readAppConfig dbSettings optPath prevDbUri roleSettings roleIsolationLvl = do
218215
env <- readPGRSTEnvironment
219216
-- if no filename provided, start with an empty map to read config from environment
220217
conf <- maybe (return $ Right M.empty) loadConfig optPath
221218

222-
case C.runParser (parser optPath env dbSettings roleSettings roleIsolationLvl observer) =<< mapLeft show conf of
219+
case C.runParser (parser optPath env dbSettings roleSettings roleIsolationLvl) =<< mapLeft show conf of
223220
Left err ->
224221
return . Left $ "Error in config " <> err
225222
Right parsedConfig ->
@@ -234,8 +231,8 @@ readAppConfig dbSettings optPath prevDbUri roleSettings roleIsolationLvl observe
234231
decodeJWKS <$>
235232
(decodeSecret =<< readSecretFile =<< readDbUriFile prevDbUri parsedConfig)
236233

237-
parser :: Maybe FilePath -> Environment -> [(Text, Text)] -> RoleSettings -> RoleIsolationLvl -> ObservationHandler -> C.Parser C.Config AppConfig
238-
parser optPath env dbSettings roleSettings roleIsolationLvl observer =
234+
parser :: Maybe FilePath -> Environment -> [(Text, Text)] -> RoleSettings -> RoleIsolationLvl -> C.Parser C.Config AppConfig
235+
parser optPath env dbSettings roleSettings roleIsolationLvl =
239236
AppConfig
240237
<$> parseAppSettings "app.settings"
241238
<*> (fromMaybe False <$> optBool "db-aggregates-enabled")
@@ -288,7 +285,6 @@ parser optPath env dbSettings roleSettings roleIsolationLvl observer =
288285
<*> pure roleSettings
289286
<*> pure roleIsolationLvl
290287
<*> optInt "internal-schema-cache-sleep"
291-
<*> pure observer
292288
where
293289
parseAppSettings :: C.Key -> C.Parser C.Config [(Text, Text)]
294290
parseAppSettings key = addFromEnv . fmap (fmap coerceText) <$> C.subassocs key C.value

src/PostgREST/Logger.hs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ module PostgREST.Logger
66
( middleware
77
, observationLogger
88
, init
9+
, LoggerState
910
) where
1011

11-
import Control.AutoUpdate (defaultUpdateSettings, mkAutoUpdate,
12-
updateAction)
13-
import Control.Debounce
12+
import Control.AutoUpdate (defaultUpdateSettings,
13+
mkAutoUpdate, updateAction)
14+
import Control.Debounce
15+
import qualified Data.ByteString.Char8 as BS
1416

1517
import Data.Time (ZonedTime, defaultTimeLocale, formatTime,
1618
getZonedTime)
@@ -24,8 +26,6 @@ import System.IO.Unsafe (unsafePerformIO)
2426
import PostgREST.Config (LogLevel (..))
2527
import PostgREST.Observation
2628

27-
import qualified PostgREST.Auth as Auth
28-
2929
import Protolude
3030

3131
data LoggerState = LoggerState
@@ -54,8 +54,8 @@ logWithDebounce loggerState action = do
5454
putMVar (stateLogDebouncePoolTimeout loggerState) newDebouncer
5555
newDebouncer
5656

57-
middleware :: LogLevel -> Wai.Middleware
58-
middleware logLevel = case logLevel of
57+
middleware :: LogLevel -> (Wai.Request -> Maybe BS.ByteString) -> Wai.Middleware
58+
middleware logLevel getAuthRole = case logLevel of
5959
LogInfo -> requestLogger (const True)
6060
LogWarn -> requestLogger (>= status400)
6161
LogError -> requestLogger (>= status500)
@@ -67,15 +67,19 @@ middleware logLevel = case logLevel of
6767
Wai.ApacheWithSettings $
6868
Wai.defaultApacheSettings &
6969
Wai.setApacheRequestFilter (\_ res -> filterStatus $ Wai.responseStatus res) &
70-
Wai.setApacheUserGetter Auth.getRole
70+
Wai.setApacheUserGetter getAuthRole
7171
, Wai.autoFlush = True
7272
, Wai.destination = Wai.Handle stdout
7373
}
7474

75-
observationLogger :: LoggerState -> ObservationHandler
76-
observationLogger loggerState obs = case obs of
75+
observationLogger :: LoggerState -> LogLevel -> ObservationHandler
76+
observationLogger loggerState logLevel obs = case obs of
7777
o@(PoolAcqTimeoutObs _) -> do
78-
logWithDebounce loggerState $
78+
when (logLevel >= LogError) $ do
79+
logWithDebounce loggerState $
80+
logWithZTime loggerState $ observationMessage o
81+
o@(QueryErrorCodeHighObs _) -> do
82+
when (logLevel >= LogError) $ do
7983
logWithZTime loggerState $ observationMessage o
8084
o ->
8185
logWithZTime loggerState $ observationMessage o

src/PostgREST/Query.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ runQuery _ _ _ _ (NoDb x) _ _ _ = pure $ NoDbResult x
7979
runQuery appState config AuthResult{..} apiReq (Db plan) sCache pgVer authenticated = do
8080
dbResp <- lift $ do
8181
let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction
82-
AppState.usePool appState config (transaction isoLvl txMode $ runExceptT dbHandler)
82+
AppState.usePool appState (transaction isoLvl txMode $ runExceptT dbHandler)
8383

8484
resp <-
8585
liftEither . mapLeft Error.PgErr $

0 commit comments

Comments
 (0)