@@ -532,57 +532,82 @@ itemJson verb a = toJSON $ a & itemPayload %~ payloadObject verb
533-- Scribes should always take a 'Severity' and 'Verbosity'.
533-- Scribes should always take a 'Severity' and 'Verbosity'.
535−-- Severity is used to *exclude log messages* that are < the provided
535+-- Severity is used to __exclude log messages__ that are lower than
536−-- Severity. For instance, if the user passes InfoS, DebugS items
536+-- the provided Severity. For instance, if the user passes InfoS,
537−-- should be ignored. Katip provides the 'permitItem' utility for this.
537+-- DebugS items should be ignored. Katip provides the 'permitItem'
538+-- utility for this. The user or the scribe may use 'permitAND' and
539+-- 'permitOR' to further customize this filtering, even dynamically if
539-- Verbosity is used to select keys from the log item's payload. Each
542-- Verbosity is used to select keys from the log item's payload. Each
540-- 'LogItem' instance describes what keys should be retained for each
543-- 'LogItem' instance describes what keys should be retained for each
541-- Verbosity level. Use the 'payloadObject' utility for extracting the keys
544-- Verbosity level. Use the 'payloadObject' utility for extracting the keys
542−-- that should be permitted.
545+-- that should be written.
544−-- There is no built-in mechanism in katip for telling a scribe that
547+-- Scribes provide a finalizer IO action ('scribeFinalizer') that is
545−-- its time to shut down. 'unregisterScribe' merely drops it from the
548+-- meant to synchronously flush any remaining writes and clean up any
546−-- 'LogEnv'. This means there are 2 ways to handle resources as a scribe:
549+-- resources acquired when the scribe was created. Internally, katip
550+-- keeps a buffer for each scribe's writes. When 'closeScribe' or
551+-- 'closeScribes' is called, that buffer stops accepting new log
552+-- messages and after the last item in its buffer is sent to 'liPush',
553+-- calls the finalizer. Thus, when the finalizer returns, katip can
554+-- assume that all resources are cleaned up and all log messages are
548−-- 1. Pass in the resource when the scribe is created. Handle
557+-- While katip internally buffers messages per 'ScribeSettings', it
549−-- allocation and release of the resource elsewhere. This is what the
558+-- sends them one at a time to the scribe. Depending on the scribe
550−-- Handle scribe does.
559+-- itself, it may make sense for that scribe to keep its own internal
551−--
560+-- buffer to batch-send logs if writing items one at a time is not
552−-- 2. Return a finalizing function that tells the scribe to shut
561+-- efficient. The scribe implementer must be sure that on
553−-- down. @katip-elasticsearch@'s @mkEsScribe@ returns an @IO (Scribe,
562+-- finalization, all writes are committed synchronously.
554−-- IO ())@. The finalizer will flush any queued log messages and shut
563+
555−-- down gracefully before returning. This can be hooked into your
564+-- | Signature of a function passed to `Scribe` constructor and
556−-- application's shutdown routine to ensure you never miss any log
565+-- mkScribe* functions that decides which messages to be
557−-- messages on shutdown.
566+-- logged. Typically filters based on 'Severity', but can be
567+-- combined with other, custom logic with 'permitAND' and 'permitOR'
568+type PermitFunc = forall a. Item a -> IO Bool
560−-- | Signature of a function passed to `Scribe` constructor and mkScribe* functions
571+-- | AND together 2 permit functions
561−-- that decides which messages to be logged
572+permitAND :: PermitFunc -> PermitFunc -> PermitFunc
562−type PermitFunc = forall a. Item a -> IO Bool
573+permitAND f1 f2 = \a -> liftA2 (&&) (f1 a) (f2 a)
575+-- | OR together 2 permit functions
576+permitOR :: PermitFunc -> PermitFunc -> PermitFunc
577+permitOR f1 f2 = \a -> liftA2 (||) (f1 a) (f2 a)
565data Scribe = Scribe {
580data Scribe = Scribe {
566 liPush :: forall a. LogItem a => Item a -> IO ()
581 liPush :: forall a. LogItem a => Item a -> IO ()
582+ -- ^ How do we write an item to the scribe's output?
567 , scribeFinalizer :: IO ()
583 , scribeFinalizer :: IO ()
568− -- ^ Provide a *blocking* finalizer to call when your scribe is
584+ -- ^ Provide a __blocking__ finalizer to call when your scribe is
585+ -- removed. All pending writes should be flushed synchronously. If
569− -- removed. If this is not relevant to your scribe, return () is
586+ -- this is not relevant to your scribe, return () is fine.
571 , scribePermitItem :: PermitFunc
587 , scribePermitItem :: PermitFunc
572− -- ^ Provide a filtering function to allow the item to be logged, or not.
588+ -- ^ Provide a filtering function to allow the item to be logged,
573− -- It can check Severity or some string in item's body.
589+ -- or not. It can check Severity or some string in item's
590+ -- body. The initial value of this is usually created from
591+ -- 'permitItem'. Scribes and users can customize this by ANDing
592+ -- or ORing onto the default with 'permitAND' or 'permitOR'
576whenM :: Monad m => m Bool -> m () -> m ()
596whenM :: Monad m => m Bool -> m () -> m ()
577whenM mbool = (>>=) mbool . flip when
597whenM mbool = (>>=) mbool . flip when
600+-- | Combine two scribes. Publishes to the left scribe if the left
601+-- would permit the item and to the right scribe if the right would
602+-- permit the item. Finalizers are called in sequence from left to
579instance Semigroup Scribe where
604instance Semigroup Scribe where
580 (Scribe pushA finA permitA) <> (Scribe pushB finB permitB) =
605 (Scribe pushA finA permitA) <> (Scribe pushB finB permitB) =
581 Scribe (\item -> whenM (permitA item) (pushA item)
606 Scribe (\item -> whenM (permitA item) (pushA item)
582 >> whenM (permitB item) (pushB item)
607 >> whenM (permitB item) (pushB item)
584 (finA `finally` finB)
609 (finA `finally` finB)
585− (\item -> (||) <$> permitA item <*> permitB item)
610+ (permitOR permitA permitB)
588instance Monoid Scribe where
613instance Monoid Scribe where
@@ -605,8 +630,9 @@ data WorkerMessage where
606-------------------------------------------------------------------------------
631-------------------------------------------------------------------------------
607-- | Should this item be logged given the user's maximum severity?
632-- | Should this item be logged given the user's maximum severity?
633+-- Most new scribes will use this as a base for their 'PermitFunc'
608permitItem :: Monad m => Severity -> Item a -> m Bool
634permitItem :: Monad m => Severity -> Item a -> m Bool
609−permitItem sev Item{..} = return $ _itemSeverity >= sev
635+permitItem sev item = return (_itemSeverity item >= sev)
612-------------------------------------------------------------------------------
638-------------------------------------------------------------------------------
@@ -652,7 +678,9 @@ initLogEnv an env = LogEnv
653-------------------------------------------------------------------------------
679-------------------------------------------------------------------------------
654-- | Add a scribe to the list. All future log calls will go to this
680-- | Add a scribe to the list. All future log calls will go to this
655−-- scribe in addition to the others.
681+-- scribe in addition to the others. Writes will be buffered per the
682+-- ScribeSettings to prevent slow scribes from slowing down
683+-- logging. Writes will be dropped if the buffer fills.
656registerScribe
684registerScribe
658 -- ^ Name the scribe
686 -- ^ Name the scribe
@@ -705,7 +733,7 @@ defaultScribeSettings = ScribeSettings 4096
707-------------------------------------------------------------------------------
735-------------------------------------------------------------------------------
708−-- | Remove a scribe from the environment. This does *not* finalize
736+-- | Remove a scribe from the environment. This does __not__ finalize
709-- the scribe. This mainly only makes sense to use with something like
737-- the scribe. This mainly only makes sense to use with something like
710-- MonadReader's @local@ function to temporarily disavow a single
738-- MonadReader's @local@ function to temporarily disavow a single
711-- logger for a block of code.
739-- logger for a block of code.
@@ -718,7 +746,7 @@ unregisterScribe nm = logEnvScribes %~ M.delete nm
720-------------------------------------------------------------------------------
748-------------------------------------------------------------------------------
721−-- | Unregister *all* scribes. Note that this is *not* for closing or
749+-- | Unregister __all__ scribes. Note that this is __not__ for closing or
722-- finalizing scribes, use 'closeScribes' for that. This mainly only
750-- finalizing scribes, use 'closeScribes' for that. This mainly only
723-- makes sense to use with something like MonadReader's @local@
751-- makes sense to use with something like MonadReader's @local@
724-- function to temporarily disavow any loggers for a block of code.
752-- function to temporarily disavow any loggers for a block of code.
@@ -730,9 +758,10 @@ clearScribes = logEnvScribes .~ mempty
731-------------------------------------------------------------------------------
759-------------------------------------------------------------------------------
732-- | Finalize a scribe. The scribe is removed from the environment,
760-- | Finalize a scribe. The scribe is removed from the environment,
733−-- its finalizer is called and it can never be written to again. Note
761+-- its finalizer is called so that it can never be written to again
762+-- and all pending writes are flushed. Note that this will throw any
734−-- that this will throw any exceptions yoru finalizer will throw, and
763+-- exceptions yoru finalizer will throw, and that LogEnv is immutable,
735−-- that LogEnv is immutable, so it will not be removed in that case.
764+-- so it will not be removed in that case.
736closeScribe
765closeScribe
738 -- ^ Name of the scribe
767 -- ^ Name of the scribe
@@ -927,6 +956,7 @@ tryWriteTBQueue q a = do
927 unless full (writeTBQueue q a)
956 unless full (writeTBQueue q a)
928 return (not full)
957 return (not full)
930-------------------------------------------------------------------------------
960-------------------------------------------------------------------------------
931-- | Log with full context, but without any code location.
961-- | Log with full context, but without any code location.