packages feed

yi-0.3: Yi/Debug.hs

{-# LANGUAGE ParallelListComp #-}

module Yi.Debug (
        initDebug       -- :: FilePath -> IO ()
       ,trace           -- :: String -> a -> a
       ,logPutStrLn
       ,logError
       ,logStream
       ,Yi.Debug.error
    ) where

import Control.Concurrent
import Control.Monad.Trans
import Data.IORef
import System.IO
import System.IO.Unsafe ( unsafePerformIO )
import System.Time

dbgHandle :: IORef Handle
dbgHandle = unsafePerformIO $ newIORef stderr

-- Set the file to which debugging output should be written. Though this
-- is called /init/Debug. This function should be called at most once.
-- Debugging output is sent to stderr by default (i.e., if this function
-- is never called.
initDebug :: FilePath -> IO ()
initDebug f = do
  openFile f WriteMode >>= writeIORef dbgHandle
  logPutStrLn "Logging initialized."

-- Outputs the given string before returning the second argument.
trace :: String -> a -> a
trace s e = unsafePerformIO $ do logPutStrLn s
                                 return e
{-# NOINLINE trace #-}


error :: String -> a
error s = unsafePerformIO $ do logPutStrLn s
                               Prelude.error s

logPutStrLn :: (MonadIO m) => [Char] -> m ()
logPutStrLn s = liftIO $ do
                   time <- toCalendarTime =<< getClockTime
                   tId <- myThreadId
                   h <- readIORef dbgHandle
                   hPutStrLn h $ calendarTimeToString time ++ " " ++ show tId ++ " " ++ s
                   hFlush h

logError :: (MonadIO m) => String -> m ()
logError s = logPutStrLn $ "error: " ++ s

logStream :: Show a => String -> Chan a -> IO ()
logStream msg ch = do
  logPutStrLn $ "Logging stream " ++ msg
  forkIO $ logStreamThread msg  ch
  return ()

logStreamThread :: Show a => String -> Chan a -> IO ()
logStreamThread msg ch = do
  stream <- getChanContents =<< dupChan ch
  mapM_ logPutStrLn [msg ++ "(" ++ show i ++ ")" ++ show event | event <- stream | i <- [(0::Int)..] ]