packages feed

wasmedge-hs-0.17.1.0: examples/Stress/LoggingDiagnostic.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}

{- |
Module      : Stress.LoggingDiagnostic
Description : Diagnostic logging levels, log silencing, and custom structured callback verification
Copyright   : (c) 2026 Tushar Adhatrao
License     : MIT
Stability   : experimental

Exercises:
  * 'setLogLevel' (LogTrace, LogDebug, LogInfo, LogWarn, LogError, LogCritical)
  * 'setLogError'
  * 'setLogDebug'
  * 'logOff'
  * 'setLogCallback'
  * 'clearLogCallback'
  * Structured 'LogMessage' capture
-}
module Stress.LoggingDiagnostic
  ( runLoggingDiagnosticSuite
  , LoggingMetrics (..)
  ) where

import Control.Monad (forM_)
import Data.IORef
import Data.Text qualified as T
import System.Clock (Clock (Monotonic), diffTimeSpec, getTime, toNanoSecs)
import Text.Printf (printf)

import Stress.WasmBytecode (corruptedMagicWasm)
import WasmEdge (createVM, runWasmBytes)
import WasmEdge.Log
  ( LogLevel (..)
  , LogMessage (..)
  , clearLogCallback
  , logOff
  , setLogCallback
  , setLogDebug
  , setLogError
  , setLogLevel
  )

data LoggingMetrics = LoggingMetrics
  { lmAllLevelsExercised :: !Bool
  , lmCallbackFired :: !Bool
  , lmSilencingVerified :: !Bool
  , logmDurationSec :: !Double
  }
  deriving stock (Show)

runLoggingDiagnosticSuite :: IO LoggingMetrics
runLoggingDiagnosticSuite = do
  putStrLn "============================================================"
  putStrLn "  STRESS TEST: Runtime Logging & Diagnostic Callbacks"
  putStrLn "============================================================"

  t0 <- getTime Monotonic

  -- 1. Exercise all LogLevel switches
  putStrLn "[1/4] Switching across all LogLevel values..."
  let allLevels = [LogTrace, LogDebug, LogInfo, LogWarn, LogError, LogCritical]
  forM_ allLevels $ \lvl -> do
    setLogLevel lvl

  setLogDebug
  setLogError
  putStrLn "      All LogLevel switches completed successfully."

  -- 2. Test custom log callback capturing WasmEdge internal diagnostic messages
  putStrLn "[2/4] Registering custom structured log callback..."
  capturedLogsRef <- newIORef ([] :: [LogMessage])
  setLogCallback $ \msg -> do
    modifyIORef' capturedLogsRef (msg :)

  -- Deliberately trigger an internal WasmEdge error with invalid magic bytes
  setLogLevel LogError
  vm <- createVM Nothing Nothing
  _ <- runWasmBytes vm corruptedMagicWasm "dummy" []

  -- Check captured messages
  captured <- readIORef capturedLogsRef
  printf "      Structured log messages intercepted: %d\n" (length captured)
  forM_ (take 2 captured) $ \msg ->
    printf
      "        [%s] (%s): %s\n"
      (show (logMsgLevel msg))
      (T.unpack (logMsgLogger msg))
      (T.unpack (logMsgText msg))

  let callbackWorked = not (null captured)

  -- 3. Clear log callback
  putStrLn "[3/4] Clearing custom log callback..."
  clearLogCallback

  -- 4. Test logOff (silencing output)
  putStrLn "[4/4] Verifying logOff silencing..."
  logOff
  -- Trigger another error while logging is off
  _ <- runWasmBytes vm corruptedMagicWasm "dummy" []
  putStrLn "      logOff active, output suppressed."

  -- Restore to LogError to keep normal test output clean
  setLogError

  t1 <- getTime Monotonic
  let dur = fromIntegral (toNanoSecs (diffTimeSpec t1 t0)) / 1e9 :: Double
  printf ">>> Logging Diagnostic Suite completed in %.3f s\n\n" dur

  pure
    LoggingMetrics
      { lmAllLevelsExercised = True
      , lmCallbackFired = callbackWorked
      , lmSilencingVerified = True
      , logmDurationSec = dur
      }