@@ -20,30 +20,34 @@ module Cardano.Logging.DocuGenerator (
2020 , addLimiter
2121 , addSilent
2222 , addDocumentedNamespace
23-
2423 , DocuResult
2524 , DocTracer (.. )
2625) where
2726
2827import Cardano.Logging.ConfigurationParser ()
28+ import Cardano.Logging.DocuGenerator.RoseTree
29+ import Cardano.Logging.DocuResult (DocuResult (.. ))
30+ import qualified Cardano.Logging.DocuResult as DocuResult
2931import Cardano.Logging.Types
32+ import Cardano.Logging.Utils (indent )
3033
3134import Prelude hiding (lines , unlines )
3235
36+ import Control.Monad (mfilter )
3337import Control.Monad.IO.Class (MonadIO , liftIO )
3438import qualified Control.Tracer as TR
3539import Data.Aeson (ToJSON )
3640import qualified Data.Aeson.Encode.Pretty as AE
3741import Data.IORef (modifyIORef , newIORef , readIORef )
38- import Data.List (groupBy , intersperse , nub , sortBy )
42+ import Data.List (find , groupBy , intersperse , isPrefixOf , nub , sortBy )
3943import qualified Data.Map.Strict as Map
40- import Data.Maybe (fromMaybe , mapMaybe )
41- import Data.Text as T (Text , empty , intercalate , lines , pack , split , stripPrefix , toLower ,
44+ import Data.Maybe (fromJust , fromMaybe , mapMaybe )
45+ import Data.Text (split )
46+ import Data.Text as T (Text , empty , intercalate , lines , pack , stripPrefix , toLower ,
4247 unlines )
4348import Data.Text.Internal.Builder (toLazyText )
4449import Data.Text.Lazy (toStrict )
4550import Data.Text.Lazy.Builder (Builder , fromString , fromText , singleton )
46- import Data.Time (getZonedTime )
4751
4852import Trace.Forward.Utils.DataPoint (DataPoint (.. ))
4953
@@ -65,12 +69,6 @@ addDocumentedNamespace out (Documented list) =
6569 (\ dm@ DocMsg {} -> dm {dmNamespace = nsReplacePrefix out (dmNamespace dm)})
6670 list
6771
68- data DocuResult =
69- DocuTracer Builder
70- | DocuMetric Builder
71- | DocuDatapoint Builder
72- deriving (Show )
73-
7472data DocTracer = DocTracer {
7573 dtTracerNames :: [[Text ]]
7674 , dtSilent :: [[Text ]]
@@ -87,23 +85,6 @@ instance Semigroup DocTracer where
8785 (dtBuilderList dtl <> dtBuilderList dtr)
8886 (dtWarnings dtl <> dtWarnings dtr)
8987
90- isTracer :: DocuResult -> Bool
91- isTracer DocuTracer {} = True
92- isTracer _ = False
93-
94- isMetric :: DocuResult -> Bool
95- isMetric DocuMetric {} = True
96- isMetric _ = False
97-
98- isDatapoint :: DocuResult -> Bool
99- isDatapoint DocuDatapoint {} = True
100- isDatapoint _ = False
101-
102- unpackDocu :: DocuResult -> Builder
103- unpackDocu (DocuTracer b) = b
104- unpackDocu (DocuMetric b) = b
105- unpackDocu (DocuDatapoint b) = b
106-
10788documentTracer' :: forall a a1 .
10889 MetaTrace a
10990 => (Trace IO a1 -> IO (Trace IO a ))
@@ -186,7 +167,7 @@ documentTracer tracer = do
186167 documentMetrics' :: [( (Text , Text ) , [([Text ],[Text ])] )] -> Maybe ([Text ], DocuResult )
187168 documentMetrics' ncns@ (((name, comment), _) : _tail) =
188169 Just ([name], DocuMetric
189- $ mconcat $ intersperse(fromText " \n\n " )
170+ $ mconcat $ intersperse (fromText " \n\n " )
190171 [ metricToBuilder (name,comment)
191172 , namespacesMetricsBuilder (nub (concatMap snd ncns))
192173 ])
@@ -196,7 +177,7 @@ documentTracer tracer = do
196177 namespacesBuilder [ns] = namespaceBuilder ns
197178 namespacesBuilder [] = fromText " __Warning__: namespace missing"
198179 namespacesBuilder nsl =
199- mconcat (intersperse (singleton ' \n ' )(map namespaceBuilder nsl))
180+ mconcat (intersperse (singleton ' \n ' ) (map namespaceBuilder nsl))
200181
201182 namespaceBuilder :: ([Text ], [Text ]) -> Builder
202183 namespaceBuilder (nsPr, nsPo) = fromText " ### " <>
@@ -206,7 +187,7 @@ documentTracer tracer = do
206187 namespacesMetricsBuilder [ns] = fromText " Dispatched by: \n " <> namespaceMetricsBuilder ns
207188 namespacesMetricsBuilder [] = mempty
208189 namespacesMetricsBuilder nsl = fromText " Dispatched by: \n " <>
209- mconcat (intersperse (singleton ' \n ' )(map namespaceMetricsBuilder nsl))
190+ mconcat (intersperse (singleton ' \n ' ) (map namespaceMetricsBuilder nsl))
210191
211192 namespaceMetricsBuilder :: ([Text ], [Text ]) -> Builder
212193 namespaceMetricsBuilder (nsPr, nsPo) = mconcat (intersperse (singleton ' .' )
@@ -453,13 +434,12 @@ docItDatapoint _backend (LoggingContext {}, _) = pure ()
453434-- Finally generate a text from all the builders
454435docuResultsToText :: DocTracer -> TraceConfig -> IO Text
455436docuResultsToText dt@ DocTracer {.. } configuration = do
456- time <- getZonedTime
457437 let traceBuilders = sortBy (\ (l,_) (r,_) -> compare l r)
458- (filter (isTracer . snd ) dtBuilderList)
438+ (filter (DocuResult. isTracer . snd ) dtBuilderList)
459439 metricsBuilders = sortBy (\ (l,_) (r,_) -> compare l r)
460- (filter (isMetric . snd ) dtBuilderList)
440+ (filter (DocuResult. isMetric . snd ) dtBuilderList)
461441 datapointBuilders = sortBy (\ (l,_) (r,_) -> compare l r)
462- (filter (isDatapoint . snd ) dtBuilderList)
442+ (filter (DocuResult. isDatapoint . snd ) dtBuilderList)
463443 header = fromText " # Cardano Trace Documentation\n\n "
464444 header1 = fromText " ## Table Of Contents\n\n "
465445 toc = generateTOC dt
@@ -469,13 +449,13 @@ docuResultsToText dt@DocTracer {..} configuration = do
469449
470450 header2 = fromText " \n ## Trace Messages\n\n "
471451 contentT = mconcat $ intersperse (fromText " \n\n " )
472- (map (unpackDocu . snd ) traceBuilders)
452+ (map (DocuResult. unpackDocu . snd ) traceBuilders)
473453 header3 = fromText " \n ## Metrics\n\n "
474454 contentM = mconcat $ intersperse (fromText " \n\n " )
475- (map (unpackDocu . snd ) metricsBuilders)
455+ (map (DocuResult. unpackDocu . snd ) metricsBuilders)
476456 header4 = fromText " \n ## Datapoints\n\n "
477457 contentD = mconcat $ intersperse (fromText " \n\n " )
478- (map (unpackDocu . snd ) datapointBuilders)
458+ (map (DocuResult. unpackDocu . snd ) datapointBuilders)
479459 config = fromText " \n ## Configuration: \n ```\n "
480460 <> AE. encodePrettyToTextBuilder configuration
481461 <> fromText " \n ```\n "
@@ -486,7 +466,6 @@ docuResultsToText dt@DocTracer {..} configuration = do
486466 legend = fromText $ utf16CircledT <> " - This is the root of a tracer\n\n " <>
487467 utf16CircledS <> " - This is the root of a tracer that is silent because of the current configuration\n\n " <>
488468 utf16CircledM <> " - This is the root of a tracer, that provides metrics\n\n "
489- ts = fromString $ " Generated at " <> show time <> " .\n "
490469 pure $ toStrict $ toLazyText (
491470 header
492471 <> header1
@@ -499,114 +478,90 @@ docuResultsToText dt@DocTracer {..} configuration = do
499478 <> contentD
500479 <> config
501480 <> numbers
502- <> legend
503- <> ts)
504-
481+ <> legend)
505482
506483generateTOC :: DocTracer -> [[Text ]] -> [[Text ]] -> [[Text ]] -> Builder
507- generateTOC dt traces metrics datapoints =
484+ generateTOC DocTracer { .. } traces metrics datapoints =
508485 generateTOCTraces
509486 <> generateTOCMetrics
510487 <> generateTOCDatapoints
511488 <> generateTOCRest
512489 where
490+ tracesTree = mapMaybe (trim [] ) (toTree traces)
491+ metricsTree = toTree (fmap splitToNS metrics)
492+ datapointsTree = toTree datapoints
493+
513494 generateTOCTraces =
514495 fromText " ### [Trace Messages](#trace-messages)\n\n "
515- <> mconcat (reverse ( fst ( foldl ( namespaceToToc ( Just dt)) ( [] , [] ) traces)) )
496+ <> mconcat (map ( namespaceToToc traces False [] ) tracesTree )
516497 <> fromText " \n "
517498 generateTOCMetrics =
518499 fromText " ### [Metrics](#metrics)\n\n "
519- <> mconcat (reverse ( fst ( foldl (namespaceToToc Nothing ) ( [] , [] ) ( map splitToNS metrics))) )
500+ <> mconcat (map (namespaceToToc ( fmap splitToNS metrics) True [] ) metricsTree )
520501 <> fromText " \n "
521502 generateTOCDatapoints =
522503 fromText " ### [Datapoints](#datapoints)\n\n "
523- <> mconcat (reverse ( fst ( foldl ( namespaceToToc Nothing ) ( [] , [] ) datapoints)) )
504+ <> mconcat (map ( namespaceToToc datapoints True [] ) datapointsTree )
524505 <> fromText " \n "
525506 generateTOCRest =
526507 fromText " ### [Configuration](#configuration)\n\n "
527508 <> fromText " \n "
528509
529-
530- namespaceToToc :: Maybe DocTracer -> ([Builder ], [Text ]) -> [Text ]-> ([Builder ], [Text ])
531- namespaceToToc condDocTracer (builders, context) ns =
532- let ref = namespaceRefBuilder ns
533- in case ns of
534- (hd: tl) -> if init (hd: tl) == context
535- then
536- let symbolsText = case condDocTracer of
537- Nothing -> " "
538- Just docTracers -> getSymbolsOf ns docTracers
539- in ( fromString (concat (replicate (length context) " " ))
540- <> fromText " 1. "
541- <> fromText " ["
542- <> fromText (last ns)
543- <> fromText symbolsText
544- <> fromText " ](#"
545- <> ref
546- <> fromText " )\n " : builders, context)
547- else
548- let cpl = commonPrefixLength context ns
549- ns' = drop cpl ns
550- context' = take cpl context
551- in namespaceToTocWithContext condDocTracer (builders, context') ns' ns ref
552- [] -> ([] ,[] )
553- namespaceToTocWithContext ::
554- Maybe DocTracer
555- -> ([Builder ], [Text ])
556- -> [Text ]
557- -> [Text ]
558- -> Builder
559- -> ([Builder ], [Text ])
560- namespaceToTocWithContext condDocTracer (builders, context) ns nsFull ref =
561- case ns of
562- [single] -> let symbolsText = case condDocTracer of
563- Nothing -> " "
564- Just docTracers -> getSymbolsOf (context ++ [single]) docTracers
565- in ((fromString (concat (replicate (length context) " " ))
566- <> fromText " 1. "
567- <> fromText " ["
568- <> fromText single
569- <> fromText symbolsText
570- <> fromText " ](#"
571- <> ref
572- <> fromText " )\n " ) : builders, context)
573- (hdn : tln) ->
574- let symbolsText = case condDocTracer of
575- Nothing -> " "
576- Just docTracers -> getSymbolsOf (context ++ [hdn]) docTracers
577- builder = fromString (concat (replicate (length context) " " ))
578- <> fromText " 1. __"
579- <> fromText hdn
580- <> fromText symbolsText
581- <> fromText " __\n "
582- in namespaceToTocWithContext condDocTracer
583- (builder : builders, context ++ [hdn]) tln nsFull ref
584- [] -> error " inpossible"
585-
586510 splitToNS :: [Text ] -> [Text ]
587511 splitToNS [sym] = split (== ' .' ) sym
588512 splitToNS other = other
589513
590- getSymbolsOf :: [Text ] -> DocTracer -> Text
591- getSymbolsOf ns DocTracer {.. } =
592- let isTracer' = elem ns dtTracerNames
593- in if isTracer'
594- then
595- let isSilent = elem ns dtSilent
596- noMetrics = elem ns dtNoMetrics
597- in utf16CircledT <> if isSilent then utf16CircledS else " "
598- <> if noMetrics then " " else utf16CircledM
599- else " "
600-
601- commonPrefixLength :: Eq a => [a ] -> [a ] -> Int
602- commonPrefixLength [] _ = 0
603- commonPrefixLength _ [] = 0
604- commonPrefixLength (a : ta) (b : tb) =
605- if a == b
606- then 1 + commonPrefixLength ta tb
607- else 0
608-
609- namespaceRefBuilder ns = mconcat (map (fromText . toLower ) ns)
514+ isTracerSymbol :: [Text ] -> Bool
515+ isTracerSymbol tracer = tracer `elem` dtTracerNames
516+
517+ -- Modify the given tracer tree so that the result is a tree where entries which
518+ -- are not tracers are removed. In case the whole tree doesn't contain a tracer, return Nothing.
519+ trim :: [Text ] {- accumulated namespace in reverse -} -> RoseTree -> Maybe RoseTree
520+ trim ns (RoseTree x nested) =
521+ let that = reverse (x : ns)
522+ -- List of all nested tracers that we shall render
523+ nestedTrimmed = mapMaybe (trim (x : ns)) nested in
524+ mfilter (\ _ -> not (null nestedTrimmed) || isTracerSymbol that) (Just (RoseTree x nestedTrimmed))
525+
526+ namespaceToToc ::
527+ [[Text ]]
528+ -> Bool
529+ -> [Text ] {- Accumulated namespace in reverse -}
530+ -> RoseTree
531+ -> Builder
532+ namespaceToToc allTracers skipSymbols accns (RoseTree x nested) = text
533+ where
534+ ns = reverse (x : accns)
535+
536+ inner = mconcat (map (namespaceToToc allTracers skipSymbols (x : accns)) nested)
537+
538+ text :: Builder
539+ text =
540+ indent (length accns)
541+ (
542+ " 1. "
543+ <> " [" <> fromText x <> fromText symbolsText <> " ]"
544+ <> " (#" <> link <> " )\n "
545+ ) <> inner
546+
547+ symbolsText :: Text
548+ symbolsText = if skipSymbols then " " else
549+ let isTracer = elem ns dtTracerNames
550+ isSilent = elem ns dtSilent
551+ isMetric = notElem ns dtNoMetrics
552+ in
553+ (if isTracer then utf16CircledT else " " )
554+ <> (if isSilent then utf16CircledS else " " )
555+ <> (if isMetric then utf16CircledM else " " )
556+
557+ -- The link to the description of the first tracer in that namespace
558+ link :: Builder
559+ link = mconcat (map (fromText . toLower) firstTracer)
560+
561+ -- The first tracer in the list of tracers that has that namespace prefix
562+ firstTracer :: [Text ]
563+ firstTracer = fromJust $ find (ns `isPrefixOf` ) allTracers
564+
610565
611566asCode :: Builder -> Builder
612567asCode b = singleton ' `' <> b <> singleton ' `'
0 commit comments