55
66module Cardano.Logging.Configuration
77 ( ConfigReflection (.. )
8+ , HermodException (.. )
89 , emptyConfigReflection
910 , configureTracers
1011 , withNamespaceConfig
@@ -28,18 +29,27 @@ import Cardano.Logging.Trace
2829import Cardano.Logging.TraceDispatcherMessage
2930import Cardano.Logging.Types
3031
32+ import Control.Applicative (asum )
33+ import Control.Exception
3134import Control.Monad (unless )
3235import Control.Monad.IO.Class (MonadIO , liftIO )
3336import Control.Monad.IO.Unlift (MonadUnliftIO )
3437import qualified Control.Tracer as T
3538import Data.IORef (IORef , modifyIORef , newIORef , readIORef , writeIORef )
36- import Data.List (maximumBy , nub )
37- import qualified Data.Map as Map
38- import Data.Maybe (fromMaybe , mapMaybe )
39+ import Data.List (inits , maximumBy , nub )
40+ import qualified Data.Map.Lazy as Map
41+ import Data.Maybe (fromMaybe , listToMaybe , mapMaybe )
3942import qualified Data.Set as Set
4043import Data.Text (Text , intercalate , unpack )
4144
4245
46+ -- This is currently ad-hoc. With a future refactoring of trace-dispatcher,
47+ -- it will be moved and serve as a proper error / exception type.
48+ data HermodException = HermodConfigException { excMessage :: String }
49+ deriving Show
50+
51+ instance Exception HermodException
52+
4353-- | Call this function at initialisation, and later for reconfiguration.
4454-- Config reflection is used to optimise the tracers and has to collect
4555-- information about the tracers. Although it is possible to give more then
@@ -153,6 +163,7 @@ withNamespaceConfig name extract withConfig tr = do
153163 ref <- liftIO (newIORef (Left (Map. empty, Nothing )))
154164 pure $ contramapM' (mapFunc ref)
155165 where
166+ configError = liftIO . throwIO . HermodConfigException
156167 mapFunc ref =
157168 \ case
158169 (lc, Right a) -> do
@@ -192,11 +203,11 @@ withNamespaceConfig name extract withConfig tr = do
192203 then do
193204 Trace tt <- withConfig (Just val) tr
194205 T. traceWith tt (lc, Left (TCConfig c))
195- else error $ " Inconsistent trace configuration with context "
206+ else configError $ " Inconsistent trace configuration with context "
196207 ++ show nst
197- Right _val -> error $ " Trace not reset before reconfiguration (1)"
208+ Right _val -> configError $ " Trace not reset before reconfiguration (1)"
198209 ++ show nst
199- Left (_cmap, Just _v) -> error $ " Trace not reset before reconfiguration (2)"
210+ Left (_cmap, Just _v) -> configError $ " Trace not reset before reconfiguration (2)"
200211 ++ show nst
201212 (lc, Left (TCOptimize cr)) -> do
202213 eitherConf <- liftIO $ readIORef ref
@@ -222,10 +233,10 @@ withNamespaceConfig name extract withConfig tr = do
222233 liftIO $ writeIORef ref (Left (newmap, Just mostCommon))
223234 Trace tt <- withConfig Nothing tr
224235 T. traceWith tt (lc, Left (TCOptimize cr))
225- Right _val -> error $ " Trace not reset before reconfiguration (3)"
236+ Right _val -> configError $ " Trace not reset before reconfiguration (3)"
226237 ++ show nst
227238 Left (_cmap, Just _v) ->
228- error $ " Trace not reset before reconfiguration (4)"
239+ configError $ " Trace not reset before reconfiguration (4)"
229240 ++ show nst
230241 (lc, Left dc@ TCDocument {}) -> do
231242 eitherConf <- liftIO $ readIORef ref
@@ -243,7 +254,7 @@ withNamespaceConfig name extract withConfig tr = do
243254 Nothing -> do
244255 tt <- withConfig (Just v) tr
245256 T. traceWith (unpackTrace tt) (lc, Left dc)
246- Left (_cmap, Nothing ) -> error ( " Missing configuration(2) " <> name <> " ns " <> show nst)
257+ Left (_cmap, Nothing ) -> configError $ " Missing configuration(2) " <> name <> " ns " <> show nst
247258
248259
249260-- | Filter a trace by severity and take the filter value from the config
@@ -253,7 +264,7 @@ filterSeverityFromConfig :: (MonadIO m) =>
253264filterSeverityFromConfig =
254265 withNamespaceConfig
255266 " severity"
256- getSeverity'
267+ ( \ conf -> pure . getSeverity conf)
257268 (\ sev tr -> contramapMCond tr (mapF sev))
258269 where
259270 mapF confSev =
@@ -282,7 +293,7 @@ withDetailsFromConfig :: (MonadIO m) =>
282293withDetailsFromConfig =
283294 withNamespaceConfig
284295 " details"
285- getDetails'
296+ ( \ conf -> pure . getDetails conf)
286297 (\ mbDtl b -> case mbDtl of
287298 Just dtl -> pure $ setDetails dtl b
288299 Nothing -> pure $ setDetails DNormal b)
@@ -294,7 +305,7 @@ withBackendsFromConfig :: (MonadIO m) =>
294305withBackendsFromConfig rappendPrefixNameAndFormatter =
295306 withNamespaceConfig
296307 " backends"
297- getBackends'
308+ ( \ conf -> pure . getBackends conf)
298309 rappendPrefixNameAndFormatter
299310 (Trace T. nullTracer)
300311
@@ -377,9 +388,6 @@ getSeverity config ns =
377388 severitySelector (ConfSeverity s) = Just s
378389 severitySelector _ = Nothing
379390
380- getSeverity' :: Applicative m => TraceConfig -> Namespace a -> m SeverityF
381- getSeverity' config ns = pure $ getSeverity config ns
382-
383391-- | If no details can be found in the config, it is set to DNormal
384392getDetails :: TraceConfig -> Namespace a -> DetailLevel
385393getDetails config ns =
@@ -389,9 +397,6 @@ getDetails config ns =
389397 detailSelector (ConfDetail d) = Just d
390398 detailSelector _ = Nothing
391399
392- getDetails' :: Applicative m => TraceConfig -> Namespace a -> m DetailLevel
393- getDetails' config n = pure $ getDetails config n
394-
395400-- | If no backends can be found in the config, it is set to
396401-- [EKGBackend, Forwarder, Stdout HumanFormatColoured]
397402getBackends :: TraceConfig -> Namespace a -> [BackendConfig ]
@@ -403,9 +408,6 @@ getBackends config ns =
403408 backendSelector (ConfBackend s) = Just s
404409 backendSelector _ = Nothing
405410
406- getBackends' :: Applicative m => TraceConfig -> Namespace a -> m [BackendConfig ]
407- getBackends' config ns = pure $ getBackends config ns
408-
409411-- | May return a limiter specification
410412getLimiterSpec :: TraceConfig -> Namespace a -> Maybe (Text , Double )
411413getLimiterSpec config ns = getOption limiterSelector config (nsGetComplete ns)
@@ -414,17 +416,10 @@ getLimiterSpec config ns = getOption limiterSelector config (nsGetComplete ns)
414416 limiterSelector (ConfLimiter f) = Just (intercalate " ." (nsPrefix ns ++ nsInner ns), f)
415417 limiterSelector _ = Nothing
416418
417- -- | Searches in the config to find an option
419+ -- | Searches in the config to find an option, most-specific as per namespace first.
420+ -- (Generates all ancestor prefixes once via `inits`, avoiding a repeated O(n) `init` call at each recursion level)
418421getOption :: (ConfigOption -> Maybe a ) -> TraceConfig -> [Text ] -> Maybe a
419- getOption sel config [] =
420- case Map. lookup [] (tcOptions config) of
421- Nothing -> Nothing
422- Just options -> case mapMaybe sel options of
423- [] -> Nothing
424- (opt : _) -> Just opt
425- getOption sel config ns =
426- case Map. lookup ns (tcOptions config) of
427- Nothing -> getOption sel config (init ns)
428- Just options -> case mapMaybe sel options of
429- [] -> getOption sel config (init ns)
430- (opt : _) -> Just opt
422+ getOption sel TraceConfig {tcOptions} ns =
423+ asum $ map tryLookup $ reverse $ inits ns
424+ where
425+ tryLookup k = listToMaybe . mapMaybe sel =<< Map. lookup k tcOptions
0 commit comments