{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Instana.SDK.Internal.Metrics.Sample
( InstanaSample
, InstanaMetricValue(..)
, SampleJson(..)
, TimedSample(..)
, ValueJson(..)
, ekgSampleToInstanaSample
, ekgValueToInstanaValue
, empty
, encodeSample
, encodeValue
, isMarkedForReset
, markForReset
, mkTimedSample
, timedSampleFromEkgSample
) where
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Types as A
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics
import qualified System.Metrics as Metrics
type InstanaSample = HashMap Text InstanaMetricValue
data InstanaMetricValue =
StringValue Text
| IntegralValue Int
| FractionalValue Double
deriving (InstanaMetricValue -> InstanaMetricValue -> Bool
(InstanaMetricValue -> InstanaMetricValue -> Bool)
-> (InstanaMetricValue -> InstanaMetricValue -> Bool)
-> Eq InstanaMetricValue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InstanaMetricValue -> InstanaMetricValue -> Bool
$c/= :: InstanaMetricValue -> InstanaMetricValue -> Bool
== :: InstanaMetricValue -> InstanaMetricValue -> Bool
$c== :: InstanaMetricValue -> InstanaMetricValue -> Bool
Eq, (forall x. InstanaMetricValue -> Rep InstanaMetricValue x)
-> (forall x. Rep InstanaMetricValue x -> InstanaMetricValue)
-> Generic InstanaMetricValue
forall x. Rep InstanaMetricValue x -> InstanaMetricValue
forall x. InstanaMetricValue -> Rep InstanaMetricValue x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep InstanaMetricValue x -> InstanaMetricValue
$cfrom :: forall x. InstanaMetricValue -> Rep InstanaMetricValue x
Generic, Int -> InstanaMetricValue -> ShowS
[InstanaMetricValue] -> ShowS
InstanaMetricValue -> String
(Int -> InstanaMetricValue -> ShowS)
-> (InstanaMetricValue -> String)
-> ([InstanaMetricValue] -> ShowS)
-> Show InstanaMetricValue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InstanaMetricValue] -> ShowS
$cshowList :: [InstanaMetricValue] -> ShowS
show :: InstanaMetricValue -> String
$cshow :: InstanaMetricValue -> String
showsPrec :: Int -> InstanaMetricValue -> ShowS
$cshowsPrec :: Int -> InstanaMetricValue -> ShowS
Show)
ekgSampleToInstanaSample :: Metrics.Sample -> InstanaSample
ekgSampleToInstanaSample :: Sample -> InstanaSample
ekgSampleToInstanaSample =
(Value -> InstanaMetricValue) -> Sample -> InstanaSample
forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
HashMap.map Value -> InstanaMetricValue
ekgValueToInstanaValue
ekgValueToInstanaValue :: Metrics.Value -> InstanaMetricValue
ekgValueToInstanaValue :: Value -> InstanaMetricValue
ekgValueToInstanaValue ekgValue :: Value
ekgValue =
case Value
ekgValue of
Metrics.Label text :: Text
text -> Text -> InstanaMetricValue
StringValue Text
text
Metrics.Counter int64 :: Int64
int64 -> Int -> InstanaMetricValue
IntegralValue (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
int64)
Metrics.Gauge int64 :: Int64
int64 -> Int -> InstanaMetricValue
IntegralValue (Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
int64)
Metrics.Distribution _ -> Text -> InstanaMetricValue
StringValue "distribution"
data TimedSample =
TimedSample
{
TimedSample -> InstanaSample
sample :: InstanaSample
, TimedSample -> Int
timestamp :: Int
, TimedSample -> Bool
resetNext :: Bool
} deriving (TimedSample -> TimedSample -> Bool
(TimedSample -> TimedSample -> Bool)
-> (TimedSample -> TimedSample -> Bool) -> Eq TimedSample
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TimedSample -> TimedSample -> Bool
$c/= :: TimedSample -> TimedSample -> Bool
== :: TimedSample -> TimedSample -> Bool
$c== :: TimedSample -> TimedSample -> Bool
Eq, (forall x. TimedSample -> Rep TimedSample x)
-> (forall x. Rep TimedSample x -> TimedSample)
-> Generic TimedSample
forall x. Rep TimedSample x -> TimedSample
forall x. TimedSample -> Rep TimedSample x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TimedSample x -> TimedSample
$cfrom :: forall x. TimedSample -> Rep TimedSample x
Generic, Int -> TimedSample -> ShowS
[TimedSample] -> ShowS
TimedSample -> String
(Int -> TimedSample -> ShowS)
-> (TimedSample -> String)
-> ([TimedSample] -> ShowS)
-> Show TimedSample
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TimedSample] -> ShowS
$cshowList :: [TimedSample] -> ShowS
show :: TimedSample -> String
$cshow :: TimedSample -> String
showsPrec :: Int -> TimedSample -> ShowS
$cshowsPrec :: Int -> TimedSample -> ShowS
Show)
empty :: Int -> TimedSample
empty :: Int -> TimedSample
empty t :: Int
t =
TimedSample :: InstanaSample -> Int -> Bool -> TimedSample
TimedSample {
sample :: InstanaSample
sample = InstanaSample
forall k v. HashMap k v
HashMap.empty
, timestamp :: Int
timestamp = Int
t
, resetNext :: Bool
resetNext = Bool
False
}
mkTimedSample :: InstanaSample -> Int -> TimedSample
mkTimedSample :: InstanaSample -> Int -> TimedSample
mkTimedSample sampledMetrics :: InstanaSample
sampledMetrics t :: Int
t =
TimedSample :: InstanaSample -> Int -> Bool -> TimedSample
TimedSample {
sample :: InstanaSample
sample = InstanaSample
sampledMetrics
, timestamp :: Int
timestamp = Int
t
, resetNext :: Bool
resetNext = Bool
False
}
timedSampleFromEkgSample :: Metrics.Sample -> Int -> TimedSample
timedSampleFromEkgSample :: Sample -> Int -> TimedSample
timedSampleFromEkgSample sampledMetrics :: Sample
sampledMetrics =
InstanaSample -> Int -> TimedSample
mkTimedSample (Sample -> InstanaSample
ekgSampleToInstanaSample Sample
sampledMetrics)
markForReset :: TimedSample -> TimedSample
markForReset :: TimedSample -> TimedSample
markForReset timedSample :: TimedSample
timedSample =
TimedSample
timedSample { resetNext :: Bool
resetNext = Bool
True }
isMarkedForReset :: TimedSample -> Bool
isMarkedForReset :: TimedSample -> Bool
isMarkedForReset = TimedSample -> Bool
resetNext
encodeSample :: InstanaSample -> A.Value
encodeSample :: InstanaSample -> Value
encodeSample metrics :: InstanaSample
metrics =
InstanaSample -> Value -> Value
buildOne InstanaSample
metrics (Value -> Value) -> Value -> Value
forall a b. (a -> b) -> a -> b
$ Value
A.emptyObject
where
buildOne :: HashMap T.Text InstanaMetricValue -> A.Value -> A.Value
buildOne :: InstanaSample -> Value -> Value
buildOne m :: InstanaSample
m o :: Value
o = (Value -> Text -> InstanaMetricValue -> Value)
-> Value -> InstanaSample -> Value
forall a k v. (a -> k -> v -> a) -> a -> HashMap k v -> a
HashMap.foldlWithKey' Value -> Text -> InstanaMetricValue -> Value
build Value
o InstanaSample
m
build :: A.Value -> T.Text -> InstanaMetricValue -> A.Value
build :: Value -> Text -> InstanaMetricValue -> Value
build m :: Value
m name :: Text
name val :: InstanaMetricValue
val = Value -> [Text] -> InstanaMetricValue -> Value
go Value
m (Text -> Text -> [Text]
T.splitOn "." Text
name) InstanaMetricValue
val
go :: A.Value -> [T.Text] -> InstanaMetricValue -> A.Value
go :: Value -> [Text] -> InstanaMetricValue -> Value
go (A.Object m :: Object
m) [str :: Text
str] val :: InstanaMetricValue
val = Object -> Value
A.Object (Object -> Value) -> Object -> Value
forall a b. (a -> b) -> a -> b
$ Text -> Value -> Object -> Object
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
str Value
metric Object
m
where metric :: Value
metric = InstanaMetricValue -> Value
encodeValue InstanaMetricValue
val
go (A.Object m :: Object
m) (str :: Text
str:rest :: [Text]
rest) val :: InstanaMetricValue
val = case Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
str Object
m of
Nothing -> Object -> Value
A.Object (Object -> Value) -> Object -> Value
forall a b. (a -> b) -> a -> b
$ Text -> Value -> Object -> Object
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
str (Value -> [Text] -> InstanaMetricValue -> Value
go Value
A.emptyObject [Text]
rest InstanaMetricValue
val) Object
m
Just m' :: Value
m' -> Object -> Value
A.Object (Object -> Value) -> Object -> Value
forall a b. (a -> b) -> a -> b
$ Text -> Value -> Object -> Object
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
str (Value -> [Text] -> InstanaMetricValue -> Value
go Value
m' [Text]
rest InstanaMetricValue
val) Object
m
go v :: Value
v _ _ = String -> Value -> Value
forall a. String -> Value -> a
typeMismatch "Object" Value
v
typeMismatch :: String
-> A.Value
-> a
typeMismatch :: String -> Value -> a
typeMismatch expected :: String
expected actual :: Value
actual =
String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ "when expecting a " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
expected String -> ShowS
forall a. [a] -> [a] -> [a]
++ ", encountered " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++
" instead"
where
name :: String
name = case Value
actual of
A.Object _ -> "Object"
A.Array _ -> "Array"
A.String _ -> "String"
A.Number _ -> "Number"
A.Bool _ -> "Boolean"
A.Null -> "Null"
encodeValue :: InstanaMetricValue -> A.Value
encodeValue :: InstanaMetricValue -> Value
encodeValue (IntegralValue n :: Int
n) = Int -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Int
n
encodeValue (FractionalValue f :: Double
f) = Double -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Double
f
encodeValue (StringValue s :: Text
s) = Text -> Value
forall a. ToJSON a => a -> Value
Aeson.toJSON Text
s
newtype SampleJson = SampleJson InstanaSample
deriving Int -> SampleJson -> ShowS
[SampleJson] -> ShowS
SampleJson -> String
(Int -> SampleJson -> ShowS)
-> (SampleJson -> String)
-> ([SampleJson] -> ShowS)
-> Show SampleJson
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SampleJson] -> ShowS
$cshowList :: [SampleJson] -> ShowS
show :: SampleJson -> String
$cshow :: SampleJson -> String
showsPrec :: Int -> SampleJson -> ShowS
$cshowsPrec :: Int -> SampleJson -> ShowS
Show
instance A.ToJSON SampleJson where
toJSON :: SampleJson -> Value
toJSON (SampleJson s :: InstanaSample
s) = InstanaSample -> Value
encodeSample InstanaSample
s
newtype ValueJson = ValueJson InstanaMetricValue
deriving Int -> ValueJson -> ShowS
[ValueJson] -> ShowS
ValueJson -> String
(Int -> ValueJson -> ShowS)
-> (ValueJson -> String)
-> ([ValueJson] -> ShowS)
-> Show ValueJson
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ValueJson] -> ShowS
$cshowList :: [ValueJson] -> ShowS
show :: ValueJson -> String
$cshow :: ValueJson -> String
showsPrec :: Int -> ValueJson -> ShowS
$cshowsPrec :: Int -> ValueJson -> ShowS
Show
instance A.ToJSON ValueJson where
toJSON :: ValueJson -> Value
toJSON (ValueJson v :: InstanaMetricValue
v) = InstanaMetricValue -> Value
encodeValue InstanaMetricValue
v