otel-effectful-1.0.0: src/Effectful/OpenTelemetry/Tracing/Span/Status.hs
module Effectful.OpenTelemetry.Tracing.Span.Status where
import Data.Aeson.Types (ToJSON (..), Value (..))
import Data.Text (Text)
import Data.Text qualified as Text
import Effectful.Exception (Exception, displayException)
import GHC.Generics (Generic)
import Prettyprinter (Pretty (..), annotate)
import Prettyprinter.Extra (PrettyAnn (..))
import Prettyprinter.Extra qualified as Pretty
import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), color, colorDull)
import Proto3.Wire (fromProtoEnum)
import Proto3.Wire.Encode.Class qualified as Proto
import Prelude
-- | The final status of a 'Span'.
-- See <https://opentelemetry.io/docs/specs/otel/trace/api/#set-status the OpenTelemetry spec>.
data Status = Status
{ message :: Text
-- ^ A human readable message, typically an error message.
, code :: Code
}
deriving stock (Generic, Eq, Show)
deriving anyclass (ToJSON)
data Code
= -- | The operation the span tracked successfully completed without an error.
Unset
| -- | The span has been explicitly marked as successful.
Ok
| -- | Some error occurred in the operation the span tracked.
Error
deriving stock (Show, Eq, Enum, Bounded)
instance ToJSON Code where
toJSON = Number . fromIntegral . fromEnum
instance PrettyAnn AnsiStyle Code where
prettyAnn Unset = mempty
prettyAnn Ok = annotate (colorDull Green) "OK"
prettyAnn Error = annotate (color Red) "ERROR"
instance Proto.Encode Status where
encode Status{..} =
mconcat
[ Proto.encodeField 2 message
, Proto.encodeField 3 code
]
instance {-# OVERLAPPING #-} Proto.EncodeField Code where
encodeField n = Proto.encodeField n . fromProtoEnum
instance PrettyAnn AnsiStyle Status where
prettyAnn Status{..} =
Pretty.unwords . filter (not . Pretty.null) $
[ prettyAnn code
, pretty message
]
fromException :: (Exception e) => e -> Status
fromException e =
Status
{ message = Text.pack . displayException $ e
, code = Error
}
-- Create a 'Status' with an 'Ok' code.
ok :: Status
ok =
Status
{ message = mempty
, code = Ok
}
-- Create a 'Status' with an 'Unset' code.
unset :: Status
unset =
Status
{ message = mempty
, code = Unset
}