+{-# NOINLINE tracers #-}
+tracers :: IORef [(String, String -> IO ())]
+tracers = unsafePerformIO (newIORef [("defaultTracer", fileTracer stderr)])
+
+-- | A tracer function that outputs the message to a file
+fileTracer :: Handle -- ^ file handle
+ -> String -- ^ trace message
+ -> IO ()
+fileTracer handle msg = do
+ hPutStr handle msg
+ hPutChar handle '\n'
+
+#ifdef mingw32_HOST_OS
+-- | A tracer function that outputs the message to the debuger (Windows only)
+winDebugTracer :: String -- ^ trace message
+ -> IO ()
+winDebugTracer msg = do
+ withCString (msg++"\n") outputDebugString
+
+foreign import ccall unsafe "OutputDebugStringA"
+ outputDebugString :: CString -> IO ()
+#endif
+
+-- | Registering a new tracer
+addTracer :: String -- ^ the tracer name
+ -> (String -> IO ()) -- ^ tracer
+ -> IO ()
+addTracer name tracer = do
+ ts <- readIORef tracers
+ writeIORef tracers ((name,tracer):filter (\(n,l) -> n /= name) ts)
+
+-- | Removing the tracer with the given name
+removeTracer :: String -> IO ()
+removeTracer name = do
+ ts <- readIORef tracers
+ writeIORef tracers (filter (\(n,l) -> n /= name) ts)
+
+-- | 'putTraceMsg' function outputs the trace message from IO monad.
+putTraceMsg :: String -> IO ()
+putTraceMsg msg = do
+ ts <- readIORef tracers
+ mapM_ (\(n,l) -> l msg) ts
+