{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-cse #-}
module Snap.Internal.Debug (debug, debugErrno) where
import Control.Monad.IO.Class (MonadIO (..))
#ifndef NODEBUG
import Control.Concurrent (MVar, myThreadId, newMVar, withMVar)
import Control.Exception (SomeException, try)
import Data.Char (toLower)
import Data.List (stripPrefix)
import Data.Maybe (fromMaybe)
import Foreign.C.Error (errnoToIOError, getErrno)
import System.Environment (getEnv)
import System.IO (hFlush, hPutStrLn, stderr)
import System.IO.Unsafe (unsafePerformIO)
import Text.Printf (printf)
#endif
debug :: MonadIO m => String -> m ()
debugErrno :: MonadIO m => String -> m ()
#ifndef NODEBUG
{-# NOINLINE debug #-}
debug = let !x = unsafePerformIO $ do
!e <- try $ getEnv "DEBUG"
!f <- either (\(_::SomeException) -> return debugIgnore)
(\y0 -> let y = map toLower y0
in if y == "1" || y == "on"
then return debugOn
else if y == "testsuite"
then return debugSeq
else return debugIgnore)
e
return $! f
in x
{-# NOINLINE debugErrno #-}
debugErrno = let !x = unsafePerformIO $ do
e <- try $ getEnv "DEBUG"
!f <- either (\(_::SomeException) -> return debugErrnoIgnore)
(\y0 -> let y = map toLower y0
in if y == "1" || y == "on"
then return debugErrnoOn
else if y == "testsuite"
then return debugSeq
else return debugErrnoIgnore)
e
return $! f
in x
debugSeq :: (MonadIO m) => String -> m ()
debugSeq !s = length s `seq` return $! ()
{-# NOINLINE debugSeq #-}
_debugMVar :: MVar ()
_debugMVar = unsafePerformIO $ newMVar ()
{-# NOINLINE _debugMVar #-}
debugOn :: (MonadIO m) => String -> m ()
debugOn s = liftIO $ withMVar _debugMVar $ \_ -> do
tid <- myThreadId
hPutStrLn stderr $ s' tid
hFlush stderr
where
chop x = let y = fromMaybe x $ stripPrefix "ThreadId " x
in printf "%8s" y
s' t = "[" ++ chop (show t) ++ "] " ++ s
{-# NOINLINE debugOn #-}
debugErrnoOn :: (MonadIO m) => String -> m ()
debugErrnoOn loc = liftIO $ do
err <- getErrno
let ex = errnoToIOError loc err Nothing Nothing
debug $ show ex
#else
debug = debugIgnore
{-# INLINE debug #-}
debugErrno = debugErrnoIgnore
{-# INLINE debugErrno #-}
#endif
debugIgnore :: (MonadIO m) => String -> m ()
debugIgnore _ = return ()
{-# INLINE debugIgnore #-}
debugErrnoIgnore :: (MonadIO m) => String -> m ()
debugErrnoIgnore _ = return ()
{-# INLINE debugErrnoIgnore #-}