Skip to content

Commit 10b900c

Browse files
committed
tracing: fix runInLoop; forwarding interruptions properly traced
1 parent d9bda00 commit 10b900c

File tree

7 files changed

+160
-67
lines changed

7 files changed

+160
-67
lines changed

bench/tx-generator/src/Cardano/Benchmarking/LogTypes.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ data TraceBenchTxSubmit txid
123123
| TraceBenchTxSubError Text
124124
| TraceBenchPlutusBudgetSummary PlutusBudgetSummary
125125
-- ^ PlutusBudgetSummary.
126+
| TraceBenchForwardingInterrupted HowToConnect String
126127
deriving stock (Show, Generic)
127128

128129
data SubmissionSummary

bench/tx-generator/src/Cardano/Benchmarking/Tracer.hs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
{-# LANGUAGE NamedFieldPuns #-}
1212
{-# LANGUAGE PatternSynonyms #-}
1313
{-# LANGUAGE RankNTypes #-}
14+
{-# LANGUAGE RecursiveDo #-}
1415
{-# LANGUAGE ScopedTypeVariables #-}
1516
{-# LANGUAGE TypeApplications #-}
1617
{-# LANGUAGE TypeOperators #-}
@@ -37,6 +38,7 @@ import Cardano.Node.Startup
3738
import Cardano.Node.Tracing.NodeInfo ()
3839
import Ouroboros.Network.IOManager (IOManager)
3940

41+
import Control.Exception (SomeException (..))
4042
import Control.Monad (forM, guard)
4143
import Data.Aeson as A
4244
import qualified Data.Aeson.KeyMap as KeyMap
@@ -85,9 +87,9 @@ initNullTracers = BenchTracers
8587
-- if the first argument isJust, we assume we have a socket path
8688
-- and want to use trace-dispatcher, so we'll create a forwarding tracer
8789
initTxGenTracers :: Maybe (IOManager, NetworkId, FilePath) -> IO BenchTracers
88-
initTxGenTracers mbForwarding = do
90+
initTxGenTracers mbForwarding = mdo
8991
mbStdoutTracer <- fmap Just standardTracer
90-
mbForwardingTracer <- prepareForwardingTracer
92+
mbForwardingTracer <- prepareForwardingTracer tracers
9193
confState <- emptyConfigReflection
9294

9395
let
@@ -108,26 +110,30 @@ initTxGenTracers mbForwarding = do
108110
connectTracer <- mkTracer TracerNameConnect mbStdoutTracer mbForwardingTracer
109111
submitTracer <- mkTracer TracerNameSubmit mbStdoutTracer mbForwardingTracer
110112

111-
traceWith benchTracer (TraceTxGeneratorVersion Version.txGeneratorVersion)
112-
113-
return $ BenchTracers
114-
{ btTxSubmit_ = benchTracer
115-
, btConnect_ = connectTracer
116-
, btSubmission2_ = submitTracer
117-
, btN2N_ = n2nSubmitTracer
118-
}
113+
let
114+
tracers = BenchTracers
115+
{ btTxSubmit_ = benchTracer
116+
, btConnect_ = connectTracer
117+
, btSubmission2_ = submitTracer
118+
, btN2N_ = n2nSubmitTracer
119+
}
120+
121+
traceWith (btTxSubmit_ tracers) (TraceTxGeneratorVersion Version.txGeneratorVersion)
122+
return tracers
119123
where
120-
prepareForwardingTracer :: IO (Maybe (Trace IO FormattedMessage))
121-
prepareForwardingTracer = forM mbForwarding $
124+
prepareForwardingTracer :: BenchTracers -> IO (Maybe (Trace IO FormattedMessage))
125+
prepareForwardingTracer benchTracer = forM mbForwarding $
122126
\(iomgr, networkId, tracerSocket) -> do
123127
let
124128
forwardingConf = fromMaybe defaultForwarder (tcForwarder initialTraceConfig)
129+
howToConnect = Net.LocalPipe tracerSocket
125130
initForwConf = InitForwardingWith
126131
{ initNetworkMagic = toNetworkMagic networkId
127132
, initEKGStore = Nothing
128-
, initHowToConnect = Net.LocalPipe tracerSocket
133+
, initHowToConnect = howToConnect
129134
, initForwarderMode = Initiator
130-
, initOnForwardInterruption = Nothing
135+
, initOnForwardInterruption = Just $ \(SomeException e) ->
136+
traceWith (btTxSubmit_ benchTracer) (TraceBenchForwardingInterrupted howToConnect $ show e)
131137
, initOnQueueOverflow = Nothing
132138
}
133139
(forwardSink, dpStore, kickoffForwarder) <-
@@ -214,8 +220,14 @@ instance (ConstructorsOf f, ConstructorsOf g) => ConstructorsOf (f :+: g) where
214220
instance (Constructor ('MetaCons n f r)) => ConstructorsOf (C1 ('MetaCons n f r) x) where
215221
constructorsOf _ = [ conName @('MetaCons n f r) undefined ]
216222

223+
217224
instance LogFormatting (TraceBenchTxSubmit TxId) where
218-
forHuman = Text.pack . show
225+
forHuman = \case
226+
TraceBenchForwardingInterrupted howToConnect errMsg ->
227+
Text.pack $ "trace forwarding connection with " <> show howToConnect <> " failed: " <> errMsg
228+
_
229+
-> ""
230+
219231
forMachine DMinimal _ = mempty
220232
forMachine DNormal t = mconcat [ "kind" .= A.String (genericName t) ]
221233
forMachine DDetailed t = forMachine DMaximum t
@@ -285,6 +297,11 @@ instance LogFormatting (TraceBenchTxSubmit TxId) where
285297
mconcat [ "kind" .= A.String "TraceBenchPlutusBudgetSummary"
286298
, "summary" .= toJSON summary
287299
]
300+
TraceBenchForwardingInterrupted howToConnect msg ->
301+
mconcat [ "kind" .= A.String "TraceBenchForwardingInterrupted"
302+
, "conn" .= howToConnect
303+
, "msg" .= msg
304+
]
288305

289306
instance MetaTrace (TraceBenchTxSubmit TxId) where
290307
namespaceFor TraceTxGeneratorVersion {} = Namespace [] ["TxGeneratorVersion"]
@@ -304,6 +321,7 @@ instance MetaTrace (TraceBenchTxSubmit TxId) where
304321
namespaceFor TraceBenchTxSubDebug {} = Namespace [] ["BenchTxSubDebug"]
305322
namespaceFor TraceBenchTxSubError {} = Namespace [] ["BenchTxSubError"]
306323
namespaceFor TraceBenchPlutusBudgetSummary {} = Namespace [] ["BenchPlutusBudgetSummary"]
324+
namespaceFor TraceBenchForwardingInterrupted {} = Namespace [] ["ForwardingInterrupted"]
307325

308326
severityFor _ _ = Just Info
309327

@@ -327,6 +345,7 @@ instance MetaTrace (TraceBenchTxSubmit TxId) where
327345
, Namespace [] ["BenchTxSubDebug"]
328346
, Namespace [] ["BenchTxSubError"]
329347
, Namespace [] ["BenchPlutusBudgetSummary"]
348+
, Namespace [] ["ForwardingInterrupted"]
330349
]
331350

332351
instance LogFormatting NodeToNodeSubmissionTrace where

cardano-node/src/Cardano/Node/Tracing/API.hs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{-# LANGUAGE PackageImports #-}
44
{-# LANGUAGE RankNTypes #-}
55
{-# LANGUAGE RecordWildCards #-}
6+
{-# LANGUAGE RecursiveDo #-}
67
{-# LANGUAGE ScopedTypeVariables #-}
78

89
module Cardano.Node.Tracing.API
@@ -37,6 +38,7 @@ import Ouroboros.Network.NodeToNode (RemoteAddress)
3738
import Prelude
3839

3940
import Control.DeepSeq (deepseq)
41+
import Control.Exception (SomeException (..))
4042
import Control.Monad (forM_)
4143
import "contra-tracer" Control.Tracer (traceWith)
4244
import "trace-dispatcher" Control.Tracer (nullTracer)
@@ -112,7 +114,7 @@ initTraceDispatcher nc p networkMagic nodeKernel noBlockForging = do
112114
, IO (Maybe String)
113115
, Tracers RemoteAddress LocalAddress blk IO
114116
)
115-
mkTracers trConfig = do
117+
mkTracers trConfig = mdo
116118
ekgStore <- EKG.newStore
117119
EKG.registerGcMetrics ekgStore
118120
ekgTrace <- ekgTracer trConfig ekgStore
@@ -127,15 +129,16 @@ initTraceDispatcher nc p networkMagic nodeKernel noBlockForging = do
127129
if forwarderBackendEnabled
128130
then do
129131
-- TODO: check if this is the correct way to use withIOManager
130-
(forwardSink, dpStore, kickoffForwarder) <- withIOManager $ \iomgr ->
132+
(forwardSink, dpStore, kickoffForwarder') <- withIOManager $ \iomgr ->
131133
let initForwConf :: InitForwardingConfig
132134
initForwConf = case ncTraceForwardSocket nc of
133135
Nothing -> InitForwardingNone
134136
Just (initHowToConnect, initForwarderMode) ->
135137
InitForwardingWith
136138
{ initNetworkMagic = networkMagic
137139
, initEKGStore = Just ekgStore
138-
, initOnForwardInterruption = Nothing -- TODO:MKarg
140+
, initOnForwardInterruption = Just $ \(SomeException e) ->
141+
traceWith (nodeStateTracer tracers) (NodeTracingForwardingInterrupted initHowToConnect $ show e)
139142
, initOnQueueOverflow = Nothing
140143
, ..
141144
}
@@ -144,21 +147,21 @@ initTraceDispatcher nc p networkMagic nodeKernel noBlockForging = do
144147
forwardingConf = fromMaybe defaultForwarder (tcForwarder trConfig)
145148
in initForwardingDelayed iomgr forwardingConf initForwConf
146149

147-
pure (forwardTracer (writeToSink forwardSink), dataPointTracer dpStore, kickoffForwarder)
150+
pure (forwardTracer (writeToSink forwardSink), dataPointTracer dpStore, kickoffForwarder')
148151
else
149152
-- Since 'Forwarder' backend isn't enabled, there is no forwarding.
150153
-- So we use nullTracers to ignore 'TraceObject's and 'DataPoint's.
151154
pure (Trace nullTracer, Trace nullTracer, pure ())
152155

153-
(,,) kickoffForwarder kickoffPrometheusSimple
154-
<$> mkDispatchTracers
155-
nodeKernel
156-
stdoutTrace
157-
fwdTracer
158-
(Just ekgTrace)
159-
dpTracer
160-
trConfig
161-
p
156+
tracers <- mkDispatchTracers
157+
nodeKernel
158+
stdoutTrace
159+
fwdTracer
160+
(Just ekgTrace)
161+
dpTracer
162+
trConfig
163+
p
164+
pure (kickoffForwarder, kickoffPrometheusSimple, tracers)
162165

163166
where
164167
-- This backend can only be used globally, i.e. will always apply to the namespace root.

cardano-node/src/Cardano/Node/Tracing/StateRep.hs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ deriving instance (NFData StartupState)
9999
data NodeState
100100
= NodeTracingOnlineConfiguring
101101
| NodeTracingFailure String
102+
| NodeTracingForwardingInterrupted HowToConnect String
102103
| NodeOpeningDbs OpeningDbs
103104
| NodeReplays Replays
104105
| NodeInitChainSelection InitChainSelection
@@ -130,16 +131,27 @@ instance LogFormatting NodeState where
130131
[ "kind" .= String "NodeShutdown", "shutdown" .= toJSON x]
131132
NodeTracingFailure x -> mconcat
132133
[ "kind" .= String "NodeTracingFailure", "message" .= toJSON x]
133-
134-
forHuman (NodeTracingFailure errMsg) = T.pack errMsg
135-
forHuman _ = ""
136-
134+
NodeTracingForwardingInterrupted howToConnect x -> mconcat
135+
[ "kind" .= String "NodeTracingForwardingInterrupted"
136+
, "conn" .= howToConnect
137+
, "message" .= toJSON x
138+
]
139+
140+
forHuman = \case
141+
NodeTracingFailure errMsg ->
142+
T.pack errMsg
143+
NodeTracingForwardingInterrupted howToConnect errMsg ->
144+
T.pack $ "trace forwarding connection with " <> show howToConnect <> " failed: " <> errMsg
145+
_
146+
-> ""
137147

138148
instance MetaTrace NodeState where
139149
namespaceFor NodeTracingOnlineConfiguring {} =
140150
Namespace [] ["NodeTracingOnlineConfiguring"]
141-
namespaceFor NodeTracingFailure {} =
151+
namespaceFor NodeTracingFailure {} =
142152
Namespace [] ["NodeTracingFailure"]
153+
namespaceFor NodeTracingForwardingInterrupted {} =
154+
Namespace [] ["NodeTracingForwardingInterrupted"]
143155
namespaceFor NodeOpeningDbs {} =
144156
Namespace [] ["OpeningDbs"]
145157
namespaceFor NodeReplays {} =
@@ -159,6 +171,8 @@ instance MetaTrace NodeState where
159171
Just Info
160172
severityFor (Namespace _ ["NodeTracingFailure"]) _ =
161173
Just Error
174+
severityFor (Namespace _ ["NodeTracingForwardingInterrupted"]) _ =
175+
Just Warning
162176
severityFor (Namespace _ ["OpeningDbs"]) _ =
163177
Just Info
164178
severityFor (Namespace _ ["NodeReplays"]) _ =
@@ -180,6 +194,8 @@ instance MetaTrace NodeState where
180194
"Tracing system came online, system configuring now"
181195
documentFor (Namespace _ ["NodeTracingFailure"]) = Just
182196
"Tracing system experienced a non-fatal failure during startup"
197+
documentFor (Namespace _ ["NodeTracingForwardingInterrupted"]) = Just
198+
"Trace/metrics forwarding connection was interrupted"
183199
documentFor (Namespace _ ["OpeningDbs"]) = Just
184200
"ChainDB components being opened"
185201
documentFor (Namespace _ ["NodeReplays"]) = Just
@@ -199,6 +215,7 @@ instance MetaTrace NodeState where
199215
allNamespaces = [
200216
Namespace [] ["NodeTracingOnlineConfiguring"]
201217
, Namespace [] ["NodeTracingFailure"]
218+
, Namespace [] ["NodeTracingForwardingInterrupted"]
202219
, Namespace [] ["OpeningDbs"]
203220
, Namespace [] ["NodeReplays"]
204221
, Namespace [] ["NodeInitChainSelection"]

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

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{-# LANGUAGE DerivingStrategies #-}
44
{-# LANGUAGE GADTs #-}
55
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+
{-# LANGUAGE MultiWayIf #-}
67
{-# LANGUAGE RankNTypes #-}
78
{-# LANGUAGE RecordWildCards #-}
89
{-# LANGUAGE ScopedTypeVariables #-}
@@ -56,13 +57,14 @@ module Cardano.Logging.Types (
5657
, TraceObject(..)
5758
, PreFormatted(..)
5859
, HowToConnect(..)
59-
, howToConnectString
6060
) where
6161

62-
6362
import Codec.Serialise (Serialise (..))
63+
import Control.Applicative ((<|>))
64+
import Control.DeepSeq (NFData)
6465
import qualified Control.Tracer as T
6566
import qualified Data.Aeson as AE
67+
import qualified Data.Aeson.Types as AE (Parser)
6668
import Data.Bool (bool)
6769
import Data.ByteString (ByteString)
6870
import qualified Data.HashMap.Strict as HM
@@ -72,7 +74,8 @@ import Data.Map.Strict (Map)
7274
import qualified Data.Map.Strict as Map
7375
import Data.Set (Set)
7476
import qualified Data.Set as Set
75-
import Data.Text as T (Text, intercalate, null, pack, singleton, unpack, words)
77+
import Data.Text as T (Text, breakOnEnd, intercalate, null, pack, singleton, unpack,
78+
unsnoc, words)
7679
import Data.Text.Read as T (decimal)
7780
import Data.Time (UTCTime)
7881
import Data.Word (Word16)
@@ -617,9 +620,42 @@ type HowToConnect :: Type
617620
data HowToConnect
618621
= LocalPipe !FilePath -- ^ Local pipe (UNIX or Windows).
619622
| RemoteSocket !Host !Port -- ^ Remote socket (host and port).
620-
deriving stock (Eq, Show, Generic)
621-
622-
howToConnectString :: HowToConnect -> String
623-
howToConnectString = \case
624-
LocalPipe pipe -> pipe
625-
RemoteSocket host port -> T.unpack host ++ ":" ++ show port
623+
deriving stock (Eq, Generic)
624+
deriving anyclass (NFData)
625+
626+
instance Show HowToConnect where
627+
show = \case
628+
LocalPipe pipe -> pipe
629+
RemoteSocket host port -> T.unpack host ++ ":" ++ show port
630+
631+
instance AE.ToJSON HowToConnect where
632+
toJSON = AE.toJSON . show
633+
toEncoding = AE.toEncoding . show
634+
635+
-- first try to host:port, and if that fails revert to parsing any
636+
-- string literal and assume it is a localpipe.
637+
instance AE.FromJSON HowToConnect where
638+
parseJSON = AE.withText "HowToConnect" $ \t ->
639+
(uncurry RemoteSocket <$> parseHostPort t)
640+
<|> ( LocalPipe <$> parseLocalPipe t)
641+
642+
parseLocalPipe :: Text -> AE.Parser FilePath
643+
parseLocalPipe t
644+
| T.null t = fail "parseLocalPipe: empty Text"
645+
| otherwise = pure $ T.unpack t
646+
647+
parseHostPort :: Text -> AE.Parser (Text, Word16)
648+
parseHostPort t
649+
| T.null t
650+
= fail "parseHostPort: empty Text"
651+
| otherwise
652+
= let
653+
(host_, portText) = T.breakOnEnd ":" t
654+
host = maybe "" fst (T.unsnoc host_)
655+
in if
656+
| T.null host -> fail "parseHostPort: Empty host or no colon found."
657+
| T.null portText -> fail "parseHostPort: Empty port."
658+
| Right (port, remainder) <- T.decimal portText
659+
, T.null remainder
660+
, 0 <= port, port <= 65535 -> pure (host, port)
661+
| otherwise -> fail "parseHostPort: Non-numeric port or value out of range."

0 commit comments

Comments
 (0)