{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
module OpenTelemetry.SemanticsConfig (
SemanticsOptions,
StabilityOpt (..),
HttpOption,
lookupStability,
httpOption,
databaseOption,
codeOption,
getSemanticsOptions,
getSemanticsOptions',
) where
import Control.Exception (SomeException, throwIO, try)
import qualified Data.HashSet as Set
import Data.IORef (newIORef, readIORef, writeIORef)
import qualified Data.Text as T
import System.Environment (lookupEnv)
import System.IO.Unsafe (unsafePerformIO)
newtype SemanticsOptions = SemanticsOptions (Set.HashSet T.Text)
data StabilityOpt
= Stable
| StableAndOld
| Old
deriving (Int -> StabilityOpt -> ShowS
[StabilityOpt] -> ShowS
StabilityOpt -> String
(Int -> StabilityOpt -> ShowS)
-> (StabilityOpt -> String)
-> ([StabilityOpt] -> ShowS)
-> Show StabilityOpt
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StabilityOpt -> ShowS
showsPrec :: Int -> StabilityOpt -> ShowS
$cshow :: StabilityOpt -> String
show :: StabilityOpt -> String
$cshowList :: [StabilityOpt] -> ShowS
showList :: [StabilityOpt] -> ShowS
Show, StabilityOpt -> StabilityOpt -> Bool
(StabilityOpt -> StabilityOpt -> Bool)
-> (StabilityOpt -> StabilityOpt -> Bool) -> Eq StabilityOpt
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StabilityOpt -> StabilityOpt -> Bool
== :: StabilityOpt -> StabilityOpt -> Bool
$c/= :: StabilityOpt -> StabilityOpt -> Bool
/= :: StabilityOpt -> StabilityOpt -> Bool
Eq)
type HttpOption = StabilityOpt
lookupStability :: T.Text -> SemanticsOptions -> StabilityOpt
lookupStability :: Text -> SemanticsOptions -> StabilityOpt
lookupStability Text
key (SemanticsOptions HashSet Text
vals)
| (Text
key Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/dup") Text -> HashSet Text -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`Set.member` HashSet Text
vals = StabilityOpt
StableAndOld
| Text
key Text -> HashSet Text -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`Set.member` HashSet Text
vals = StabilityOpt
Stable
| Bool
otherwise = StabilityOpt
Old
httpOption :: SemanticsOptions -> StabilityOpt
httpOption :: SemanticsOptions -> StabilityOpt
httpOption = Text -> SemanticsOptions -> StabilityOpt
lookupStability Text
"http"
databaseOption :: SemanticsOptions -> StabilityOpt
databaseOption :: SemanticsOptions -> StabilityOpt
databaseOption = Text -> SemanticsOptions -> StabilityOpt
lookupStability Text
"database"
codeOption :: SemanticsOptions -> StabilityOpt
codeOption :: SemanticsOptions -> StabilityOpt
codeOption = Text -> SemanticsOptions -> StabilityOpt
lookupStability Text
"code"
parseSemanticsOptions :: Maybe String -> SemanticsOptions
parseSemanticsOptions :: Maybe String -> SemanticsOptions
parseSemanticsOptions Maybe String
Nothing = HashSet Text -> SemanticsOptions
SemanticsOptions HashSet Text
forall a. HashSet a
Set.empty
parseSemanticsOptions (Just String
env) =
HashSet Text -> SemanticsOptions
SemanticsOptions (HashSet Text -> SemanticsOptions)
-> HashSet Text -> SemanticsOptions
forall a b. (a -> b) -> a -> b
$ [Text] -> HashSet Text
forall a. (Eq a, Hashable a) => [a] -> HashSet a
Set.fromList ([Text] -> HashSet Text) -> [Text] -> HashSet Text
forall a b. (a -> b) -> a -> b
$ (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
T.strip ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ HasCallStack => Text -> Text -> [Text]
Text -> Text -> [Text]
T.splitOn Text
"," (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
env
getSemanticsOptions' :: IO SemanticsOptions
getSemanticsOptions' :: IO SemanticsOptions
getSemanticsOptions' = Maybe String -> SemanticsOptions
parseSemanticsOptions (Maybe String -> SemanticsOptions)
-> IO (Maybe String) -> IO SemanticsOptions
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
lookupEnv String
"OTEL_SEMCONV_STABILITY_OPT_IN"
memoize :: IO a -> IO (IO a)
memoize :: forall a. IO a -> IO (IO a)
memoize IO a
action = do
ref <- Maybe (Either SomeException a)
-> IO (IORef (Maybe (Either SomeException a)))
forall a. a -> IO (IORef a)
newIORef Maybe (Either SomeException a)
forall a. Maybe a
Nothing
pure $ do
mres <- readIORef ref
res <- case mres of
Just Either SomeException a
res -> Either SomeException a -> IO (Either SomeException a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Either SomeException a
res
Maybe (Either SomeException a)
Nothing -> do
res <- forall e a. Exception e => IO a -> IO (Either e a)
try @SomeException IO a
action
writeIORef ref $ Just res
pure res
either throwIO pure res
getSemanticsOptions :: IO SemanticsOptions
getSemanticsOptions :: IO SemanticsOptions
getSemanticsOptions = IO (IO SemanticsOptions) -> IO SemanticsOptions
forall a. IO a -> a
unsafePerformIO (IO (IO SemanticsOptions) -> IO SemanticsOptions)
-> IO (IO SemanticsOptions) -> IO SemanticsOptions
forall a b. (a -> b) -> a -> b
$ IO SemanticsOptions -> IO (IO SemanticsOptions)
forall a. IO a -> IO (IO a)
memoize IO SemanticsOptions
getSemanticsOptions'
{-# NOINLINE getSemanticsOptions #-}