@@ -25,6 +25,7 @@ module Cardano.Unlog.LogObject
2525 , logObjectStreamInterpreterKeys
2626 , LOBody (.. )
2727 , LOAnyType (.. )
28+ , textRefEquals
2829 )
2930where
3031
@@ -36,6 +37,7 @@ import qualified Data.Aeson.Key as Aeson
3637import qualified Data.Aeson.KeyMap as KeyMap
3738import Data.Aeson.Types (Parser )
3839import qualified Data.ByteString.Lazy as LBS
40+ import Data.Hashable (hash )
3941import qualified Data.Map.Strict as Map
4042import qualified Data.Text as LText
4143import Data.Text.Short (ShortText , fromText , toText )
@@ -54,6 +56,53 @@ import Cardano.Util
5456
5557type Text = ShortText
5658
59+ -- | Us of the a TextRef replaces commonly expected string parses with references
60+ -- into a Map, reducing memory footprint - given that large runs can contain
61+ -- >25mio log objects.
62+ data TextRef
63+ = TextRef {- # UNPACK #-} !Int
64+ | TextLit {- # UNPACK #-} !Text
65+ deriving Generic
66+ deriving anyclass NFData
67+
68+ lookupTextRef :: Int -> Text
69+ lookupTextRef ref = Map. findWithDefault Text. empty ref dict
70+ where
71+ dict = Map. fromList [(hash t, t) | t <- concat [allKeys, kinds, legacy]]
72+ kinds = map (" Cardano.Node." <> ) allKeys
73+ legacy = map (" cardano.node." <> )
74+ [ " BlockFetchClient"
75+ , " BlockFetchServer"
76+ , " ChainDB"
77+ , " ChainSyncClient"
78+ , " ChainSyncHeaderServer"
79+ , " DnsSubscription"
80+ , " Forge"
81+ , " IpSubscription"
82+ , " LeadershipCheck"
83+ , " Mempool"
84+ , " resources"
85+ , " TxInbound"
86+ ]
87+ allKeys =
88+ concatMap Map. keys [fst3 interpreters, snd3 interpreters, thd3 interpreters]
89+ & filter (not . Text. null )
90+
91+ toTextRef :: Text -> TextRef
92+ toTextRef t = let h = hash t in if Text. null (lookupTextRef h) then TextLit t else TextRef h
93+
94+ textRefEquals :: TextRef -> Text -> Bool
95+ textRefEquals (TextRef i) = (== lookupTextRef i)
96+ textRefEquals (TextLit t) = (== t)
97+
98+ instance Show TextRef where
99+ show (TextRef i) = show $ lookupTextRef i
100+ show (TextLit t) = show t
101+
102+ instance ToJSON TextRef where
103+ toJSON (TextRef i) = toJSON $ lookupTextRef i
104+ toJSON (TextLit t) = toJSON t
105+
57106-- | Input data.
58107data HostLogs a
59108 = HostLogs
@@ -128,7 +177,7 @@ readLogObjectStream f okDErr loAnyLimit =
128177 fmap (\ bs ->
129178 AE. eitherDecode bs &
130179 either
131- (LogObject zeroUTCTime " Cardano.Analysis.DecodeError" " DecodeError" " " (TId " 0" )
180+ (LogObject zeroUTCTime ( TextLit " Cardano.Analysis.DecodeError" ) ( TextLit " DecodeError" ) " " (TId " 0" )
132181 . LODecodeError (Text. fromByteString (LBS. toStrict bs)
133182 & fromMaybe " #<ERROR decoding input fromByteString>" )
134183 . Text. fromText
@@ -143,8 +192,8 @@ readLogObjectStream f okDErr loAnyLimit =
143192data LogObject
144193 = LogObject
145194 { loAt :: ! UTCTime
146- , loNS :: ! Text
147- , loKind :: ! Text
195+ , loNS :: ! TextRef
196+ , loKind :: ! TextRef
148197 , loHost :: ! Host
149198 , loTid :: ! TId
150199 , loBody :: ! LOBody
@@ -348,6 +397,8 @@ interpreters = map3ple Map.fromList . unzip3 . fmap ent $
348397 map3ple :: (a -> b ) -> (a ,a ,a ) -> (b ,b ,b )
349398 map3ple f (x,y,z) = (f x, f y, f z)
350399
400+
401+
351402logObjectStreamInterpreterKeysLegacy , logObjectStreamInterpreterKeys :: [Text ]
352403logObjectStreamInterpreterKeysLegacy =
353404 logObjectStreamInterpreterKeysLegacy1 <> logObjectStreamInterpreterKeysLegacy2
@@ -457,8 +508,8 @@ instance FromJSON LogObject where
457508 " The 'ns' field must be either a string, or a singleton-String vector, was: " <> show x
458509 LogObject
459510 <$> v .: " at"
460- <*> pure ns
461- <*> pure kind
511+ <*> pure (toTextRef ns)
512+ <*> pure (toTextRef kind)
462513 <*> v .: " host"
463514 <*> v .: " thread"
464515 <*> case Map. lookup ns (thd3 interpreters)
0 commit comments