Skip to content

Commit 7447a7e

Browse files
committed
cardano-tracer: Add functionality to run cardano-tracer as a library, with shut-down functionality and internal/user messaging.
1 parent 0f6b522 commit 7447a7e

File tree

15 files changed

+307
-111
lines changed

15 files changed

+307
-111
lines changed
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
import Cardano.Tracer.CLI (TracerParams, parseTracerParams)
1+
{-# LANGUAGE OverloadedRecordDot #-}
2+
3+
import Cardano.Tracer.CLI (TracerParams(..), parseTracerParams)
4+
import Cardano.Tracer.MetaTrace
25
import Cardano.Tracer.Run (runCardanoTracer)
36

7+
import Data.Functor (void)
48
import Data.Version (showVersion)
59
import Options.Applicative
610

711
import Paths_cardano_tracer (version)
812

913
main :: IO ()
10-
main =
11-
runCardanoTracer =<< customExecParser (prefs showHelpOnEmpty) tracerInfo
14+
main = void do
15+
tracerParams :: TracerParams
16+
<- customExecParser (prefs showHelpOnEmpty) tracerInfo
17+
trace :: Trace IO TracerTrace <-
18+
-- Default `Nothing' severity filter to Info.
19+
mkTracerTracer $ SeverityF (tracerParams.logSeverity <|> Just Info)
20+
runCardanoTracer trace tracerParams
1221

1322
tracerInfo :: ParserInfo TracerParams
1423
tracerInfo = info
@@ -21,7 +30,9 @@ tracerInfo = info
2130

2231
versionOption :: Parser (a -> a)
2332
versionOption = infoOption
24-
(showVersion version)
25-
(long "version" <>
26-
short 'v' <>
27-
help "Show version")
33+
do showVersion version
34+
do mconcat
35+
[ long "version"
36+
, short 'v'
37+
, help "Show version"
38+
]

cardano-tracer/cardano-tracer.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ library
200200
, trace-dispatcher ^>= 2.10.0
201201
, trace-forward ^>= 2.3.0
202202
, trace-resources ^>= 0.2.3
203+
, unagi-chan
203204
, wai ^>= 3.2
204205
, warp ^>= 3.4
205206
, yaml
@@ -294,6 +295,7 @@ library demo-acceptor-lib
294295
exposed-modules: Cardano.Tracer.Test.Acceptor
295296

296297
build-depends: bytestring
298+
, QuickCheck
297299
, cardano-tracer
298300
, containers
299301
, extra
@@ -306,9 +308,9 @@ library demo-acceptor-lib
306308
, text
307309
, trace-dispatcher
308310
, trace-forward
311+
, unagi-chan
309312
, vector
310313
, vector-algorithms
311-
, QuickCheck
312314

313315
executable demo-acceptor
314316
import: project-config

cardano-tracer/src/Cardano/Tracer/Acceptors/Run.hs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE LambdaCase #-}
12
{-# LANGUAGE NamedFieldPuns #-}
23
{-# LANGUAGE PackageImports #-}
34

@@ -14,6 +15,7 @@ import Cardano.Tracer.Utils
1415
import Cardano.Logging.Types (TraceObject)
1516
import qualified Cardano.Logging.Types as Net
1617

18+
import Control.Concurrent.Chan.Unagi (dupChan)
1719
import Control.Concurrent.Async (forConcurrently_)
1820
import "contra-tracer" Control.Tracer (Tracer, contramap, nullTracer, stdoutTracer)
1921
import qualified Data.List.NonEmpty as NE
@@ -33,20 +35,28 @@ import qualified Trace.Forward.Protocol.TraceObject.Type as TOF
3335
-- 1. Server mode, when the tracer accepts connections from any number of nodes.
3436
-- 2. Client mode, when the tracer initiates connections to specified number of nodes.
3537
runAcceptors :: TracerEnv -> TracerEnvRTView -> IO ()
36-
runAcceptors tracerEnv@TracerEnv{teTracer} tracerEnvRTView = do
38+
runAcceptors tracerEnv@TracerEnv{teTracer, teInChan = inChan} tracerEnvRTView = do
3739
traceWith teTracer $ TracerStartedAcceptors network
3840
case network of
39-
AcceptAt howToConnect ->
41+
AcceptAt howToConnect -> let
4042
-- Run one server that accepts connections from the nodes.
41-
runInLoop
42-
(runAcceptorsServer tracerEnv tracerEnvRTView howToConnect $ acceptorsConfigs (Net.howToConnectString howToConnect))
43-
verbosity howToConnect initialPauseInSec
44-
ConnectTo localSocks ->
43+
44+
action :: IO ()
45+
action = do
46+
dieOnShutdown =<< dupChan inChan
47+
runAcceptorsServer tracerEnv tracerEnvRTView howToConnect $ acceptorsConfigs (Net.howToConnectString howToConnect)
48+
49+
in runInLoop action verbosity howToConnect initialPauseInSec
50+
ConnectTo localSocks -> do
4551
-- Run N clients that initiate connections to the nodes.
46-
forConcurrently_ (NE.nub localSocks) \howToConnect ->
47-
runInLoop
48-
(runAcceptorsClient tracerEnv tracerEnvRTView howToConnect $ acceptorsConfigs (Net.howToConnectString howToConnect))
49-
verbosity howToConnect initialPauseInSec
52+
forConcurrently_ (NE.nub localSocks) \howToConnect -> let
53+
54+
action :: IO ()
55+
action = runAcceptorsClient tracerEnv tracerEnvRTView howToConnect $ acceptorsConfigs (Net.howToConnectString howToConnect)
56+
57+
in do
58+
dieOnShutdown =<< dupChan inChan
59+
runInLoop action verbosity howToConnect initialPauseInSec
5060
where
5161
TracerConfig{network, ekgRequestFreq, verbosity, ekgRequestFull} = teConfig tracerEnv
5262
ekgUseFullRequests = fromMaybe False ekgRequestFull

cardano-tracer/src/Cardano/Tracer/Environment.hs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE LambdaCase #-}
24

35
module Cardano.Tracer.Environment
46
( TracerEnv (..)
57
, TracerEnvRTView (..)
8+
, RawMessage (..)
9+
, InternalMessage (..)
10+
, Tag (..)
11+
, CardanoTracerMessage
12+
, onRawMessage
13+
, onInternal
14+
, onUser
15+
, delayUntilShutdown
16+
, dieOnShutdown
17+
, forever'tilShutdown
618
) where
719

820
import Cardano.Logging.Types
21+
import Cardano.Logging.Resources.Types (ResourceStats)
922
import Cardano.Tracer.Configuration
1023
#if RTVIEW
1124
import Cardano.Tracer.Handlers.Notifications.Types
@@ -16,10 +29,13 @@ import Cardano.Tracer.Handlers.State.TraceObjects
1629
import Cardano.Tracer.MetaTrace
1730
import Cardano.Tracer.Types
1831

32+
import Control.Concurrent (myThreadId)
33+
import Control.Exception (AsyncException(ThreadKilled), throwTo)
34+
import Control.Concurrent.Chan.Unagi (InChan, OutChan, readChan)
1935
import Control.Concurrent.Extra (Lock)
2036
import Data.Text (Text)
2137
import Data.Text.Lazy.Builder (Builder)
22-
38+
import Data.Kind (Type)
2339

2440
-- | Environment for all functions.
2541
data TracerEnv = TracerEnv
@@ -36,6 +52,7 @@ data TracerEnv = TracerEnv
3652
, teRegistry :: !HandleRegistry
3753
, teStateDir :: !(Maybe FilePath)
3854
, teMetricsHelp :: ![(Text, Builder)]
55+
, teInChan :: !(InChan (CardanoTracerMessage ()))
3956
}
4057

4158
#if RTVIEW
@@ -51,3 +68,46 @@ data TracerEnvRTView = TracerEnvRTView
5168
#else
5269
data TracerEnvRTView = TracerEnvRTView
5370
#endif
71+
72+
type CardanoTracerMessage userMsg = RawMessage InternalMessage userMsg
73+
74+
type RawMessage :: Type -> Type -> Type
75+
data RawMessage internal user
76+
= Shutdown
77+
| InternalMessage internal
78+
| UserMessage user
79+
80+
delayUntilShutdown :: OutChan (RawMessage internal user) -> IO ()
81+
delayUntilShutdown outChan = go where
82+
go :: IO ()
83+
go = readChan outChan >>= \case
84+
Shutdown -> pure ()
85+
_ -> go
86+
87+
onRawMessage :: (internal -> IO ()) -> (user -> IO ()) -> OutChan (RawMessage internal user) -> IO ()
88+
onRawMessage internalAction userAction outChan =
89+
readChan outChan >>= \case
90+
Shutdown -> myThreadId >>= (`throwTo` ThreadKilled)
91+
InternalMessage internal -> internalAction internal
92+
UserMessage user -> userAction user
93+
94+
onInternal :: (internal -> IO ()) -> OutChan (RawMessage internal user) -> IO ()
95+
onInternal = (`onRawMessage` mempty)
96+
97+
onUser :: (user -> IO ()) -> OutChan (RawMessage internal user) -> IO ()
98+
onUser = (mempty `onRawMessage`)
99+
100+
data InternalMessage where
101+
ResourceMessage :: Tag ex -> (ex -> IO ()) -> InternalMessage
102+
103+
data Tag a where
104+
TagResource :: Tag (ResourceStats, Trace IO TracerTrace)
105+
106+
dieOnShutdown :: OutChan (RawMessage internal user) -> IO ()
107+
dieOnShutdown = onRawMessage mempty mempty
108+
109+
forever'tilShutdown :: OutChan (RawMessage internal user) -> IO () -> IO ()
110+
forever'tilShutdown outChan action = do
111+
readChan outChan >>= \case
112+
Shutdown -> pure ()
113+
_ -> action *> forever'tilShutdown outChan action

cardano-tracer/src/Cardano/Tracer/Handlers/Logs/Rotator.hs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ module Cardano.Tracer.Handlers.Logs.Rotator
66
) where
77

88
import Cardano.Tracer.Configuration
9-
import Cardano.Tracer.Environment
9+
import Cardano.Tracer.Environment (TracerEnv (..), forever'tilShutdown)
1010
import Cardano.Tracer.Handlers.Logs.Utils (createOrUpdateEmptyLog, getTimeStampFromLog,
1111
isItLog)
1212
import Cardano.Tracer.MetaTrace
1313
import Cardano.Tracer.Types (HandleRegistry, HandleRegistryKey, NodeName)
1414
import Cardano.Tracer.Utils (showProblemIfAny, readRegistry)
1515

1616
import Control.Concurrent.Async (forConcurrently_)
17+
import Control.Concurrent.Chan.Unagi (dupChan)
1718
import Control.Concurrent.Extra (Lock)
18-
import Control.Monad (forM_, forever, unless, when)
19+
import Control.Monad (forM_, unless, when)
1920
import Control.Monad.Extra (whenJust, whenM)
2021
import Data.Foldable (for_)
2122
import Data.List (nub, sort)
@@ -33,38 +34,40 @@ import System.Time.Extra (sleep)
3334

3435
-- | Runs rotation mechanism for the log files.
3536
runLogsRotator :: TracerEnv -> IO ()
36-
runLogsRotator TracerEnv
37-
{ teConfig = TracerConfig{rotation, verbosity, logging}
38-
, teCurrentLogLock
39-
, teTracer
40-
, teRegistry
41-
} = do
42-
whenJust rotation \rotParams -> do
37+
runLogsRotator tracerEnv@TracerEnv { teConfig = TracerConfig{rotation}, teTracer } = do
38+
whenJust rotation \rot -> do
4339
traceWith teTracer TracerStartedLogRotator
44-
launchRotator loggingParamsForFiles rotParams verbosity teRegistry teCurrentLogLock
45-
where
40+
launchRotator tracerEnv rot
41+
42+
launchRotator
43+
:: TracerEnv
44+
-> RotationParams
45+
-> IO ()
46+
launchRotator tracerEnv rot@RotationParams{rpFrequencySecs} = do
47+
whenNonEmpty loggingParamsForFiles do
48+
outChan <- dupChan teInChan
49+
forever'tilShutdown outChan do
50+
showProblemIfAny verbosity do
51+
forM_ loggingParamsForFiles \loggingParam -> do
52+
checkRootDir teCurrentLogLock teRegistry rot loggingParam
53+
sleep (fromIntegral rpFrequencySecs)
54+
where
55+
whenNonEmpty :: Applicative f => [a] -> f () -> f ()
56+
whenNonEmpty = unless . null
57+
58+
TracerEnv
59+
{ teConfig = TracerConfig{verbosity, logging}
60+
, teCurrentLogLock
61+
, teRegistry
62+
, teInChan
63+
} = tracerEnv
64+
4665
loggingParamsForFiles :: [LoggingParams]
4766
loggingParamsForFiles = nub (NE.filter filesOnly logging)
4867

4968
filesOnly :: LoggingParams -> Bool
5069
filesOnly LoggingParams{logMode} = logMode == FileMode
5170

52-
launchRotator
53-
:: [LoggingParams]
54-
-> RotationParams
55-
-> Maybe Verbosity
56-
-> HandleRegistry
57-
-> Lock
58-
-> IO ()
59-
launchRotator [] _ _ _ _ = return ()
60-
launchRotator loggingParamsForFiles
61-
rotParams@RotationParams{rpFrequencySecs} verb registry currentLogLock =
62-
forever do
63-
showProblemIfAny verb do
64-
forM_ loggingParamsForFiles \loggingParam -> do
65-
checkRootDir currentLogLock registry rotParams loggingParam
66-
sleep $ fromIntegral rpFrequencySecs
67-
6871
-- | All the logs with 'TraceObject's received from particular node
6972
-- will be stored in a separate subdirectory in the root directory.
7073
--

cardano-tracer/src/Cardano/Tracer/Handlers/Metrics/Monitoring.hs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE LambdaCase #-}
12
{-# LANGUAGE NamedFieldPuns #-}
23
{-# LANGUAGE OverloadedStrings #-}
34
{-# LANGUAGE ScopedTypeVariables #-}
@@ -14,6 +15,8 @@ import Cardano.Tracer.Types
1415

1516
import Prelude hiding (head)
1617

18+
import Control.Concurrent.Async (race_)
19+
import Control.Concurrent.Chan.Unagi (OutChan, dupChan)
1720
import Data.ByteString as ByteString (ByteString, isInfixOf)
1821
import Data.ByteString.Builder (stringUtf8)
1922
import qualified Data.Text as T
@@ -39,19 +42,26 @@ runMonitoringServer
3942
-> Endpoint -- ^ (web page with list of connected nodes, EKG web page).
4043
-> IO RouteDictionary
4144
-> IO ()
42-
runMonitoringServer TracerEnv{teTracer} endpoint computeRoutes_autoUpdate = do
45+
runMonitoringServer TracerEnv{teTracer, teInChan = inChan} endpoint computeRoutes_autoUpdate = do
4346
-- Pause to prevent collision between "Listening"-notifications from servers.
4447
sleep 0.2
4548
traceWith teTracer TracerStartedMonitoring
4649
{ ttMonitoringEndpoint = endpoint
4750
, ttMonitoringType = "list"
4851
}
4952
dummyStore <- EKG.newStore
50-
runSettings (setEndpoint endpoint defaultSettings) do
51-
renderEkg dummyStore computeRoutes_autoUpdate
53+
outChan <- dupChan inChan
54+
55+
let run :: IO ()
56+
run = runSettings (setEndpoint endpoint defaultSettings) $
57+
renderEkg dummyStore outChan computeRoutes_autoUpdate
58+
59+
race_ run (delayUntilShutdown outChan)
60+
61+
renderEkg :: EKG.Store -> OutChan (CardanoTracerMessage ()) -> IO RouteDictionary -> Application
62+
renderEkg dummyStore outChan computeRoutes_autoUpdate request send = do
63+
dieOnShutdown outChan
5264

53-
renderEkg :: EKG.Store -> IO RouteDictionary -> Application
54-
renderEkg dummyStore computeRoutes_autoUpdate request send = do
5565
routeDictionary :: RouteDictionary <-
5666
computeRoutes_autoUpdate
5767

0 commit comments

Comments
 (0)