{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE OverloadedStrings #-}
module Instana.SDK.Internal.WireSpan
( QueuedSpan(..)
, WireSpan(..)
, SpanKind(..)
) where
import Control.Applicative ((<|>))
import Data.Aeson (FromJSON, ToJSON, Value, (.:), (.=))
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Extra.Merge as AesonExtra
import Data.Aeson.Types (Parser)
import Data.Text (Text)
import GHC.Generics
import Instana.SDK.Internal.Id (Id)
data SpanKind =
Entry
| Exit
| Intermediate
deriving (Eq, Generic, Show)
instance FromJSON SpanKind where
parseJSON :: Value -> Parser SpanKind
parseJSON = Aeson.withScientific "span kind string" $
\k ->
case k of
1 -> return Entry
2 -> return Exit
3 -> return Intermediate
_ ->
fail "expected numeric span kind (1, 2, or 3)."
instance ToJSON SpanKind where
toJSON :: SpanKind -> Value
toJSON k =
case k of
Entry -> Aeson.Number 1
Exit -> Aeson.Number 2
Intermediate -> Aeson.Number 3
data From = From
{ entityId :: String
, hostId :: Text
} deriving (Eq, Generic, Show)
instance FromJSON From where
parseJSON = Aeson.withObject "from" $
\f ->
From
<$> f .: "e"
<*> f .: "h"
instance ToJSON From where
toJSON :: From -> Value
toJSON f = Aeson.object
[ "e" .= entityId f
, "h" .= hostId f
]
data QueuedSpan = QueuedSpan
{ traceId :: Id
, spanId :: Id
, parentId :: Maybe Id
, spanName :: Text
, timestamp :: Int
, duration :: Int
, kind :: SpanKind
, errorCount :: Int
, serviceName :: Maybe Text
, spanData :: Value
} deriving (Eq, Generic, Show)
data WireSpan = WireSpan
{ queuedSpan :: QueuedSpan
, pid :: String
, agentUuid :: Text
, serviceNameConfig :: Maybe Text
} deriving (Eq, Generic, Show)
instance ToJSON WireSpan where
toJSON :: WireSpan -> Value
toJSON wireSpan =
let
span_ = queuedSpan wireSpan
pid_ = pid wireSpan
agentUuid_ = agentUuid wireSpan
serviceNameConfig_ = serviceNameConfig wireSpan
spanData_ =
case (serviceName span_ <|> serviceNameConfig_) of
Just service ->
AesonExtra.lodashMerge
(spanData span_)
(Aeson.object [ "service" .= service ])
_ ->
spanData span_
in
Aeson.object
[ "t" .= traceId span_
, "s" .= spanId span_
, "p" .= parentId span_
, "n" .= spanName span_
, "ts" .= timestamp span_
, "ta" .= ("haskell" :: String)
, "d" .= duration span_
, "k" .= kind span_
, "ec" .= errorCount span_
, "data" .= spanData_
, "f" .= From pid_ agentUuid_
]