Skip to content

Commit e64ad42

Browse files
committed
Add setLoggerReformat
This refactors the contract between `reformatTerminal` and the construction that happens in `newLogger`. Previously, we constructed `lReformat` directly, which is a function of only `LogLevel` and `ByteString`. This meant that a "reformat" function such as `reformatTerminal` had to do some extra work that all such functions would have to do: - Construct the `Colors` value if needed - Return that `ByteString` as-is if it doesn't parse as `LoggedMessage` We can pull both of these responsibilities out into `newLogger` itself and simplify `reformatTerminal` by giving it what it needs directly. Also, by passing `LogSettings` entirely (instead of just the breakpoint), we've now made its signature into something that works well as a generic "reformat" interface. Then, by putting that logic behind a `setLoggerReformat` that `newLogger` uses internally, we give users a hook for assign any such "reformat" function from the outside too: ```hs main :: IO () main = do withLoggerEnv $ \logger -> do let app = App $ setLoggerReformat myReformat logger runAppM app -- ... myReformat :: LogSettings -> Colors -> LogLevel -> LoggedMessage -> ByteString myReformat = undefined ``` An extension like this doesn't interact with `LOG_FORMAT`, which may be surprising, but it works well for situations that don't need to be runtime-dynamic like that, such as CLIs.
1 parent a3ab781 commit e64ad42

File tree

3 files changed

+150
-143
lines changed

3 files changed

+150
-143
lines changed

Blammo/src/Blammo/Logging/Logger.hs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Blammo.Logging.Logger
88
, pushLoggerLn
99
, getLoggerLogSettings
1010
, getLoggerReformat
11+
, setLoggerReformat
1112
, getLoggerShouldLog
1213
, getLoggerShouldColor
1314
, pushLogStrLn
@@ -24,6 +25,7 @@ module Blammo.Logging.Logger
2425

2526
import Prelude
2627

28+
import Blammo.Logging.Colors (Colors, getColors)
2729
import Blammo.Logging.Internal.Logger
2830
import Blammo.Logging.LogSettings
2931
import Blammo.Logging.Terminal
@@ -34,9 +36,11 @@ import Control.Monad (unless, when)
3436
import Control.Monad.IO.Class (MonadIO (..))
3537
import Control.Monad.Logger.Aeson
3638
import Control.Monad.Reader (MonadReader)
39+
import qualified Data.Aeson as Aeson
3740
import Data.ByteString (ByteString)
3841
import Data.Either (partitionEithers, rights)
3942
import Data.List (intercalate)
43+
import Data.Maybe (fromMaybe)
4044
import Data.Text (Text)
4145
import GHC.Stack (HasCallStack)
4246
import System.IO (stderr, stdout)
@@ -89,6 +93,17 @@ getLoggerLoggerSet = lLoggerSet
8993
getLoggerReformat :: Logger -> LogLevel -> ByteString -> ByteString
9094
getLoggerReformat = lReformat
9195

96+
setLoggerReformat
97+
:: (LogSettings -> Colors -> LogLevel -> LoggedMessage -> ByteString)
98+
-> Logger
99+
-> Logger
100+
setLoggerReformat f logger =
101+
logger
102+
{ lReformat = \level bytes -> fromMaybe bytes $ do
103+
lm <- Aeson.decodeStrict bytes
104+
pure $ f (lLogSettings logger) (getColors $ lShouldColor logger) level lm
105+
}
106+
92107
getLoggerShouldLog :: Logger -> LogSource -> LogLevel -> Bool
93108
getLoggerShouldLog = lShouldLog
94109

@@ -133,18 +148,20 @@ newLogger settings = do
133148
<$> newFileLoggerSetN defaultBufSize concurrency path
134149
<*> shouldColorAuto settings (pure False)
135150

136-
let
137-
lReformat = case getLogSettingsFormat settings of
138-
LogFormatJSON -> const id -- breakpoint and color ignored
139-
LogFormatTerminal -> reformatTerminal breakpoint lShouldColor
140-
141-
lShouldLog = shouldLogLevel settings
142-
lLoggedMessages = Nothing
143-
lLogSettings = settings
144-
145-
pure $ Logger {..}
151+
let logger =
152+
Logger
153+
{ lLogSettings = settings
154+
, lLoggerSet = lLoggerSet
155+
, lReformat = const id -- By default render (JSON) bytestring as-is
156+
, lShouldLog = shouldLogLevel settings
157+
, lShouldColor = lShouldColor
158+
, lLoggedMessages = Nothing
159+
}
160+
161+
pure $ case getLogSettingsFormat settings of
162+
LogFormatJSON -> logger
163+
LogFormatTerminal -> setLoggerReformat reformatTerminal logger
146164
where
147-
breakpoint = getLogSettingsBreakpoint settings
148165
concurrency = getLogSettingsConcurrency settings
149166

150167
flushLogger :: (MonadIO m, MonadReader env m, HasLogger env) => m ()

Blammo/src/Blammo/Logging/Terminal.hs

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Blammo.Logging.Terminal
2020
import Prelude
2121

