Skip to content

Commit 0d15b3f

Browse files
committed
sharpen the package split and add a front-door module
The trace-dispatcher-api / trace-dispatcher split was too coarse: output types (FormattedMessage, TraceObject, PreFormatted), the forwarder connection type (HowToConnect/Host/Port), and several utility/domain modules lived in the API package despite having no business being there — they pulled in bytestring, async, cborg-json, and time as transitive API dependencies. Moved to trace-dispatcher: FormattedMessage, TraceObject, PreFormatted → Cardano.Logging.Formatter HowToConnect, Host, Port → Cardano.Logging.Tracer.Forward Cardano.Logging.Utils, Types.NodeInfo, Types.NodeStartupInfo, Types.TraceMessage trace-dispatcher-api now exposes exactly two modules (Cardano.Logging.Types, Cardano.Logging.Trace) covering the Trace newtype, the LogFormatting/MetaTrace typeclasses, core combinators, and the TraceControl dependency chain. Removed four no-longer-needed build-depends (async, bytestring, cborg-json, time). New Cardano.Logging.API is added as the single-import front door for the package, re-exporting both modules with a module haddock that explains the two-tier role and guides users toward Cardano.Logging (from trace-dispatcher) when they need the full backend stack. Cardano.Logging (the trace-dispatcher mega-module) gains a three-step usage haddock and no longer re-exports FrequencyLimiter or TraceDispatcherMessage, which are internal implementation details.
1 parent 21633e9 commit 0d15b3f

15 files changed

Lines changed: 230 additions & 122 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
-- | Stable public API for the Hermod tracing system.
2+
--
3+
-- This is the single-import front door for @trace-dispatcher-api@. It
4+
-- re-exports everything a package needs to:
5+
--
6+
-- * __Define trace types__: write 'LogFormatting' (human\/machine rendering,
7+
-- metrics) and 'MetaTrace' (namespace, severity, documentation) instances
8+
-- for your domain message types.
9+
--
10+
-- * __Dispatch messages__: call 'traceWith' to emit, 'contramapM' \/ 'contramapM''
11+
-- to adapt types, 'foldTraceM' to accumulate state, 'routingTrace' to fan out.
12+
--
13+
-- * __Filter and annotate__: 'filterTraceBySeverity', 'filterTraceByPrivacy',
14+
-- 'withNames', 'setSeverity', 'setDetails', etc.
15+
--
16+
-- == When to use this package vs. @trace-dispatcher@
17+
--
18+
-- Depend on @trace-dispatcher-api@ (and import this module) when your package
19+
-- only needs to __define__ trace types and __call__ the core combinators — for
20+
-- example, a library that instruments its own operations. You get a small
21+
-- transitive closure with no I\/O backends, no config parser, no Prometheus.
22+
--
23+
-- Depend on @trace-dispatcher@ (and import "Cardano.Logging") when you need
24+
-- the __full stack__: backend constructors ('standardTracer', 'ekgTracer',
25+
-- 'forwardTracer'), 'configureTracers', 'readConfiguration', and so on.
26+
--
27+
-- == Types exported by this module
28+
--
29+
-- === For tracer authors
30+
--
31+
-- @
32+
-- Trace -- the central carrier type
33+
-- LogFormatting(..) -- typeclass: forMachine, forHuman, asMetrics
34+
-- MetaTrace(..) -- typeclass: namespaceFor, severityFor, documentFor, …
35+
-- Metric(..) -- metric payload (IntM, DoubleM, CounterM, PrometheusM)
36+
-- Namespace(..) -- hierarchical trace identifier
37+
-- LoggingContext(..) -- per-message context (namespace, severity, privacy, detail)
38+
-- SeverityS(..) -- message severity (Debug … Emergency)
39+
-- SeverityF(..) -- severity filter (Nothing = Silence)
40+
-- Privacy(..) -- Public | Confidential
41+
-- DetailLevel(..) -- DMinimal … DMaximum
42+
-- Folding(..) -- wrapper for fold-based stateful tracers
43+
-- @
44+
--
45+
-- === Configuration and control (consumed by @trace-dispatcher@)
46+
--
47+
-- 'TraceControl', 'TraceConfig', 'ConfigOption', 'BackendConfig',
48+
-- 'ConfigReflection', 'DocCollector', 'LogDoc', 'ForwarderAddr',
49+
-- 'ForwarderMode', 'TraceOptionForwarder', 'PrometheusSimpleRun'.
50+
-- These appear in type signatures throughout the system; tracer authors
51+
-- typically do not construct them directly.
52+
module Cardano.Logging.API
53+
( module X
54+
) where
55+
56+
-- Core types: Trace, LogFormatting, MetaTrace, Namespace, Metric,
57+
-- LoggingContext, Severity, Privacy, DetailLevel, Folding,
58+
-- TraceConfig, TraceControl, BackendConfig, …
59+
import Cardano.Logging.Types as X
60+
61+
-- Core combinators: traceWith, contramapM, contramapM', foldTraceM,
62+
-- foldCondTraceM, routingTrace, filterTrace*,
63+
-- withNames, setSeverity, setDetails, withLoggingContext, …
64+
import Cardano.Logging.Trace as X

