on master help sign in
Move ThreadId prefix out of JSON newtype and into handle scribe

My reasoning here is that it makes sense in the bracketed handle scribe to differentiate these random looking numbers next to eachother as PID and ThreadId, respectively. Moving it out of the newtype means backends like elasticsearch and datadog don't log it wiith the extra "ThreadId " prefix, which is unnecessary because the log data id structured and identifies the field with the key name.

commitc2ce898777c6aa477acdf9663592ae0915ca433e authorMichael Xavier <michael@michaelxavier.net> dateWed 9 Jan 2019, 13:20 (8 years ago) parentf9ccb80
5 files changed+95−84
katip-datadog/test/Katip/Tests/Scribes/Datadog/TCP.hs+16−9 katip/src/Katip/Core.hs+31−27 katip/src/Katip/Scribes/Handle.hs+8−8 katip/test/Katip/Tests/Scribes/Handle-text.golden+38−38 katip/test/Katip/Tests/Scribes/Handle.hs+2−2
katip-datadog/test/Katip/Tests/Scribes/Datadog/TCP.hs+16−9
@@ -8,6 +8,7 @@ module Katip.Tests.Scribes.Datadog.TCP
88import Control.Concurrent.Async
99import qualified Control.Exception.Safe as EX
1010import qualified Data.Aeson as A
11+import qualified Data.Char as Char
1112import qualified Data.Conduit as C
1213import qualified Data.Conduit.Binary as CB
1314import qualified Data.Conduit.List as CL
@@ -16,7 +17,8 @@ import Data.Foldable (toList)
1617import qualified Data.HashMap.Strict as HM
1718import Data.IORef
1819import Data.Sequence ((|>))
19−import Data.Text
20+import Data.Text (Text)
21+import qualified Data.Text as T
2022import Test.Tasty
2123import Test.Tasty.HUnit
2224-------------------------------------------------------------------------------
@@ -31,14 +33,15 @@ tests = testGroup "Katip.Scribes.Datadog.TCP"
3133 [ testCase "logs well-formed messages in order" $ do
3234 logs <- collectLogs $ do
3335 logItem (sl "foo" ("bar" :: Text)) "mynamespace" noLoc InfoS "a message"
34− logs @?=
35− [ CapturedLog
36− { capturedLog_namespace = Namespace ["katip-datadog-tests", "mynamespace"]
37− , capturedLog_data = A.Object (HM.singleton "foo" (A.String "bar"))
38− , capturedLog_sev = InfoS
39− , capturedLog_message = "a message"
40− }
41− ]
36+ length logs @?= 1
37+ let (CapturedLog ns dta sev msg thread) = head logs
38+ ns @?= Namespace ["katip-datadog-tests", "mynamespace"]
39+ dta @?= A.Object (HM.singleton "foo" (A.String "bar"))
40+ sev @?= InfoS
41+ msg @?= "a message"
42+ if T.all Char.isNumber thread && T.length thread > 0
43+ then pure ()
44+ else assertFailure ("Expected thread id to just be a number but it was " <> T.unpack thread)
4245 ]
4346 where
4447 noLoc = Nothing
@@ -51,6 +54,7 @@ data CapturedLog = CapturedLog
5154 , capturedLog_data :: A.Value
5255 , capturedLog_sev :: Severity
5356 , capturedLog_message :: Text
57+ , capturedLog_thread :: Text
5458 } deriving (Show, Eq)
5559
5660
@@ -60,13 +64,16 @@ instance A.FromJSON CapturedLog where
6064 sev <- o A..: "severity"
6165 dta <- o A..: "data"
6266 namespace <- o A..: "ns"
67+ thread <- o A..: "thread"
6368 pure $ CapturedLog
6469 { capturedLog_namespace = namespace
6570 , capturedLog_data = dta
6671 , capturedLog_sev = sev
6772 , capturedLog_message = message
73+ , capturedLog_thread = thread
6874 }
6975
76+
7077-------------------------------------------------------------------------------
7178collectLogs :: KatipT IO () -> IO [CapturedLog]
7279collectLogs f = do
katip/src/Katip/Core.hs+31−27
@@ -22,14 +22,14 @@
2222module Katip.Core where
2323
2424-------------------------------------------------------------------------------
25−import Control.Applicative as A
25+import Control.Applicative as A
2626import Control.AutoUpdate
2727import Control.Concurrent
28−import qualified Control.Concurrent.Async as Async
28+import qualified Control.Concurrent.Async as Async
2929import Control.Concurrent.STM
30−import qualified Control.Concurrent.STM.TBQueue as BQ
30+import qualified Control.Concurrent.STM.TBQueue as BQ
3131import Control.Exception.Safe
32−import Control.Monad (unless, void, when)
32+import Control.Monad (unless, void, when)
3333import Control.Monad.Base
3434import Control.Monad.IO.Class
3535import Control.Monad.IO.Unlift
@@ -41,28 +41,30 @@ import Control.Monad.Trans.Either
4141import Control.Monad.Trans.Except
4242import Control.Monad.Trans.Maybe
4343import Control.Monad.Trans.Reader
44−import Control.Monad.Trans.Resource (ResourceT, transResourceT)
45−import Control.Monad.Trans.State.Lazy (StateT, mapStateT)
46−import qualified Control.Monad.Trans.State.Strict as Strict (StateT, mapStateT)
47−import Control.Monad.Trans.Writer.Lazy (WriterT, mapWriterT)
48−import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT, mapWriterT)
49−import Control.Monad.Trans.RWS.Lazy (RWST, mapRWST)
50−import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
51−import Data.Aeson (FromJSON (..), ToJSON (..),
52− object)
53−import qualified Data.Aeson as A
54−import Data.Foldable as FT
55−import qualified Data.HashMap.Strict as HM
44+import Control.Monad.Trans.Resource (ResourceT, transResourceT)
45+import Control.Monad.Trans.RWS.Lazy (RWST, mapRWST)
46+import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
47+import Control.Monad.Trans.State.Lazy (StateT, mapStateT)
48+import qualified Control.Monad.Trans.State.Strict as Strict (StateT, mapStateT)
49+import Control.Monad.Trans.Writer.Lazy (WriterT, mapWriterT)
50+import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT,
51+ mapWriterT)
52+import Data.Aeson (FromJSON (..), ToJSON (..),
53+ object)
54+import qualified Data.Aeson as A
55+import Data.Foldable as FT
56+import qualified Data.HashMap.Strict as HM
5657import Data.List
57−import qualified Data.Map.Strict as M
58−import Data.Semigroup as SG
58+import qualified Data.Map.Strict as M
59+import Data.Maybe (fromMaybe)
60+import Data.Semigroup as SG
5961import Data.String
6062import Data.String.Conv
61−import Data.Text (Text)
62−import qualified Data.Text as T
63−import qualified Data.Text.Lazy.Builder as B
63+import Data.Text (Text)
64+import qualified Data.Text as T
65+import qualified Data.Text.Lazy.Builder as B
6466import Data.Time
65−import GHC.Generics hiding (to)
67+import GHC.Generics hiding (to)
6668#if MIN_VERSION_base(4, 8, 0)
6769#if !MIN_VERSION_base(4, 9, 0)
6870import GHC.SrcLoc
@@ -70,7 +72,7 @@ import GHC.SrcLoc
7072import GHC.Stack
7173#endif
7274import Language.Haskell.TH
73−import qualified Language.Haskell.TH.Syntax as TH
75+import qualified Language.Haskell.TH.Syntax as TH
7476import Lens.Micro
7577import Lens.Micro.TH
7678import Network.HostName
@@ -244,7 +246,9 @@ newtype ThreadIdText = ThreadIdText {
244246
245247
246248mkThreadIdText :: ThreadId -> ThreadIdText
247−mkThreadIdText = ThreadIdText . T.pack . show
249+mkThreadIdText = ThreadIdText . stripPrefix' "ThreadId " . T.pack . show
250+ where
251+ stripPrefix' pfx t = fromMaybe t (T.stripPrefix pfx t)
248252
249253
250254-------------------------------------------------------------------------------
@@ -578,9 +582,9 @@ permitOR f1 f2 = \a -> liftA2 (||) (f1 a) (f2 a)
578582
579583
580584data Scribe = Scribe {
581− liPush :: forall a. LogItem a => Item a -> IO ()
585+ liPush :: forall a. LogItem a => Item a -> IO ()
582586 -- ^ How do we write an item to the scribe's output?
583− , scribeFinalizer :: IO ()
587+ , scribeFinalizer :: IO ()
584588 -- ^ Provide a __blocking__ finalizer to call when your scribe is
585589 -- removed. All pending writes should be flushed synchronously. If
586590 -- this is not relevant to your scribe, return () is fine.
@@ -618,7 +622,7 @@ instance Monoid Scribe where
618622-------------------------------------------------------------------------------
619623data ScribeHandle = ScribeHandle {
620624 shScribe :: Scribe
621− , shChan :: BQ.TBQueue WorkerMessage
625+ , shChan :: BQ.TBQueue WorkerMessage
622626 }
623627
624628
katip/src/Katip/Scribes/Handle.hs+8−8
@@ -56,9 +56,9 @@ data ColorStrategy
5656-- and other information will be flattened out into bracketed
5757-- fields. For example:
5858--
59−-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:32:7] Started
60−-- > [2016-05-11 21:01:15][MyApp.confrabulation][Debug][myhost.example.com][1724][ThreadId 1154][confrab_factor:42.0][main:Helpers.Logging Helpers/Logging.hs:41:9] Confrabulating widgets, with extra namespace and context
61−-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:43:7] Namespace and context are back to normal
59+-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][PID 1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:32:7] Started
60+-- > [2016-05-11 21:01:15][MyApp.confrabulation][Debug][myhost.example.com][PID 1724][ThreadId 1154][confrab_factor:42.0][main:Helpers.Logging Helpers/Logging.hs:41:9] Confrabulating widgets, with extra namespace and context
61+-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][PID 1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:43:7] Namespace and context are back to normal
6262--
6363-- Returns the newly-created `Scribe`. The finalizer flushes the
6464-- handle. Handle mode is set to 'LineBuffering' automatically.
@@ -117,17 +117,17 @@ formatItem = bracketFormat
117117-- | A traditional 'bracketed' log format. Contexts and other information will
118118-- be flattened out into bracketed fields. For example:
119119--
120−-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:32:7] Started
121−-- > [2016-05-11 21:01:15][MyApp.confrabulation][Debug][myhost.example.com][1724][ThreadId 1154][confrab_factor:42.0][main:Helpers.Logging Helpers/Logging.hs:41:9] Confrabulating widgets, with extra namespace and context
122−-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:43:7] Namespace and context are back to normal
120+-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][PID 1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:32:7] Started
121+-- > [2016-05-11 21:01:15][MyApp.confrabulation][Debug][myhost.example.com][PID 1724][ThreadId 1154][confrab_factor:42.0][main:Helpers.Logging Helpers/Logging.hs:41:9] Confrabulating widgets, with extra namespace and context
122+-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][PID 1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:43:7] Namespace and context are back to normal
123123bracketFormat :: LogItem a => ItemFormatter a
124124bracketFormat withColor verb Item{..} =
125125 brackets nowStr <>
126126 brackets (mconcat $ map fromText $ intercalateNs _itemNamespace) <>
127127 brackets (fromText (renderSeverity' _itemSeverity)) <>
128128 brackets (fromString _itemHost) <>
129− brackets (fromString (show _itemProcess)) <>
130− brackets (fromText (getThreadIdText _itemThread)) <>
129+ brackets ("PID " <> fromString (show _itemProcess)) <>
130+ brackets ("ThreadId " <> fromText (getThreadIdText _itemThread)) <>
131131 mconcat ks <>
132132 maybe mempty (brackets . fromString . locationToString) _itemLoc <>
133133 fromText " " <> (unLogStr _itemMessage)
katip/test/Katip/Tests/Scribes/Handle-text.golden+38−38
@@ -1,40 +1,40 @@
1−[2016-06-12 12:34:56][foo][Debug][example][7331][1337][note.deep:some note] message
2−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
3−[2016-06-12 12:34:56][foo][Notice][example][7331][1337][note.deep:some note] message
4−[2016-06-12 12:34:56][foo][Warning][example][7331][1337][note.deep:some note] message
5−[2016-06-12 12:34:56][foo][Error][example][7331][1337][note.deep:some note] message
6−[2016-06-12 12:34:56][foo][Critical][example][7331][1337][note.deep:some note] message
7−[2016-06-12 12:34:56][foo][Alert][example][7331][1337][note.deep:some note] message
8−[2016-06-12 12:34:56][foo][Emergency][example][7331][1337][note.deep:some note] message
9−[2016-06-12 12:34:56][foo][Info][example][7331][0][note.deep:some note] message
10−[2016-06-12 12:34:56][foo][Info][example][7331][1][note.deep:some note] message
11−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
12−[2016-06-12 12:34:56][foo][Info][example][7331][2147483647][note.deep:some note] message
13−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
14−[2016-06-12 12:34:56][foo][Info][www.example.com][7331][1337][note.deep:some note] message
15−[2016-06-12 12:34:56][foo][Info][127.0.0.1][7331][1337][note.deep:some note] message
16−[2016-06-12 12:34:56][foo][Info][example][0][1337][note.deep:some note] message
17−[2016-06-12 12:34:56][foo][Info][example][1][1337][note.deep:some note] message
18−[2016-06-12 12:34:56][foo][Info][example][1337][1337][note.deep:some note] message
19−[2016-06-12 12:34:56][foo][Info][example][2147483647][1337][note.deep:some note] message
20−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
21−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
1+[2016-06-12 12:34:56][foo][Debug][example][PID 7331][ThreadId 1337][note.deep:some note] message
2+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
3+[2016-06-12 12:34:56][foo][Notice][example][PID 7331][ThreadId 1337][note.deep:some note] message
4+[2016-06-12 12:34:56][foo][Warning][example][PID 7331][ThreadId 1337][note.deep:some note] message
5+[2016-06-12 12:34:56][foo][Error][example][PID 7331][ThreadId 1337][note.deep:some note] message
6+[2016-06-12 12:34:56][foo][Critical][example][PID 7331][ThreadId 1337][note.deep:some note] message
7+[2016-06-12 12:34:56][foo][Alert][example][PID 7331][ThreadId 1337][note.deep:some note] message
8+[2016-06-12 12:34:56][foo][Emergency][example][PID 7331][ThreadId 1337][note.deep:some note] message
9+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 0][note.deep:some note] message
10+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1][note.deep:some note] message
11+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
12+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 2147483647][note.deep:some note] message
13+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
14+[2016-06-12 12:34:56][foo][Info][www.example.com][PID 7331][ThreadId 1337][note.deep:some note] message
15+[2016-06-12 12:34:56][foo][Info][127.0.0.1][PID 7331][ThreadId 1337][note.deep:some note] message
16+[2016-06-12 12:34:56][foo][Info][example][PID 0][ThreadId 1337][note.deep:some note] message
17+[2016-06-12 12:34:56][foo][Info][example][PID 1][ThreadId 1337][note.deep:some note] message
18+[2016-06-12 12:34:56][foo][Info][example][PID 1337][ThreadId 1337][note.deep:some note] message
19+[2016-06-12 12:34:56][foo][Info][example][PID 2147483647][ThreadId 1337][note.deep:some note] message
20+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
21+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
2222with newline
23−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message
24−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] сообщение
25−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] 哈囉世界
26−[2000-01-01 00:00:00][foo][Info][example][7331][1337][note.deep:some note] message
27−[2123-12-31 23:59:59][foo][Info][example][7331][1337][note.deep:some note] message
28−[2016-10-10 01:01:05][foo][Info][example][7331][1337][note.deep:some note] message
29−[2100-12-31 12:59:10][foo][Info][example][7331][1337][note.deep:some note] message
30−[1982-01-01 12:30:00][foo][Info][example][7331][1337][note.deep:some note] message
31−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
32−[2016-06-12 12:34:56][foo.bar][Info][example][7331][1337][note.deep:some note] message
33−[2016-06-12 12:34:56][фу.бар][Info][example][7331][1337][note.deep:some note] message
23+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message a really long message
24+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] сообщение
25+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] 哈囉世界
26+[2000-01-01 00:00:00][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
27+[2123-12-31 23:59:59][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
28+[2016-10-10 01:01:05][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
29+[2100-12-31 12:59:10][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
30+[1982-01-01 12:30:00][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
31+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
32+[2016-06-12 12:34:56][foo.bar][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
33+[2016-06-12 12:34:56][фу.бар][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
3434[2016-06-12 12:34:56][with
35−newline][Info][example][7331][1337][note.deep:some note] message
36−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note] message
37−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note][main:Some.Module path/Some/Module.hs:30:1] message
38−[2016-06-12 12:34:56][foo][Info][example][7331][1337][note.deep:some note][main:Some.Module путь/Some/Module.hs:3000:9000] message
39−[2016-06-12 12:34:56][foo][Info][example][7331][1337][sub:null][text:][num:0][float:0] message
40−[2016-06-12 12:34:56][foo][Info][example][7331][1337][sub.note.deep:some note][text:note][num:10][float:5.5] message
35+newline][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
36+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note] message
37+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note][main:Some.Module path/Some/Module.hs:30:1] message
38+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][note.deep:some note][main:Some.Module путь/Some/Module.hs:3000:9000] message
39+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][sub:null][text:][num:0][float:0] message
40+[2016-06-12 12:34:56][foo][Info][example][PID 7331][ThreadId 1337][sub.note.deep:some note][text:note][num:10][float:5.5] message
katip/test/Katip/Tests/Scribes/Handle.hs+2−2
@@ -39,7 +39,7 @@ tests = testGroup "Katip.Scribes.Handle"
3939 runKatipT le $ logItem dummyLogItem "test" Nothing InfoS "wont make it in"
4040 hClose h
4141 res <- readFile path
42− let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[[:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note.deep:some note\\] test message" :: String
42+ let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[PID [:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note.deep:some note\\] test message" :: String
4343 let matches = res =~ pat
4444 assertBool (show res M.<> " did not match") matches
4545 , withResource setupFile (const (return ())) $ \setupScribe -> testCase "logs correct data to a file" $ do
@@ -48,7 +48,7 @@ tests = testGroup "Katip.Scribes.Handle"
4848 fin
4949 runKatipT le $ logItem dummyLogItem "test" Nothing InfoS "wont make it in"
5050 res <- readFile path
51− let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[[:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note.deep:some note\\] test message" :: String
51+ let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[PID [:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note.deep:some note\\] test message" :: String
5252 let matches = res =~ pat
5353 assertBool (show res <> " did not match") matches
5454 , withResource setupTempFile teardownTempFile $ \setupFn ->