{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Instana.SDK.Span.Span
Description : A type for spans (entries, exits or intermediates).
-}
module Instana.SDK.Span.Span
  ( Span (Entry, Exit)
  , SpanKind (EntryKind, ExitKind, IntermediateKind)
  , addRegisteredData
  , addRegisteredDataAt
  , addTag
  , addTagAt
  , addToErrorCount
  , correlationId
  , correlationType
  , errorCount
  , parentId
  , serviceName
  , setCorrelationId
  , setCorrelationType
  , setServiceName
  , setSynthetic
  , setW3cTraceContext
  , spanData
  , setTpFlag
  , spanId
  , spanKind
  , spanName
  , synthetic
  , timestamp
  , tpFlag
  , traceId
  , w3cTraceContext
  ) where


import           Data.Aeson                           (Value, (.=))
import qualified Data.Aeson                           as Aeson
import qualified Data.List                            as List
import           Data.Text                            as T
import           GHC.Generics

import           Instana.SDK.Internal.Id              (Id)
import           Instana.SDK.Internal.W3CTraceContext (W3CTraceContext)
import           Instana.SDK.Span.EntrySpan           (EntrySpan)
import qualified Instana.SDK.Span.EntrySpan           as EntrySpan
import           Instana.SDK.Span.ExitSpan            (ExitSpan)
import qualified Instana.SDK.Span.ExitSpan            as ExitSpan


-- |The span kind (entry, exit or intermediate).
data SpanKind =
    -- |The monitored componenent receives a call.
    EntryKind
    -- |The monitored componenent calls something else.
  | ExitKind
    -- |An additional annotation that is added to the trace while a traced call
    -- is being processed.
  | IntermediateKind
  deriving (SpanKind -> SpanKind -> Bool
(SpanKind -> SpanKind -> Bool)
-> (SpanKind -> SpanKind -> Bool) -> Eq SpanKind
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SpanKind -> SpanKind -> Bool
$c/= :: SpanKind -> SpanKind -> Bool
== :: SpanKind -> SpanKind -> Bool
$c== :: SpanKind -> SpanKind -> Bool
Eq, (forall x. SpanKind -> Rep SpanKind x)
-> (forall x. Rep SpanKind x -> SpanKind) -> Generic SpanKind
forall x. Rep SpanKind x -> SpanKind
forall x. SpanKind -> Rep SpanKind x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SpanKind x -> SpanKind
$cfrom :: forall x. SpanKind -> Rep SpanKind x
Generic, Int -> SpanKind -> ShowS
[SpanKind] -> ShowS
SpanKind -> String
(Int -> SpanKind -> ShowS)
-> (SpanKind -> String) -> ([SpanKind] -> ShowS) -> Show SpanKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SpanKind] -> ShowS
$cshowList :: [SpanKind] -> ShowS
show :: SpanKind -> String
$cshow :: SpanKind -> String
showsPrec :: Int -> SpanKind -> ShowS
$cshowsPrec :: Int -> SpanKind -> ShowS
Show)


-- |A span.
data Span =
    Entry EntrySpan
  | Exit ExitSpan
  deriving (Span -> Span -> Bool
(Span -> Span -> Bool) -> (Span -> Span -> Bool) -> Eq Span
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Span -> Span -> Bool
$c/= :: Span -> Span -> Bool
== :: Span -> Span -> Bool
$c== :: Span -> Span -> Bool
Eq, (forall x. Span -> Rep Span x)
-> (forall x. Rep Span x -> Span) -> Generic Span
forall x. Rep Span x -> Span
forall x. Span -> Rep Span x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Span x -> Span
$cfrom :: forall x. Span -> Rep Span x
Generic, Int -> Span -> ShowS
[Span] -> ShowS
Span -> String
(Int -> Span -> ShowS)
-> (Span -> String) -> ([Span] -> ShowS) -> Show Span
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Span] -> ShowS
$cshowList :: [Span] -> ShowS
show :: Span -> String
$cshow :: Span -> String
showsPrec :: Int -> Span -> ShowS
$cshowsPrec :: Int -> Span -> ShowS
Show)


-- |Accessor for the trace ID.
traceId :: Span -> Id
traceId :: Span -> Id
traceId span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Id
EntrySpan.traceId EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Id
ExitSpan.traceId ExitSpan
exit


-- |Accessor for the span ID.
spanId :: Span -> Id
spanId :: Span -> Id
spanId span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Id
EntrySpan.spanId EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Id
ExitSpan.spanId ExitSpan
exit


-- |Parent span ID.
parentId :: Span -> Maybe Id
parentId :: Span -> Maybe Id
parentId span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Maybe Id
EntrySpan.parentId EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> Id -> Maybe Id
forall a. a -> Maybe a
Just (Id -> Maybe Id) -> Id -> Maybe Id
forall a b. (a -> b) -> a -> b
$ ExitSpan -> Id
ExitSpan.parentId ExitSpan
exit


-- |Name of span.
spanName :: Span -> Text
spanName :: Span -> Text
spanName span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Text
EntrySpan.spanName EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Text
ExitSpan.spanName ExitSpan
exit


