{-# LANGUAGE LambdaCase #-}
module OpenTelemetry.Internal.Logging (
OTelLogLevel (..),
otelLogError,
otelLogWarning,
otelLogInfo,
otelLogDebug,
getOTelLogLevel,
setGlobalErrorHandler,
getGlobalErrorHandler,
) where
import Data.Char (toLower)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import System.Environment (lookupEnv)
import System.IO (hPutStrLn, stderr)
import System.IO.Unsafe (unsafePerformIO)
data OTelLogLevel
= OTelLogNone
| OTelLogError
| OTelLogWarning
| OTelLogInfo
| OTelLogDebug
deriving (OTelLogLevel -> OTelLogLevel -> Bool
(OTelLogLevel -> OTelLogLevel -> Bool)
-> (OTelLogLevel -> OTelLogLevel -> Bool) -> Eq OTelLogLevel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OTelLogLevel -> OTelLogLevel -> Bool
== :: OTelLogLevel -> OTelLogLevel -> Bool
$c/= :: OTelLogLevel -> OTelLogLevel -> Bool
/= :: OTelLogLevel -> OTelLogLevel -> Bool
Eq, Eq OTelLogLevel
Eq OTelLogLevel =>
(OTelLogLevel -> OTelLogLevel -> Ordering)
-> (OTelLogLevel -> OTelLogLevel -> Bool)
-> (OTelLogLevel -> OTelLogLevel -> Bool)
-> (OTelLogLevel -> OTelLogLevel -> Bool)
-> (OTelLogLevel -> OTelLogLevel -> Bool)
-> (OTelLogLevel -> OTelLogLevel -> OTelLogLevel)
-> (OTelLogLevel -> OTelLogLevel -> OTelLogLevel)
-> Ord OTelLogLevel
OTelLogLevel -> OTelLogLevel -> Bool
OTelLogLevel -> OTelLogLevel -> Ordering
OTelLogLevel -> OTelLogLevel -> OTelLogLevel
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: OTelLogLevel -> OTelLogLevel -> Ordering
compare :: OTelLogLevel -> OTelLogLevel -> Ordering
$c< :: OTelLogLevel -> OTelLogLevel -> Bool
< :: OTelLogLevel -> OTelLogLevel -> Bool
$c<= :: OTelLogLevel -> OTelLogLevel -> Bool
<= :: OTelLogLevel -> OTelLogLevel -> Bool
$c> :: OTelLogLevel -> OTelLogLevel -> Bool
> :: OTelLogLevel -> OTelLogLevel -> Bool
$c>= :: OTelLogLevel -> OTelLogLevel -> Bool
>= :: OTelLogLevel -> OTelLogLevel -> Bool
$cmax :: OTelLogLevel -> OTelLogLevel -> OTelLogLevel
max :: OTelLogLevel -> OTelLogLevel -> OTelLogLevel
$cmin :: OTelLogLevel -> OTelLogLevel -> OTelLogLevel
min :: OTelLogLevel -> OTelLogLevel -> OTelLogLevel
Ord, Int -> OTelLogLevel -> ShowS
[OTelLogLevel] -> ShowS
OTelLogLevel -> [Char]
(Int -> OTelLogLevel -> ShowS)
-> (OTelLogLevel -> [Char])
-> ([OTelLogLevel] -> ShowS)
-> Show OTelLogLevel
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OTelLogLevel -> ShowS
showsPrec :: Int -> OTelLogLevel -> ShowS
$cshow :: OTelLogLevel -> [Char]
show :: OTelLogLevel -> [Char]
$cshowList :: [OTelLogLevel] -> ShowS
showList :: [OTelLogLevel] -> ShowS
Show)
parseLogLevel :: String -> OTelLogLevel
parseLogLevel :: [Char] -> OTelLogLevel
parseLogLevel [Char]
s = case (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower [Char]
s of
[Char]
"none" -> OTelLogLevel
OTelLogNone
[Char]
"error" -> OTelLogLevel
OTelLogError
[Char]
"warn" -> OTelLogLevel
OTelLogWarning
[Char]
"warning" -> OTelLogLevel
OTelLogWarning
[Char]
"info" -> OTelLogLevel
OTelLogInfo
[Char]
"debug" -> OTelLogLevel
OTelLogDebug
[Char]
_ -> OTelLogLevel
OTelLogInfo
cachedLogLevel :: IORef OTelLogLevel
cachedLogLevel :: IORef OTelLogLevel
cachedLogLevel = IO (IORef OTelLogLevel) -> IORef OTelLogLevel
forall a. IO a -> a
unsafePerformIO (IO (IORef OTelLogLevel) -> IORef OTelLogLevel)
-> IO (IORef OTelLogLevel) -> IORef OTelLogLevel
forall a b. (a -> b) -> a -> b
$ do
mEnv <- [Char] -> IO (Maybe [Char])
lookupEnv [Char]
"OTEL_LOG_LEVEL"
newIORef $ case mEnv of
Maybe [Char]
Nothing -> OTelLogLevel
OTelLogInfo
Just [Char]
v -> [Char] -> OTelLogLevel
parseLogLevel [Char]
v
{-# NOINLINE cachedLogLevel #-}
globalErrorHandler :: IORef (String -> IO ())
globalErrorHandler :: IORef ([Char] -> IO ())
globalErrorHandler = IO (IORef ([Char] -> IO ())) -> IORef ([Char] -> IO ())
forall a. IO a -> a
unsafePerformIO (IO (IORef ([Char] -> IO ())) -> IORef ([Char] -> IO ()))
-> IO (IORef ([Char] -> IO ())) -> IORef ([Char] -> IO ())
forall a b. (a -> b) -> a -> b
$ ([Char] -> IO ()) -> IO (IORef ([Char] -> IO ()))
forall a. a -> IO (IORef a)
newIORef (Handle -> [Char] -> IO ()
hPutStrLn Handle
stderr)
{-# NOINLINE globalErrorHandler #-}
setGlobalErrorHandler :: (String -> IO ()) -> IO ()
setGlobalErrorHandler :: ([Char] -> IO ()) -> IO ()
setGlobalErrorHandler = IORef ([Char] -> IO ()) -> ([Char] -> IO ()) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef ([Char] -> IO ())
globalErrorHandler
getGlobalErrorHandler :: IO (String -> IO ())
getGlobalErrorHandler :: IO ([Char] -> IO ())
getGlobalErrorHandler = IORef ([Char] -> IO ()) -> IO ([Char] -> IO ())
forall a. IORef a -> IO a
readIORef IORef ([Char] -> IO ())
globalErrorHandler
getOTelLogLevel :: IO OTelLogLevel
getOTelLogLevel :: IO OTelLogLevel
getOTelLogLevel = IORef OTelLogLevel -> IO OTelLogLevel
forall a. IORef a -> IO a
readIORef IORef OTelLogLevel
cachedLogLevel
{-# INLINE getOTelLogLevel #-}
otelLog :: OTelLogLevel -> String -> String -> IO ()
otelLog :: OTelLogLevel -> [Char] -> [Char] -> IO ()
otelLog OTelLogLevel
minLevel [Char]
prefix [Char]
msg = do
level <- IO OTelLogLevel
getOTelLogLevel
if level >= minLevel
then do
handler <- getGlobalErrorHandler
handler (prefix <> msg)
else pure ()
{-# INLINE otelLog #-}
otelLogError :: String -> IO ()
otelLogError :: [Char] -> IO ()
otelLogError = OTelLogLevel -> [Char] -> [Char] -> IO ()
otelLog OTelLogLevel
OTelLogError [Char]
"OpenTelemetry [ERROR] "
{-# INLINE otelLogError #-}
otelLogWarning :: String -> IO ()
otelLogWarning :: [Char] -> IO ()
otelLogWarning = OTelLogLevel -> [Char] -> [Char] -> IO ()
otelLog OTelLogLevel
OTelLogWarning [Char]
"OpenTelemetry [WARN] "
{-# INLINE otelLogWarning #-}
otelLogInfo :: String -> IO ()
otelLogInfo :: [Char] -> IO ()
otelLogInfo = OTelLogLevel -> [Char] -> [Char] -> IO ()
otelLog OTelLogLevel
OTelLogInfo [Char]
"OpenTelemetry [INFO] "
{-# INLINE otelLogInfo #-}
otelLogDebug :: String -> IO ()
otelLogDebug :: [Char] -> IO ()
otelLogDebug = OTelLogLevel -> [Char] -> [Char] -> IO ()
otelLog OTelLogLevel
OTelLogDebug [Char]
"OpenTelemetry [DEBUG] "
{-# INLINE otelLogDebug #-}