trace-dispatcher-api/src/Cardano/Logging/Types.hs

Lines changed: 2 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
{-# LANGUAGE DeriveGeneric #-}
33
{-# LANGUAGE DerivingStrategies #-}
44
{-# LANGUAGE GADTs #-}
5-
{-# LANGUAGE MultiWayIf #-}
65
{-# LANGUAGE RankNTypes #-}
76
{-# LANGUAGE RecordWildCards #-}
87
{-# LANGUAGE ScopedTypeVariables #-}
9-
{-# LANGUAGE StandaloneKindSignatures #-}
108

119
{-# OPTIONS_GHC -Wno-partial-fields #-}
1210

@@ -44,39 +42,28 @@ module Cardano.Logging.Types (
4442
, emptyConfigReflection
4543
, TraceConfig(..)
4644
, emptyTraceConfig
47-
, FormattedMessage(..)
4845
, TraceControl(..)
4946
, DocCollector(..)
5047
, LogDoc(..)
5148
, emptyLogDoc
5249
, BackendConfig(..)
5350
, Folding(..)
5451
, unfold
55-
, TraceObject(..)
56-
, PreFormatted(..)
57-
, HowToConnect(..)
5852
) where
5953

6054
import Codec.Serialise (Serialise (..))
61-
import Control.Applicative ((<|>))
6255
import Control.DeepSeq (NFData)
6356
import qualified Control.Tracer as T
6457
import qualified Data.Aeson as AE
65-
import qualified Data.Aeson.Types as AE (Parser)
6658
import Data.Bool (bool)
67-
import Data.ByteString (ByteString)
6859
import Data.IORef
69-
import Data.Kind (Type)
7060
import Data.Map.Strict (Map)
7161
import qualified Data.Map.Strict as Map
7262
import Data.Set (Set)
7363
import qualified Data.Set as Set
74-
import Data.Text as T (Text, breakOnEnd, intercalate, null,
75-
pack, singleton, unpack, unsnoc,
76-
words)
64+
import Data.Text as T (Text, intercalate, null,
65+
pack, singleton, unpack, words)
7766
import Data.Text.Read as T (decimal)
78-
import Data.Time (UTCTime)
79-
import Data.Word (Word16)
8067
import GHC.Generics
8168
import Network.HostName (HostName)
8269
import Network.Socket (PortNumber)
@@ -334,40 +321,6 @@ emptyConfigReflection = do
334321
allTracers <- newIORef Set.empty
335322
pure $ ConfigReflection silence hasMetrics allTracers
336323

337-
data FormattedMessage =
338-
FormattedHuman Bool Text
339-
-- ^ The bool specifies if the formatting includes colours
340-
| FormattedMachine Text
341-
| FormattedMetrics [Metric]
342-
| FormattedForwarder TraceObject
343-
| FormattedCBOR ByteString
344-
deriving stock (Eq, Show)
345-
346-
347-
data PreFormatted = PreFormatted {
348-
pfTime :: !UTCTime
349-
, pfNamespace :: !Text
350-
, pfThreadId :: !Text
351-
, pfForHuman :: !(Maybe Text)
352-
, pfForMachineObject :: AE.Object
353-
}
354-
355-
-- | Used as interface object for ForwarderTracer
356-
data TraceObject = TraceObject {
357-
toHuman :: !(Maybe Text)
358-
, toMachine :: !Text
359-
, toNamespace :: ![Text]
360-
, toSeverity :: !SeverityS
361-
, toDetails :: !DetailLevel
362-
, toTimestamp :: !UTCTime
363-
, toHostname :: !Text
364-
, toThreadId :: !Text
365-
} deriving stock
366-
(Eq, Show, Generic)
367-
-- ^ Instances for 'TraceObject' to forward it using 'trace-forward' library.
368-
deriving anyclass
369-
(Serialise, NFData)
370-
371324
-- |
372325
data BackendConfig =
373326
Forwarder
@@ -613,55 +566,3 @@ instance LogFormatting b => LogFormatting (Folding a b) where
613566
forHuman (Folding b) = forHuman b
614567
asMetrics (Folding b) = asMetrics b
615568

616-
-- | Specifies how to connect to the peer.
617-
--
618-
-- Taken from ekg-forward:System.Metrics.Configuration, to avoid dependency.
619-
type Host :: Type
620-
type Host = Text
621-
622-
type Port :: Type
623-
type Port = Word16
624-
625-
type HowToConnect :: Type
626-
data HowToConnect
627-
= LocalPipe !FilePath -- ^ Local pipe (UNIX or Windows).
628-
| RemoteSocket !Host !Port -- ^ Remote socket (host and port).
629-
deriving stock (Eq, Generic)
630-
deriving anyclass (NFData)
631-
632-
instance Show HowToConnect where
633-
show = \case
634-
LocalPipe pipe -> pipe
635-
RemoteSocket host port -> T.unpack host ++ ":" ++ show port
636-
637-
instance AE.ToJSON HowToConnect where
638-
toJSON = AE.toJSON . show
639-
toEncoding = AE.toEncoding . show
640-
641-
-- first try to host:port, and if that fails revert to parsing any
642-
-- string literal and assume it is a localpipe.
643-
instance AE.FromJSON HowToConnect where
644-
parseJSON = AE.withText "HowToConnect" $ \t ->
645-
(uncurry RemoteSocket <$> parseHostPort t)
646-
<|> ( LocalPipe <$> parseLocalPipe t)
647-
648-
parseLocalPipe :: Text -> AE.Parser FilePath
649-
parseLocalPipe t
650-
| T.null t = fail "parseLocalPipe: empty Text"
651-
| otherwise = pure $ T.unpack t
652-
653-
parseHostPort :: Text -> AE.Parser (Text, Word16)
654-
parseHostPort t
655-
| T.null t
656-
= fail "parseHostPort: empty Text"
657-
| otherwise
658-
= let
659-
(host_, portText) = T.breakOnEnd ":" t
660-
host = maybe "" fst (T.unsnoc host_)
661-
in if
662-
| T.null host -> fail "parseHostPort: Empty host or no colon found."
663-
| T.null portText -> fail "parseHostPort: Empty port."
664-
| Right (port, remainder) <- T.decimal portText
665-
, T.null remainder
666-
, 0 <= port, port <= 65535 -> pure (host, port)
667-
| otherwise -> fail "parseHostPort: Non-numeric port or value out of range."

trace-dispatcher-api/trace-dispatcher-api.cabal

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,18 @@ common project-config
4343
library
4444
import: project-config
4545
hs-source-dirs: src
46-
exposed-modules: Cardano.Logging.Trace
46+
exposed-modules: Cardano.Logging.API
47+
Cardano.Logging.Trace
4748
Cardano.Logging.Types
48-
Cardano.Logging.Types.NodeInfo
49-
Cardano.Logging.Types.NodeStartupInfo
50-
Cardano.Logging.Types.TraceMessage
51-
Cardano.Logging.Utils
5249

5350
build-depends: base >=4.12 && <5
5451
, aeson >= 2.1.0.0
55-
, async
56-
, bytestring
57-
, cborg
58-
, cborg-json
5952
, containers
6053
, contra-tracer ^>= 0.2.1
6154
, deepseq
6255
, hostname
6356
, network
6457
, serialise
6558
, text
66-
, time
6759
, unliftio
6860
, unliftio-core
Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,47 @@
1+
-- | Batteries-included public interface for the Hermod tracing system.
2+
--
3+
-- A typical application wires up tracing in three steps:
4+
--
5+
-- 1. __Define trace types__: for each domain-specific message type, write
6+
-- 'LogFormatting' (human\/machine rendering, metrics) and 'MetaTrace'
7+
-- (namespace, severity, documentation) instances.
8+
--
9+
-- 2. __Construct backends__: call 'mkCardanoTracer' (or 'mkCardanoTracer'')
10+
-- with 'standardTracer', 'ekgTracer', and\/or 'forwardTracer' to build a
11+
-- 'Trace IO YourType'.
12+
--
13+
-- 3. __Configure__: load a 'TraceConfig' with 'readConfiguration' and apply it
14+
-- with 'configureTracers'. Use 'checkTraceConfiguration' to validate the
15+
-- config against all known namespaces at startup.
16+
--
17+
118
module Cardano.Logging (
219
module X
320
) where
421

5-
import Cardano.Logging.Configuration as X
6-
import Cardano.Logging.ConfigurationParser as X
7-
import Cardano.Logging.Consistency as X
8-
import Cardano.Logging.Formatter as X
9-
import Cardano.Logging.FrequencyLimiter as X
22+
-- Core API types and combinators (from trace-dispatcher-api)
23+
import Cardano.Logging.Types as X
1024
import Cardano.Logging.Trace as X
11-
import Cardano.Logging.TraceDispatcherMessage as X
25+
26+
-- Backend constructors
1227
import Cardano.Logging.Tracer.Composed as X
1328
import Cardano.Logging.Tracer.DataPoint as X
1429
import Cardano.Logging.Tracer.EKG as X
1530
import Cardano.Logging.Tracer.Forward as X
1631
import Cardano.Logging.Tracer.Standard as X
17-
import Cardano.Logging.Types as X
32+
33+
-- Configuration: loading, parsing, applying, and checking
34+
import Cardano.Logging.Configuration as X
35+
import Cardano.Logging.ConfigurationParser as X
36+
import Cardano.Logging.Consistency as X
37+
38+
-- Output types produced by the backend pipeline
39+
-- (FormattedMessage, TraceObject, PreFormatted)
40+
import Cardano.Logging.Formatter as X
41+
42+
-- Utilities: showT, showTHex, showTReal, runInLoop
1843
import Cardano.Logging.Utils as X
1944

45+
-- Re-exports arrow/emit/squelch from contra-tracer for custom backend authors.
46+
-- traceWith, contramapM, nullTracer, Tracer are shadowed by this package's own versions.
2047
import Control.Tracer as X hiding (Tracer, contramapM, nullTracer, traceWith)

trace-dispatcher/src/Cardano/Logging/Configuration.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module Cardano.Logging.Configuration
2424
) where
2525

2626
import Cardano.Logging.DocuGenerator (addFiltered, addLimiter, addSilent)
27+
import Cardano.Logging.Formatter (FormattedMessage)
2728
import Cardano.Logging.FrequencyLimiter (limitFrequency)
2829
import Cardano.Logging.Trace
2930
import Cardano.Logging.TraceDispatcherMessage

trace-dispatcher/src/Cardano/Logging/DocuGenerator.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module Cardano.Logging.DocuGenerator (
2626
) where
2727

2828
import Cardano.Logging.ConfigurationParser ()
29+
import Cardano.Logging.Formatter (FormattedMessage)
2930
import Cardano.Logging.Types
3031
import Cardano.Logging.Types.DocuGenerator
3132

trace-dispatcher/src/Cardano/Logging/Formatter.hs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
{-# LANGUAGE DeriveAnyClass #-}
2+
{-# LANGUAGE DeriveGeneric #-}
3+
{-# LANGUAGE DerivingStrategies #-}
14
{-# LANGUAGE FlexibleInstances #-}
25
{-# LANGUAGE RankNTypes #-}
36
{-# LANGUAGE ScopedTypeVariables #-}
47

58
{-# OPTIONS_GHC -Wno-orphans #-}
69

710
module Cardano.Logging.Formatter (
8-
metricsFormatter
11+
FormattedMessage(..)
12+
, PreFormatted(..)
13+
, TraceObject(..)
14+
, metricsFormatter
915
, preFormatted
1016
, forwardFormatter
1117
, forwardFormatter'
@@ -21,7 +27,11 @@ import Cardano.Logging.Trace (contramapM)
2127
import Cardano.Logging.Types
2228
import Cardano.Logging.Types.TraceMessage
2329

24-
import Codec.Serialise (serialise)
30+
import Codec.Serialise (Serialise (..), serialise)
31+
import Control.DeepSeq (NFData)
32+
import Data.ByteString (ByteString)
33+
import Data.Time (UTCTime)
34+
import GHC.Generics (Generic)
2535
import Control.Concurrent (myThreadId)
2636
import Control.Monad.IO.Class (MonadIO, liftIO)
2737
import qualified Control.Tracer as T
@@ -41,6 +51,41 @@ import System.Environment (lookupEnv)
4151
import System.IO.Unsafe (unsafePerformIO)
4252

4353

54+
data FormattedMessage =
55+
FormattedHuman Bool Text
56+
-- ^ The bool specifies if the formatting includes colours
57+
| FormattedMachine Text
58+
| FormattedMetrics [Metric]
59+
| FormattedForwarder TraceObject
60+
| FormattedCBOR ByteString
61+
deriving stock (Eq, Show)
62+
63+
64+
data PreFormatted = PreFormatted {
65+
pfTime :: !UTCTime
66+
, pfNamespace :: !Text
67+
, pfThreadId :: !Text
68+
, pfForHuman :: !(Maybe Text)
69+
, pfForMachineObject :: AE.Object
70+
}
71+
72+
-- | Used as interface object for ForwarderTracer
73+
data TraceObject = TraceObject {
74+
toHuman :: !(Maybe Text)
75+
, toMachine :: !Text
76+
, toNamespace :: ![Text]
77+
, toSeverity :: !SeverityS
78+
, toDetails :: !DetailLevel
79+
, toTimestamp :: !UTCTime
80+
, toHostname :: !Text
81+
, toThreadId :: !Text
82+
} deriving stock
83+
(Eq, Show, Generic)
84+
-- ^ Instances for 'TraceObject' to forward it using 'trace-forward' library.
85+
deriving anyclass
86+
(Serialise, NFData)
87+
88+
4489
-- | If the @TRACE_DISPATCHER_LOGGING_HOSTNAME@ environment variable is set,
4590
-- it overrides the system hostname in the trace message. This is useful when
4691
-- multiple instances of a service or application on the same host.

trace-dispatcher/src/Cardano/Logging/Tracer/EKG.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Cardano.Logging.Tracer.EKG (
66
) where
77

88
import Cardano.Logging.DocuGenerator
9+
import Cardano.Logging.Formatter (FormattedMessage (..))
910
import Cardano.Logging.Types
1011
import Cardano.Logging.Utils (showTReal, tryEvalNF)
1112

0 commit comments

Comments
 (0)