-- |Kind of span.
spanKind :: Span -> SpanKind
spanKind :: Span -> SpanKind
spanKind span_ :: Span
span_ =
  case Span
span_ of
    Entry _ -> SpanKind
EntryKind
    Exit _  -> SpanKind
ExitKind


-- |Start time.
timestamp :: Span -> Int
timestamp :: Span -> Int
timestamp span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Int
EntrySpan.timestamp EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Int
ExitSpan.timestamp ExitSpan
exit


-- |Error count.
errorCount :: Span -> Int
errorCount :: Span -> Int
errorCount span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Int
EntrySpan.errorCount EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Int
ExitSpan.errorCount ExitSpan
exit


-- |Add to the error count.
addToErrorCount :: Int -> Span -> Span
addToErrorCount :: Int -> Span -> Span
addToErrorCount increment :: Int
increment span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Int -> EntrySpan -> EntrySpan
EntrySpan.addToErrorCount Int
increment EntrySpan
entry
    Exit exit :: ExitSpan
exit ->
      ExitSpan -> Span
Exit (ExitSpan -> Span) -> ExitSpan -> Span
forall a b. (a -> b) -> a -> b
$ Int -> ExitSpan -> ExitSpan
ExitSpan.addToErrorCount Int
increment ExitSpan
exit


-- |An optional attribute for overriding the name of the service in Instana.
serviceName :: Span -> Maybe Text
serviceName :: Span -> Maybe Text
serviceName span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Maybe Text
EntrySpan.serviceName EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Maybe Text
ExitSpan.serviceName ExitSpan
exit


-- |Override the name of the service for the associated call in Instana.
setServiceName :: Text -> Span -> Span
setServiceName :: Text -> Span -> Span
setServiceName serviceName_ :: Text
serviceName_ span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Text -> EntrySpan -> EntrySpan
EntrySpan.setServiceName Text
serviceName_ EntrySpan
entry
    Exit exit :: ExitSpan
exit ->
      ExitSpan -> Span
Exit (ExitSpan -> Span) -> ExitSpan -> Span
forall a b. (a -> b) -> a -> b
$ Text -> ExitSpan -> ExitSpan
ExitSpan.setServiceName Text
serviceName_ ExitSpan
exit


-- |The website monitoring correlation type.
correlationType :: Span -> Maybe Text
correlationType :: Span -> Maybe Text
correlationType span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Maybe Text
EntrySpan.correlationType EntrySpan
entry
    Exit _      -> Maybe Text
forall a. Maybe a
Nothing


-- |Set the website monitoring correlation type. This should only be set on
-- root entry spans. It will be silently ignored for other types of spans.
setCorrelationType :: Text -> Span -> Span
setCorrelationType :: Text -> Span -> Span
setCorrelationType correlationType_ :: Text
correlationType_ span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Text -> EntrySpan -> EntrySpan
EntrySpan.setCorrelationType Text
correlationType_ EntrySpan
entry
    Exit _ ->
      Span
span_


-- |The website monitoring correlation ID.
correlationId :: Span -> Maybe Text
correlationId :: Span -> Maybe Text
correlationId span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Maybe Text
EntrySpan.correlationId EntrySpan
entry
    Exit _      -> Maybe Text
forall a. Maybe a
Nothing


-- |Set the website monitoring correlation ID. This should only be set on
-- root entry spans. It will be silently ignored for other types of spans.
setCorrelationId :: Text -> Span -> Span
setCorrelationId :: Text -> Span -> Span
setCorrelationId correlationId_ :: Text
correlationId_ span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Text -> EntrySpan -> EntrySpan
EntrySpan.setCorrelationId Text
correlationId_ EntrySpan
entry
    Exit _ ->
      Span
span_


-- |The W3C Trace Context. An entry span only has an associated W3C trace
-- context, if W3C trace context headers have been received. In contrast,
-- exit spans always have an associated W3C trace context.
w3cTraceContext :: Span -> Maybe W3CTraceContext
w3cTraceContext :: Span -> Maybe W3CTraceContext
w3cTraceContext span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Maybe W3CTraceContext
EntrySpan.w3cTraceContext EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> W3CTraceContext -> Maybe W3CTraceContext
forall a. a -> Maybe a
Just (W3CTraceContext -> Maybe W3CTraceContext)
-> W3CTraceContext -> Maybe W3CTraceContext
forall a b. (a -> b) -> a -> b
$ ExitSpan -> W3CTraceContext
ExitSpan.w3cTraceContext ExitSpan
exit


-- |Attaches a W3C trace context to the span.
setW3cTraceContext :: W3CTraceContext -> Span -> Span
setW3cTraceContext :: W3CTraceContext -> Span -> Span
setW3cTraceContext w3cTraceContext_ :: W3CTraceContext
w3cTraceContext_ span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ W3CTraceContext -> EntrySpan -> EntrySpan
EntrySpan.setW3cTraceContext W3CTraceContext
w3cTraceContext_ EntrySpan
entry
    Exit exit :: ExitSpan
