{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE InstanceSigs      #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Instana.SDK.Span.SpanType
Description : Describes the type of a span, either an SDK span or a
              registered span.
-}
module Instana.SDK.Span.SpanType
  ( Registered (..)
  , SpanType (SdkSpan, RegisteredSpan)
  , spanName
  , initialData
  ) where


import           Data.Aeson            (Value, (.=))
import qualified Data.Aeson            as Aeson
import           Data.String           (IsString (fromString))
import           Data.Text             (Text)
import qualified Data.Text             as T
import           GHC.Generics

import           Instana.SDK.Span.Span (SpanKind (EntryKind, ExitKind, IntermediateKind))


-- |Differentiates between SDK spans and registered spans (which receive
-- special treatment by Instana's processing pipeline.
data SpanType =
    SdkSpan Text
  | RegisteredSpan Registered
  deriving (SpanType -> SpanType -> Bool
(SpanType -> SpanType -> Bool)
-> (SpanType -> SpanType -> Bool) -> Eq SpanType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SpanType -> SpanType -> Bool
$c/= :: SpanType -> SpanType -> Bool
== :: SpanType -> SpanType -> Bool
$c== :: SpanType -> SpanType -> Bool
Eq, (forall x. SpanType -> Rep SpanType x)
-> (forall x. Rep SpanType x -> SpanType) -> Generic SpanType
forall x. Rep SpanType x -> SpanType
forall x. SpanType -> Rep SpanType x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SpanType x -> SpanType
$cfrom :: forall x. SpanType -> Rep SpanType x
Generic, Int -> SpanType -> ShowS
[SpanType] -> ShowS
SpanType -> String
(Int -> SpanType -> ShowS)
-> (SpanType -> String) -> ([SpanType] -> ShowS) -> Show SpanType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SpanType] -> ShowS
$cshowList :: [SpanType] -> ShowS
show :: SpanType -> String
$cshow :: SpanType -> String
showsPrec :: Int -> SpanType -> ShowS
$cshowsPrec :: Int -> SpanType -> ShowS
Show)


-- |All registered spans that the Haskell trace SDK will produce.
data Registered =
    HaskellWaiServer
  | HaskellHttpClient
  deriving (Registered -> Registered -> Bool
(Registered -> Registered -> Bool)
-> (Registered -> Registered -> Bool) -> Eq Registered
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Registered -> Registered -> Bool
$c/= :: Registered -> Registered -> Bool
== :: Registered -> Registered -> Bool
$c== :: Registered -> Registered -> Bool
Eq, (forall x. Registered -> Rep Registered x)
-> (forall x. Rep Registered x -> Registered) -> Generic Registered
forall x. Rep Registered x -> Registered
forall x. Registered -> Rep Registered x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Registered x -> Registered
$cfrom :: forall x. Registered -> Rep Registered x
Generic, Int -> Registered -> ShowS
[Registered] -> ShowS
Registered -> String
(Int -> Registered -> ShowS)
-> (Registered -> String)
-> ([Registered] -> ShowS)
-> Show Registered
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Registered] -> ShowS
$cshowList :: [Registered] -> ShowS
show :: Registered -> String
$cshow :: Registered -> String
showsPrec :: Int -> Registered -> ShowS
$cshowsPrec :: Int -> Registered -> ShowS
Show)


-- |Returns the wire value of span.n for a SpanType value.
spanName    :: SpanType -> Text
spanName :: SpanType -> Text
spanName    (SdkSpan _)                 = "sdk"
spanName    (RegisteredSpan registered :: Registered
registered) = Registered -> Text
registeredSpanName Registered
registered


-- |Returns the wire value of span.n for a registered span.
registeredSpanName :: Registered -> Text
registeredSpanName :: Registered -> Text
registeredSpanName HaskellWaiServer  = "haskell.wai.server"
registeredSpanName HaskellHttpClient = "haskell.http.client"


-- |Returns the initial data (span.data) for a SpanType value.
initialData :: SpanKind -> SpanType -> Value
initialData :: SpanKind -> SpanType -> Value
initialData kind :: SpanKind
kind (SdkSpan s :: Text
s)     = SpanKind -> Text -> Value
initialSdkData SpanKind
kind Text
s
initialData _ (RegisteredSpan _) = Value
emptyValue


-- |Enables passing any string as the span type argument to SDK.startEntrySpan
-- etc. - this will be automatically converted to an SDK span.
instance IsString SpanType where
  fromString :: String -> SpanType
  fromString :: String -> SpanType
fromString s :: String
s = Text -> SpanType
SdkSpan (Text -> SpanType) -> Text -> SpanType
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
s


-- |Provides the initial data for an SDK span.
initialSdkData :: SpanKind -> Text -> Value
initialSdkData :: SpanKind -> Text -> Value
initialSdkData kind :: SpanKind
kind spanName_ :: Text
spanName_ =
  let
    sdkKind :: String
    sdkKind :: String
sdkKind =
      case SpanKind
kind of
        EntryKind        -> "entry"
        ExitKind         -> "exit"
        IntermediateKind -> "intermediate"
  in
  ([Pair] -> Value
Aeson.object [ "sdk" Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.=
    [Pair] -> Value
Aeson.object
      [ "name" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
spanName_
      , "type" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String
sdkKind
      ]
    ]
  )


-- |Provides an empty Aeson value.
emptyValue :: Value
emptyValue :: Value
emptyValue = [Pair] -> Value
Aeson.object []