packages feed

hs-opentelemetry-api-1.0.0.0: test/OpenTelemetry/Internal/LoggingSpec.hs

{-# LANGUAGE LambdaCase #-}

module OpenTelemetry.Internal.LoggingSpec (spec) where

import Control.Exception (bracket_)
import Data.IORef
import Data.List (isInfixOf)
import OpenTelemetry.Internal.Logging
import Test.Hspec


spec :: Spec
spec = sequential $
  describe "OpenTelemetry.Internal.Logging" $ do
    -- Implementation-specific: internal log level ordering for filtering
    -- https://opentelemetry.io/docs/specs/otel/error-handling/
    describe "OTelLogLevel" $ do
      it "orders None < Error < Warning < Info < Debug" $ do
        OTelLogNone `shouldSatisfy` (< OTelLogError)
        OTelLogError `shouldSatisfy` (< OTelLogWarning)
        OTelLogWarning `shouldSatisfy` (< OTelLogInfo)
        OTelLogInfo `shouldSatisfy` (< OTelLogDebug)

    -- Error handling §Error handling principles: global error handler
    -- https://opentelemetry.io/docs/specs/otel/error-handling/
    describe "global error handler" $ do
      it "setGlobalErrorHandler and getGlobalErrorHandler roundtrip" $ do
        ref <- newIORef ([] :: [String])
        old <- getGlobalErrorHandler
        let custom msg = modifyIORef ref (msg :)
        bracket_
          (setGlobalErrorHandler custom)
          (setGlobalErrorHandler old)
          $ do
            handler <- getGlobalErrorHandler
            handler "probe"
            msgs <- readIORef ref
            msgs `shouldBe` ["probe"]

      it "otelLogError passes a message containing ERROR and the payload" $ do
        captured <- newIORef Nothing
        old <- getGlobalErrorHandler
        let custom msg = writeIORef captured (Just msg)
        bracket_
          (setGlobalErrorHandler custom)
          (setGlobalErrorHandler old)
          $ do
            otelLogError "test"
            mmsg <- readIORef captured
            mmsg `shouldSatisfy` \case
              Just msg -> "ERROR" `isInfixOf` msg && "test" `isInfixOf` msg
              Nothing -> False

      it "otelLogWarning passes a message containing WARN and the payload" $ do
        captured <- newIORef Nothing
        old <- getGlobalErrorHandler
        let custom msg = writeIORef captured (Just msg)
        bracket_
          (setGlobalErrorHandler custom)
          (setGlobalErrorHandler old)
          $ do
            otelLogWarning "notice"
            mmsg <- readIORef captured
            mmsg `shouldSatisfy` \case
              Just msg -> "WARN" `isInfixOf` msg && "notice" `isInfixOf` msg
              Nothing -> False

      it "invokes the handler only when getOTelLogLevel reaches each minimum" $ do
        lvl <- getOTelLogLevel
        called <- newIORef False
        old <- getGlobalErrorHandler
        let mark _ = writeIORef called True
        let reset = writeIORef called False
        bracket_
          (setGlobalErrorHandler mark)
          (setGlobalErrorHandler old)
          $ do
            reset
            otelLogDebug "x"
            readIORef called >>= (`shouldBe` (lvl >= OTelLogDebug))
            reset
            otelLogInfo "x"
            readIORef called >>= (`shouldBe` (lvl >= OTelLogInfo))
            reset
            otelLogError "x"
            readIORef called >>= (`shouldBe` (lvl >= OTelLogError))