@@ -25,6 +25,7 @@ module Cardano.Unlog.LogObject
25
25
, logObjectStreamInterpreterKeys
26
26
, LOBody (.. )
27
27
, LOAnyType (.. )
28
+ , textRefEquals
28
29
)
29
30
where
30
31
@@ -36,6 +37,7 @@ import qualified Data.Aeson.Key as Aeson
36
37
import qualified Data.Aeson.KeyMap as KeyMap
37
38
import Data.Aeson.Types (Parser )
38
39
import qualified Data.ByteString.Lazy as LBS
40
+ import Data.Hashable (hash )
39
41
import qualified Data.Map.Strict as Map
40
42
import qualified Data.Text as LText
41
43
import Data.Text.Short (ShortText , fromText , toText )
@@ -54,6 +56,53 @@ import Cardano.Util
54
56
55
57
type Text = ShortText
56
58
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
+
57
106
-- | Input data.
58
107
data HostLogs a
59
108
= HostLogs
@@ -128,7 +177,7 @@ readLogObjectStream f okDErr loAnyLimit =
128
177
fmap (\ bs ->
129
178
AE. eitherDecode bs &
130
179
either
131
- (LogObject zeroUTCTime " Cardano.Analysis.DecodeError" " DecodeError" " " (TId " 0" )
180
+ (LogObject zeroUTCTime ( TextLit " Cardano.Analysis.DecodeError" ) ( TextLit " DecodeError" ) " " (TId " 0" )
132
181
. LODecodeError (Text. fromByteString (LBS. toStrict bs)
133
182
& fromMaybe " #<ERROR decoding input fromByteString>" )
134
183
. Text. fromText
@@ -143,8 +192,8 @@ readLogObjectStream f okDErr loAnyLimit =
143
192
data LogObject
144
193
= LogObject
145
194
{ loAt :: ! UTCTime
146
- , loNS :: ! Text
147
- , loKind :: ! Text
195
+ , loNS :: ! TextRef
196
+ , loKind :: ! TextRef
148
197
, loHost :: ! Host
149
198
, loTid :: ! TId
150
199
, loBody :: ! LOBody
@@ -348,6 +397,8 @@ interpreters = map3ple Map.fromList . unzip3 . fmap ent $
348
397
map3ple :: (a -> b ) -> (a ,a ,a ) -> (b ,b ,b )
349
398
map3ple f (x,y,z) = (f x, f y, f z)
350
399
400
+
401
+
351
402
logObjectStreamInterpreterKeysLegacy , logObjectStreamInterpreterKeys :: [Text ]
352
403
logObjectStreamInterpreterKeysLegacy =
353
404
logObjectStreamInterpreterKeysLegacy1 <> logObjectStreamInterpreterKeysLegacy2
@@ -457,8 +508,8 @@ instance FromJSON LogObject where
457
508
" The 'ns' field must be either a string, or a singleton-String vector, was: " <> show x
458
509
LogObject
459
510
<$> v .: " at"
460
- <*> pure ns
461
- <*> pure kind
511
+ <*> pure (toTextRef ns)
512
+ <*> pure (toTextRef kind)
462
513
<*> v .: " host"
463
514
<*> v .: " thread"
464
515
<*> case Map. lookup ns (thd3 interpreters)
0 commit comments