{-# LANGUAGE DeriveGeneric #-}
module Instana.SDK.Internal.Context
( AgentConnection(..)
, InternalContext(..)
, ConnectionState(..)
, isAgentConnectionEstablished
, mkAgentReadyState
, readAgentUuid
, readPid
, whenConnected
) where
import Control.Concurrent (ThreadId)
import Control.Concurrent.STM (STM)
import qualified Control.Concurrent.STM as STM
import Data.Map.Strict (Map)
import Data.Sequence (Seq)
import Data.Text (Text)
import qualified Foreign.C.Types as CTypes
import GHC.Generics
import Network.HTTP.Client as HttpClient
import qualified System.Metrics as Metrics
import Instana.SDK.Internal.AgentConnection.Json.AnnounceResponse (AnnounceResponse)
import qualified Instana.SDK.Internal.AgentConnection.Json.AnnounceResponse as AnnounceResponse
import Instana.SDK.Internal.Command (Command)
import Instana.SDK.Internal.Config (FinalConfig)
import Instana.SDK.Internal.Metrics.Sample (TimedSample)
import Instana.SDK.Internal.SpanStack (SpanStack)
import Instana.SDK.Internal.WireSpan (QueuedSpan)
data ConnectionState =
Unconnected
| AgentHostLookup
| Unannounced (String, Int)
| Announced (String, Int)
| AgentReady Ready
deriving (ConnectionState -> ConnectionState -> Bool
(ConnectionState -> ConnectionState -> Bool)
-> (ConnectionState -> ConnectionState -> Bool)
-> Eq ConnectionState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ConnectionState -> ConnectionState -> Bool
$c/= :: ConnectionState -> ConnectionState -> Bool
== :: ConnectionState -> ConnectionState -> Bool
$c== :: ConnectionState -> ConnectionState -> Bool
Eq, Int -> ConnectionState -> ShowS
[ConnectionState] -> ShowS
ConnectionState -> String
(Int -> ConnectionState -> ShowS)
-> (ConnectionState -> String)
-> ([ConnectionState] -> ShowS)
-> Show ConnectionState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ConnectionState] -> ShowS
$cshowList :: [ConnectionState] -> ShowS
show :: ConnectionState -> String
$cshow :: ConnectionState -> String
showsPrec :: Int -> ConnectionState -> ShowS
$cshowsPrec :: Int -> ConnectionState -> ShowS
Show, (forall x. ConnectionState -> Rep ConnectionState x)
-> (forall x. Rep ConnectionState x -> ConnectionState)
-> Generic ConnectionState
forall x. Rep ConnectionState x -> ConnectionState
forall x. ConnectionState -> Rep ConnectionState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ConnectionState x -> ConnectionState
$cfrom :: forall x. ConnectionState -> Rep ConnectionState x
Generic)
data Ready =
Ready
{ Ready -> AgentConnection
connection :: AgentConnection
, Ready -> Store
metrics :: Metrics.Store
} deriving ((forall x. Ready -> Rep Ready x)
-> (forall x. Rep Ready x -> Ready) -> Generic Ready
forall x. Rep Ready x -> Ready
forall x. Ready -> Rep Ready x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Ready x -> Ready
$cfrom :: forall x. Ready -> Rep Ready x
Generic)
instance Eq Ready where
r1 :: Ready
r1 == :: Ready -> Ready -> Bool
== r2 :: Ready
r2 =
Ready -> AgentConnection
connection Ready
r1 AgentConnection -> AgentConnection -> Bool
forall a. Eq a => a -> a -> Bool
== Ready -> AgentConnection
connection Ready
r2
instance Show Ready where
show :: Ready -> String
show r :: Ready
r =
AgentConnection -> String
forall a. Show a => a -> String
show (AgentConnection -> String) -> AgentConnection -> String
forall a b. (a -> b) -> a -> b
$ Ready -> AgentConnection
connection Ready
r
data AgentConnection =
AgentConnection
{
AgentConnection -> String
agentHost :: String
, AgentConnection -> Int
agentPort :: Int
, AgentConnection -> String
pid :: String
, AgentConnection -> Text
agentUuid :: Text
}
deriving (AgentConnection -> AgentConnection -> Bool
(AgentConnection -> AgentConnection -> Bool)
-> (AgentConnection -> AgentConnection -> Bool)
-> Eq AgentConnection
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AgentConnection -> AgentConnection -> Bool
$c/= :: AgentConnection -> AgentConnection -> Bool
== :: AgentConnection -> AgentConnection -> Bool
$c== :: AgentConnection -> AgentConnection -> Bool
Eq, Int -> AgentConnection -> ShowS
[AgentConnection] -> ShowS
AgentConnection -> String
(Int -> AgentConnection -> ShowS)
-> (AgentConnection -> String)
-> ([AgentConnection] -> ShowS)
-> Show AgentConnection
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AgentConnection] -> ShowS
$cshowList :: [AgentConnection] -> ShowS
show :: AgentConnection -> String
$cshow :: AgentConnection -> String
showsPrec :: Int -> AgentConnection -> ShowS
$cshowsPrec :: Int -> AgentConnection -> ShowS
Show, (forall x. AgentConnection -> Rep AgentConnection x)
-> (forall x. Rep AgentConnection x -> AgentConnection)
-> Generic AgentConnection
forall x. Rep AgentConnection x -> AgentConnection
forall x. AgentConnection -> Rep AgentConnection x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AgentConnection x -> AgentConnection
$cfrom :: forall x. AgentConnection -> Rep AgentConnection x
Generic)
mkAgentReadyState ::
(String, Int)
-> AnnounceResponse
-> Metrics.Store
-> ConnectionState
mkAgentReadyState :: (String, Int) -> AnnounceResponse -> Store -> ConnectionState
mkAgentReadyState (host_ :: String
host_, port_ :: Int
port_) announceResponse :: AnnounceResponse
announceResponse metricsStore :: Store
metricsStore =
let
agentConnection :: AgentConnection
agentConnection = AgentConnection :: String -> Int -> String -> Text -> AgentConnection
AgentConnection
{ agentHost :: String
agentHost = String
host_
, agentPort :: Int
agentPort = Int
port_
, pid :: String
pid = Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ AnnounceResponse -> Int
AnnounceResponse.pid AnnounceResponse
announceResponse
, agentUuid :: Text
agentUuid = AnnounceResponse -> Text
AnnounceResponse.agentUuid AnnounceResponse
announceResponse
}
in
Ready -> ConnectionState
AgentReady (Ready -> ConnectionState) -> Ready -> ConnectionState
forall a b. (a -> b) -> a -> b
$
Ready :: AgentConnection -> Store -> Ready
Ready
{ connection :: AgentConnection
connection = AgentConnection
agentConnection
, metrics :: Store
metrics = Store
metricsStore
}
data InternalContext = InternalContext
{ InternalContext -> FinalConfig
config :: FinalConfig
, InternalContext -> Int
sdkStartTime :: Int
, InternalContext -> Manager
httpManager :: HttpClient.Manager
, InternalContext -> TQueue Command
commandQueue :: STM.TQueue Command
, InternalContext -> TVar (Seq QueuedSpan)
spanQueue :: STM.TVar (Seq QueuedSpan)
, InternalContext -> TVar ConnectionState
connectionState :: STM.TVar ConnectionState
, InternalContext -> TVar (Maybe CInt)
fileDescriptor :: STM.TVar (Maybe CTypes.CInt)
, InternalContext -> TVar (Map ThreadId SpanStack)
currentSpans :: STM.TVar (Map ThreadId SpanStack)
, InternalContext -> TVar TimedSample
previousMetricsSample :: STM.TVar TimedSample
}
instance Show InternalContext where
show :: InternalContext -> String
show context :: InternalContext
context = FinalConfig -> String
forall a. Show a => a -> String
show (InternalContext -> FinalConfig
config InternalContext
context)
isAgentConnectionEstablishedSTM :: InternalContext -> STM Bool
isAgentConnectionEstablishedSTM :: InternalContext -> STM Bool
isAgentConnectionEstablishedSTM context :: InternalContext
context = do
ConnectionState
state <- TVar ConnectionState -> STM ConnectionState
forall a. TVar a -> STM a
STM.readTVar (TVar ConnectionState -> STM ConnectionState)
-> TVar ConnectionState -> STM ConnectionState
forall a b. (a -> b) -> a -> b
$ InternalContext -> TVar ConnectionState
connectionState InternalContext
context
Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> STM Bool) -> Bool -> STM Bool
forall a b. (a -> b) -> a -> b
$
case ConnectionState
state of
AgentReady _ -> Bool
True
_ -> Bool
False
isAgentConnectionEstablished :: InternalContext -> IO Bool
isAgentConnectionEstablished :: InternalContext -> IO Bool
isAgentConnectionEstablished context :: InternalContext
context =
STM Bool -> IO Bool
forall a. STM a -> IO a
STM.atomically (STM Bool -> IO Bool) -> STM Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ InternalContext -> STM Bool
isAgentConnectionEstablishedSTM InternalContext
context
readAgentUuidSTM :: InternalContext -> STM (Maybe Text)
readAgentUuidSTM :: InternalContext -> STM (Maybe Text)
readAgentUuidSTM context :: InternalContext
context = do
ConnectionState
state <- TVar ConnectionState -> STM ConnectionState
forall a. TVar a -> STM a
STM.readTVar (TVar ConnectionState -> STM ConnectionState)
-> TVar ConnectionState -> STM ConnectionState
forall a b. (a -> b) -> a -> b
$ InternalContext -> TVar ConnectionState
connectionState InternalContext
context
Maybe Text -> STM (Maybe Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Text -> STM (Maybe Text)) -> Maybe Text -> STM (Maybe Text)
forall a b. (a -> b) -> a -> b
$ (AgentConnection -> Text) -> ConnectionState -> Maybe Text
forall a. (AgentConnection -> a) -> ConnectionState -> Maybe a
mapConnectionState AgentConnection -> Text
agentUuid ConnectionState
state
readAgentUuid :: InternalContext -> IO (Maybe Text)
readAgentUuid :: InternalContext -> IO (Maybe Text)
readAgentUuid context :: InternalContext
context =
STM (Maybe Text) -> IO (Maybe Text)
forall a. STM a -> IO a
STM.atomically (STM (Maybe Text) -> IO (Maybe Text))
-> STM (Maybe Text) -> IO (Maybe Text)
forall a b. (a -> b) -> a -> b
$ InternalContext -> STM (Maybe Text)
readAgentUuidSTM InternalContext
context
readPidSTM :: InternalContext -> STM (Maybe String)
readPidSTM :: InternalContext -> STM (Maybe String)
readPidSTM context :: InternalContext
context = do
ConnectionState
state <- TVar ConnectionState -> STM ConnectionState
forall a. TVar a -> STM a
STM.readTVar (TVar ConnectionState -> STM ConnectionState)
-> TVar ConnectionState -> STM ConnectionState
forall a b. (a -> b) -> a -> b
$ InternalContext -> TVar ConnectionState
connectionState InternalContext
context
Maybe String -> STM (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> STM (Maybe String))
-> Maybe String -> STM (Maybe String)
forall a b. (a -> b) -> a -> b
$ (AgentConnection -> String) -> ConnectionState -> Maybe String
forall a. (AgentConnection -> a) -> ConnectionState -> Maybe a
mapConnectionState AgentConnection -> String
pid ConnectionState
state
readPid :: InternalContext -> IO (Maybe String)
readPid :: InternalContext -> IO (Maybe String)
readPid context :: InternalContext
context =
STM (Maybe String) -> IO (Maybe String)
forall a. STM a -> IO a
STM.atomically (STM (Maybe String) -> IO (Maybe String))
-> STM (Maybe String) -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ InternalContext -> STM (Maybe String)
readPidSTM InternalContext
context
mapConnectionState :: (AgentConnection -> a) -> ConnectionState -> Maybe a
mapConnectionState :: (AgentConnection -> a) -> ConnectionState -> Maybe a
mapConnectionState fn :: AgentConnection -> a
fn state :: ConnectionState
state =
case ConnectionState
state of
AgentReady (Ready agentConnection :: AgentConnection
agentConnection _) ->
a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ AgentConnection -> a
fn AgentConnection
agentConnection
_ ->
Maybe a
forall a. Maybe a
Nothing
whenConnected ::
InternalContext
-> (AgentConnection -> Metrics.Store -> IO ())
-> IO ()
whenConnected :: InternalContext -> (AgentConnection -> Store -> IO ()) -> IO ()
whenConnected context :: InternalContext
context action :: AgentConnection -> Store -> IO ()
action = do
ConnectionState
state <- STM ConnectionState -> IO ConnectionState
forall a. STM a -> IO a
STM.atomically (STM ConnectionState -> IO ConnectionState)
-> STM ConnectionState -> IO ConnectionState
forall a b. (a -> b) -> a -> b
$ TVar ConnectionState -> STM ConnectionState
forall a. TVar a -> STM a
STM.readTVar (TVar ConnectionState -> STM ConnectionState)
-> TVar ConnectionState -> STM ConnectionState
forall a b. (a -> b) -> a -> b
$ InternalContext -> TVar ConnectionState
connectionState InternalContext
context
ConnectionState -> (Ready -> IO ()) -> IO ()
whenConnectedState
ConnectionState
state
(\(Ready agentConnection :: AgentConnection
agentConnection metricsStore :: Store
metricsStore) ->
AgentConnection -> Store -> IO ()
action AgentConnection
agentConnection Store
metricsStore
)
whenConnectedState :: ConnectionState -> (Ready -> IO ()) -> IO ()
whenConnectedState :: ConnectionState -> (Ready -> IO ()) -> IO ()
whenConnectedState state :: ConnectionState
state action :: Ready -> IO ()
action = do
case ConnectionState
state of
Unconnected ->
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
AgentHostLookup ->
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Unannounced _ ->
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Announced _ ->
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
AgentReady ready :: Ready
ready -> do
Ready -> IO ()
action Ready
ready