@@ -2,6 +2,9 @@
22module Control.Logger
33 ( Logger
44 , loggerContext
5+ , scrubber
6+ , censor
7+ , censorWith
58 , logMsg
69 , logMsgWith
710 , logInfo
@@ -32,13 +35,20 @@ module Control.Logger
3235 , compactCallStack
3336 , st
3437 , ToObject(..)
38+ , withScrubber
39+ , censoringWith
40+ , censoring
3541 ) where
3642
3743import Control.Has
44+import Control.Lens hiding (censoring)
3845import Control.Logger.Internal
3946import Control.Logger.Orphans ()
47+import Control.Monad
4048import Control.Monad.Catch
49+import Control.Monad.IO.Class
4150import qualified Data.List as List
51+import Data.Monoid
4252import Data.Text (Text)
4353import qualified Data.Text as Text
4454import Data.Time
@@ -46,10 +56,6 @@ import GHC.Stack
4656import Katip (ToObject (..))
4757import System.Log.FastLogger
4858import Text.Shakespeare.Text (st)
49−#if MIN_VERSION_base(4,18,0)
50−import Control.Monad
51−#else
52−#endif
5359
5460logError
5561 :: (LoggingMonad r m)
@@ -103,6 +109,50 @@ logErrorWith
103109 -> m ()
104110logErrorWith logger msg = withFrozenCallStack (logMsgWith logger Error msg)
105111
112+safeReplace :: Text -> Text -> Text -> Text
113+safeReplace what with where_
114+ | Text.null what = where_
115+ | otherwise = Text.replace what with where_
116+
117+-- | Add a some text to scrubber
118+censorWith :: Text -> Text -> Logger -> Logger
119+censorWith replacement needle l =
120+ l & scrubber <>~ Endo (safeReplace needle replacement)
121+
122+-- | Censor with "***"
123+censor :: Text -> Logger -> Logger
124+censor = censorWith "***"
125+
126+-- | Run an action with adjusted scrubber
127+withScrubber
128+ :: forall r m a. (Has Logger r, MonadReader r m)
129+ => (Endo Text -> Endo Text)
130+ -> m a
131+ -> m a
132+withScrubber scrubF = local expandScrubber
133+ where
134+ expandScrubber :: r -> r
135+ expandScrubber = over part (over scrubber scrubF)
136+
137+-- | Run an action while censoring additional text from logs
138+censoringWith
139+ :: (Has Logger r, MonadReader r m)
140+ => Text
141+ -> Text
142+ -> m a
143+ -> m a
144+censoringWith replacement txt = withScrubber (<> censored)
145+ where
146+ censored = Endo (safeReplace txt replacement)
147+
148+-- | Run an action while censoring additional text from logs
149+censoring
150+ :: (Has Logger r, MonadReader r m)
151+ => Text
152+ -> m a
153+ -> m a
154+censoring = censoringWith "***"
155+
106156-- | Log exceptions occured in computation and just ignore them.
107157tryLogError
108158 :: (MonadIO m, MonadCatch m, Has Logger r, MonadReader r m)
@@ -153,14 +203,14 @@ fileLogger :: MonadIO m => FilePath -> m Logger
153203fileLogger fp = fastFunc <$> liftIO (newFileLoggerSet defaultBufSize fp)
154204
155205silentLogger :: Logger
156−silentLogger = Logger mempty (\_ _ _ _ -> return ())
206+silentLogger = Logger mempty mempty (\_ _ _ _ -> return ())
157207
158208-- | Logger which flushes buffer after each message. This is useful with
159209-- stderrLogger.
160210flushingFastFunc
161211 :: LogSeverity -> LoggerSet -> Logger
162212flushingFastFunc minLogLevel loggerSet =
163− Logger mempty $ \_ stack logLevel msg ->
213+ Logger mempty mempty $ \_ stack logLevel msg ->
164214 when (logLevel >= minLogLevel) $ do
165215 ts <- getCurrentTime
166216 pushLogStr loggerSet
@@ -184,14 +234,14 @@ flushingStderrLogger =
184234-- | Make our outdated 'Logger' of fast-logger's 'LoggerSet'
185235fastFunc :: LoggerSet -> Logger
186236fastFunc loggerSet =
187− Logger mempty $ \_ _ _ msg -> pushLogStr loggerSet $ toLogStr msg
237+ Logger mempty mempty $ \_ _ _ msg -> pushLogStr loggerSet $ toLogStr msg
188238
189239type LogSource = Text
190240
191241-- | Default logger tests and same things.
192242defaultFastFunc :: LogSource -> LogSeverity -> LoggerSet -> Logger
193243defaultFastFunc loc minLogLevel loggerSet =
194− Logger mempty $ \_ stack s msg -> when (s >= minLogLevel) $ do
244+ Logger mempty mempty $ \_ stack s msg -> when (s >= minLogLevel) $ do
195245 ts <- getCurrentTime
196246 pushLogStr loggerSet $ formatLogStr ts stack loc s (toLogStr msg)
197247