diff options
Diffstat (limited to 'src/DPut.hs')
-rw-r--r-- | src/DPut.hs | 55 |
1 files changed, 24 insertions, 31 deletions
diff --git a/src/DPut.hs b/src/DPut.hs index 6fd69040..38e532d0 100644 --- a/src/DPut.hs +++ b/src/DPut.hs | |||
@@ -1,3 +1,5 @@ | |||
1 | {-# LANGUAGE ConstraintKinds #-} | ||
2 | {-# LANGUAGE ScopedTypeVariables #-} | ||
1 | module DPut where | 3 | module DPut where |
2 | 4 | ||
3 | import Control.Monad.IO.Class | 5 | import Control.Monad.IO.Class |
@@ -10,26 +12,10 @@ import qualified Data.ByteString.Char8 as B | |||
10 | import qualified Data.Text as T | 12 | import qualified Data.Text as T |
11 | import qualified Data.Text.Encoding as T | 13 | import qualified Data.Text.Encoding as T |
12 | import Debug.Trace | 14 | import Debug.Trace |
15 | import Data.Typeable | ||
16 | import Data.Dynamic | ||
13 | 17 | ||
14 | -- | Debug Tags, add more as needed, but ensure XAnnounce is always first, XMisc last | 18 | type IsDebugTag t = (Eq t, Ord t, Show t, Read t, Enum t, Bounded t,Typeable t) |
15 | data DebugTag | ||
16 | = XAnnounce | ||
17 | | XBitTorrent | ||
18 | | XDHT | ||
19 | | XLan | ||
20 | | XMan | ||
21 | | XNetCrypto | ||
22 | | XNetCryptoOut | ||
23 | | XOnion | ||
24 | | XRoutes | ||
25 | | XPing | ||
26 | | XRefresh | ||
27 | | XJabber | ||
28 | | XMisc | ||
29 | | XNodeinfoSearch | ||
30 | | XUnexpected -- Used only for special anomalous errors that we didn't expect to happen. | ||
31 | | XUnused -- Never commit code that uses XUnused. | ||
32 | deriving (Eq, Ord, Show, Read, Enum, Bounded) | ||
33 | 19 | ||
34 | appName :: String | 20 | appName :: String |
35 | appName = "toxmpp" | 21 | appName = "toxmpp" |
@@ -37,43 +23,50 @@ appName = "toxmpp" | |||
37 | (<.>) :: String -> String -> String | 23 | (<.>) :: String -> String -> String |
38 | a <.> b = a ++ "." ++ b | 24 | a <.> b = a ++ "." ++ b |
39 | 25 | ||
40 | dput :: MonadIO m => DebugTag -> String -> m () | 26 | dput :: (MonadIO m, IsDebugTag tag) => tag -> String -> m () |
41 | dput tag msg = liftIO $ debugM (appName <.> show tag) msg | 27 | dput tag msg = liftIO $ debugM (appName <.> show tag) msg |
42 | 28 | ||
43 | dputB :: MonadIO m => DebugTag -> B.ByteString -> m () | 29 | dputB :: (MonadIO m, IsDebugTag tag) => tag -> B.ByteString -> m () |
44 | dputB tag msg = liftIO $ debugM (appName <.> show tag) (T.unpack . T.decodeUtf8 $ msg) | 30 | dputB tag msg = liftIO $ debugM (appName <.> show tag) (T.unpack . T.decodeUtf8 $ msg) |
45 | 31 | ||
46 | {-# NOINLINE verbosityMap #-} | 32 | {-# NOINLINE verbosityMap #-} |
47 | verbosityMap :: IORef (Map.Map DebugTag Bool) | 33 | verbosityMap :: IORef (Map.Map TypeRep Dynamic) |
48 | verbosityMap = unsafePerformIO $ newIORef (Map.empty) | 34 | verbosityMap = unsafePerformIO $ newIORef (Map.empty) |
49 | 35 | ||
50 | -- | Trace version of 'dput' works in arbitrary monad, using unsafePerformIO. | 36 | -- | Trace version of 'dput' works in arbitrary monad, using unsafePerformIO. |
51 | tput :: Applicative m => DebugTag -> String -> m () | 37 | tput :: (Applicative m, IsDebugTag tag) => tag -> String -> m () |
52 | tput tag msg = | 38 | tput tag msg = |
53 | let mp = unsafePerformIO $ readIORef verbosityMap | 39 | let mp = unsafePerformIO $ readIORef verbosityMap |
54 | in if fromMaybe True (Map.lookup tag mp) | 40 | in if maybe True (fromMaybe True . Map.lookup tag . flip fromDyn Map.empty) (Map.lookup (typeOf tag) mp) |
55 | then trace msg (pure ()) | 41 | then trace msg (pure ()) |
56 | else pure () | 42 | else pure () |
57 | 43 | ||
58 | -- | like 'trace' but parameterized with 'DebugTag' | 44 | -- | like 'trace' but parameterized with 'DebugTag' |
59 | dtrace :: DebugTag -> String -> a -> a | 45 | dtrace :: forall a tag. IsDebugTag tag => tag -> String -> a -> a |
60 | dtrace tag msg result = let mp = unsafePerformIO $ readIORef verbosityMap | 46 | dtrace tag msg result = let mp = unsafePerformIO $ readIORef verbosityMap |
61 | in if fromMaybe True (Map.lookup tag mp) | 47 | mp' :: Map.Map tag Bool |
48 | mp' = maybe Map.empty (flip fromDyn Map.empty) (Map.lookup (typeOf tag) mp) | ||
49 | in if fromMaybe True (Map.lookup tag mp') | ||
62 | then trace msg result | 50 | then trace msg result |
63 | else result | 51 | else result |
64 | 52 | ||
65 | setTagLevel :: Priority -> DebugTag -> IO () | 53 | setTagLevel :: forall tag. IsDebugTag tag => Priority -> tag -> IO () |
66 | setTagLevel level tag = do | 54 | setTagLevel level tag = do |
67 | updateGlobalLogger (appName <.> show tag) (setLevel level) | 55 | updateGlobalLogger (appName <.> show tag) (setLevel level) |
68 | modifyIORef verbosityMap (Map.insert tag (level <= DEBUG)) | 56 | modifyIORef verbosityMap $ \mpByType -> do |
57 | case Map.lookup (typeOf tag) mpByType of | ||
58 | Nothing -> Map.insert (typeOf tag) (toDyn $ Map.fromList [(tag,(level <= DEBUG))]) mpByType | ||
59 | Just dyn -> let mpByTag :: Map.Map tag Bool | ||
60 | mpByTag = fromDyn dyn Map.empty | ||
61 | in Map.insert (typeOf tag) (toDyn $ Map.insert tag (level <= DEBUG) mpByTag) mpByType | ||
69 | 62 | ||
70 | setQuiet :: DebugTag -> IO () | 63 | setQuiet :: forall tag. IsDebugTag tag => tag -> IO () |
71 | setQuiet = setTagLevel WARNING | 64 | setQuiet = setTagLevel WARNING |
72 | 65 | ||
73 | setVerbose :: DebugTag -> IO () | 66 | setVerbose :: forall tag. IsDebugTag tag => tag -> IO () |
74 | setVerbose = setTagLevel DEBUG | 67 | setVerbose = setTagLevel DEBUG |
75 | 68 | ||
76 | getVerbose :: DebugTag -> IO Bool | 69 | getVerbose :: forall tag. IsDebugTag tag => tag -> IO Bool |
77 | getVerbose tag = do | 70 | getVerbose tag = do |
78 | logger <- getLogger (appName <.> show tag) | 71 | logger <- getLogger (appName <.> show tag) |
79 | case getLevel logger of | 72 | case getLevel logger of |