exit ->
      ExitSpan -> Span
Exit (ExitSpan -> Span) -> ExitSpan -> Span
forall a b. (a -> b) -> a -> b
$ W3CTraceContext -> ExitSpan -> ExitSpan
ExitSpan.setW3cTraceContext W3CTraceContext
w3cTraceContext_ ExitSpan
exit


-- |The span.tp flag. A span with span.tp = True has inherited the trace ID/
-- parent ID from W3C trace context instead of Instana headers. Only valid for
-- non-root entry spans.
tpFlag :: Span -> Bool
tpFlag :: Span -> Bool
tpFlag span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Bool
EntrySpan.tpFlag EntrySpan
entry
    Exit _      -> Bool
False


-- |Set the span.tp flag. A span with span.tp = True has inherited the trace ID/
-- parent ID from W3C trace context instead of Instana headers. Only valid for
-- non-root entry spans, will be silently ignored for root entry spans and exit
-- spans.
setTpFlag :: Span -> Span
setTpFlag :: Span -> Span
setTpFlag span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ EntrySpan -> EntrySpan
EntrySpan.setTpFlag EntrySpan
entry
    Exit _ ->
      Span
span_


-- |The synthetic flag.
synthetic :: Span -> Bool
synthetic :: Span -> Bool
synthetic span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Bool
EntrySpan.synthetic EntrySpan
entry
    Exit _      -> Bool
False


-- |Set the synthetic flag. This should only be set on entry spans. It will be
-- silently ignored for other types of spans.
setSynthetic :: Bool -> Span -> Span
setSynthetic :: Bool -> Span -> Span
setSynthetic synthetic_ :: Bool
synthetic_ span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry ->
      EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Bool -> EntrySpan -> EntrySpan
EntrySpan.setSynthetic Bool
synthetic_ EntrySpan
entry
    Exit _ ->
      Span
span_


-- |Optional additional span data.
spanData :: Span -> Value
spanData :: Span -> Value
spanData span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Value
EntrySpan.spanData EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Value
ExitSpan.spanData ExitSpan
exit


-- |Add a value to the span's custom tags section. This should be used for SDK
-- spans instead of addRegisteredData.
addTag :: Value -> Span -> Span
addTag :: Value -> Span -> Span
addTag value :: Value
value span_ :: Span
span_ =
  Text -> Value -> Span -> Span
forall a. ToJSON a => Text -> a -> Span -> Span
addRegisteredDataAt "sdk.custom.tags" Value
value Span
span_


-- |Add a value to the given path to the span's custom tags section. This should
-- be used for SDK spans instead of addRegisteredDataAt.
addTagAt :: Aeson.ToJSON a => Text -> a -> Span -> Span
addTagAt :: Text -> a -> Span -> Span
addTagAt path :: Text
path value :: a
value span_ :: Span
span_ =
  Text -> a -> Span -> Span
forall a. ToJSON a => Text -> a -> Span -> Span
addRegisteredDataAt ([Text] -> Text
T.concat ["sdk.custom.tags.", Text
path]) a
value Span
span_



-- |Add a value to the span's data section. This should only be used for
-- registered spans, not for SDK spans. For SDK spans, you should use addTag
-- instead.
addRegisteredData :: Value -> Span -> Span
addRegisteredData :: Value -> Span -> Span
addRegisteredData value :: Value
value span_ :: Span
span_ =
  case Span
span_ of
    Entry entry :: EntrySpan
entry -> EntrySpan -> Span
Entry (EntrySpan -> Span) -> EntrySpan -> Span
forall a b. (a -> b) -> a -> b
$ Value -> EntrySpan -> EntrySpan
EntrySpan.addData Value
value EntrySpan
entry
    Exit exit :: ExitSpan
exit   -> ExitSpan -> Span
Exit (ExitSpan -> Span) -> ExitSpan -> Span
forall a b. (a -> b) -> a -> b
$ Value -> ExitSpan -> ExitSpan
ExitSpan.addData Value
value ExitSpan
exit


-- |Add a value at the given path to the span's data section. For SDK spans, you
-- should use addTagAt instead.
addRegisteredDataAt :: Aeson.ToJSON a => Text -> a -> Span -> Span
addRegisteredDataAt :: Text -> a -> Span -> Span
addRegisteredDataAt path :: Text
path value :: a
value span_ :: Span
span_ =
  let
    pathSegments :: [Text]
pathSegments = Text -> Text -> [Text]
T.splitOn "." Text
path
    newData :: Value
newData = (Text -> Value -> Value) -> Value -> [Text] -> Value
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
List.foldr
      (\nextPathSegment :: Text
nextPathSegment accumulatedAesonValue :: Value
accumulatedAesonValue ->
        [Pair] -> Value
Aeson.object [
          Text
nextPathSegment Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Value
accumulatedAesonValue
        ]
      )
      (a -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON a
value)
      [Text]
pathSegments
  in
  Value -> Span -> Span
addRegisteredData Value
newData Span
span_