2222
import Blammo.Logging.Colors
23+
import Blammo.Logging.LogSettings (LogSettings, getLogSettingsBreakpoint)
2324
import Blammo.Logging.Terminal.LogPiece (LogPiece, logPiece)
2425
import qualified Blammo.Logging.Terminal.LogPiece as LogPiece
2526
import Control.Monad.Logger.Aeson
@@ -28,68 +29,64 @@ import Data.Aeson.Compat (KeyMap)
2829
import qualified Data.Aeson.Compat as Key
2930
import qualified Data.Aeson.Compat as KeyMap
3031
import Data.ByteString (ByteString)
31-
import qualified Data.ByteString.Lazy as BSL
3232
import Data.List (sortOn)
3333
import Data.Maybe (fromMaybe)
3434
import Data.Text (Text, pack)
3535
import qualified Data.Text as T
3636
import Data.Time (defaultTimeLocale, formatTime)
3737
import qualified Data.Vector as V
3838

39-
reformatTerminal :: Int -> Bool -> LogLevel -> ByteString -> ByteString
40-
reformatTerminal breakpoint useColor logLevel bytes = fromMaybe bytes $ do
41-
LoggedMessage {..} <- decode $ BSL.fromStrict bytes
42-
43-
let
44-
colors@Colors {..} = getColors useColor
45-
46-
logTimestampPiece =
47-
logPiece dim $
48-
pack $
49-
formatTime
50-
defaultTimeLocale
51-
"%F %X"
52-
loggedMessageTimestamp
53-
54-
logLevelPiece = case logLevel of
55-
LevelDebug -> logPiece gray $ padTo 9 "debug"
56-
LevelInfo -> logPiece green $ padTo 9 "info"
57-
LevelWarn -> logPiece yellow $ padTo 9 "warn"
58-
LevelError -> logPiece red $ padTo 9 "error"
59-
LevelOther x -> logPiece blue $ padTo 9 x
60-
61-
loggedSourceAsMap =
62-
foldMap (KeyMap.singleton "source" . String) loggedMessageLogSource
63-
64-
logPrefixPiece =
65-
logTimestampPiece <> " [" <> logLevelPiece <> "] "
66-
67-
logMessagePiece = logPiece bold $ padTo 31 loggedMessageText
68-
69-
logAttrsPiece =
70-
mconcat
71-
[ colorizeKeyMap " " colors loggedSourceAsMap
72-
, colorizeKeyMap " " colors loggedMessageThreadContext
73-
, colorizeKeyMap " " colors loggedMessageMeta
74-
]
75-
76-
oneLineLogPiece = mconcat [logPrefixPiece, logMessagePiece, logAttrsPiece]
77-
78-
multiLineLogPiece =
79-
let shift = "\n" <> LogPiece.offset (LogPiece.visibleLength logPrefixPiece)
80-
in mconcat
81-
[ logPrefixPiece
82-
, logMessagePiece
83-
, colorizeKeyMap shift colors loggedSourceAsMap
84-
, colorizeKeyMap shift colors loggedMessageThreadContext
85-
, colorizeKeyMap shift colors loggedMessageMeta
86-
]
87-
88-
pure $
89-
LogPiece.bytestring $
90-
if LogPiece.visibleLength oneLineLogPiece <= breakpoint
91-
then oneLineLogPiece
92-
else multiLineLogPiece
39+
reformatTerminal
40+
:: LogSettings -> Colors -> LogLevel -> LoggedMessage -> ByteString
41+
reformatTerminal settings colors@Colors {..} logLevel LoggedMessage {..} = do
42+
LogPiece.bytestring $
43+
if LogPiece.visibleLength oneLineLogPiece <= breakpoint
44+
then oneLineLogPiece
45+
else multiLineLogPiece
46+
where
47+
breakpoint = getLogSettingsBreakpoint settings
48+
49+
logTimestampPiece =
50+
logPiece dim $
51+
pack $
52+
formatTime
53+
defaultTimeLocale
54+
"%F %X"
55+
loggedMessageTimestamp
56+
57+
logLevelPiece = case logLevel of
58+
LevelDebug -> logPiece gray $ padTo 9 "debug"
59+
LevelInfo -> logPiece green $ padTo 9 "info"
60+
LevelWarn -> logPiece yellow $ padTo 9 "warn"
61+
LevelError -> logPiece red $ padTo 9 "error"
62+
LevelOther x -> logPiece blue $ padTo 9 x
63+
64+
loggedSourceAsMap =
65+
foldMap (KeyMap.singleton "source" . String) loggedMessageLogSource
66+
67+
logPrefixPiece =
68+
logTimestampPiece <> " [" <> logLevelPiece <> "] "
69+
70+
logMessagePiece = logPiece bold $ padTo 31 loggedMessageText
71+
72+
logAttrsPiece =
73+
mconcat
74+
[ colorizeKeyMap " " colors loggedSourceAsMap
75+
, colorizeKeyMap " " colors loggedMessageThreadContext
76+
, colorizeKeyMap " " colors loggedMessageMeta
77+
]
78+
79+
oneLineLogPiece = mconcat [logPrefixPiece, logMessagePiece, logAttrsPiece]
80+
81+
multiLineLogPiece =
82+
let shift = "\n" <> LogPiece.offset (LogPiece.visibleLength logPrefixPiece)
83+
in mconcat
84+
[ logPrefixPiece
85+
, logMessagePiece
86+
, colorizeKeyMap shift colors loggedSourceAsMap
87+
, colorizeKeyMap shift colors loggedMessageThreadContext
88+
, colorizeKeyMap shift colors loggedMessageMeta
89+
]
9390

9491
colorizeKeyMap :: LogPiece -> Colors -> KeyMap Value -> LogPiece
9592
colorizeKeyMap sep Colors {..} km

0 commit comments

Comments
 (0)