{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-} module Control.Monad.Log.LogLoc where import Control.Monad.Log #if !(MIN_VERSION_base(4,8,0)) import Control.Applicative #endif import Data.Text (Text) import qualified Data.Text as T import Data.Aeson import Data.Monoid ((<>)) import Language.Haskell.TH.Syntax (Q, Exp) import qualified Language.Haskell.TH.Syntax as TH -- | source location information. -- -- @ -- showt (LogLoc "package" "Module" "file.hs" 122) = "package Module file.hs 122" -- toJSON (LogLoc "package" "Module" "file.hs" 122) = -- '{"package":"package","module":"module","filename":"file.hs","line":122}' -- @ data LogLoc = LogLoc { package :: Text , module' :: Text , filename :: Text , line :: Int } deriving (Show, Eq, Ord) instance TextShow LogLoc where showb (LogLoc p m f l) = fromText (T.intercalate " " [p, m, f, showt l]) instance ToJSON LogLoc where toJSON (LogLoc p m f l) = object ["filename" .= f, "module" .= m, "package" .= p, "line" .= l] #if MIN_VERSION_aeson(0,10,0) toEncoding (LogLoc p m f l) = pairs ("filename" .= f <> "module" .= m <> "package" .= p <> "line" .= l) #endif instance FromJSON LogLoc where parseJSON (Object v) = LogLoc <$> v .: "package" <*> v .: "module" <*> v .: "filename" <*> v .: "line" parseJSON _ = fail "LogLoc should be an object" -- | Lift a location into an Exp. liftLogLoc :: TH.Loc -> Q Exp liftLogLoc (TH.Loc f p m (l, _) _) = [|LogLoc (T.pack $(TH.lift p)) (T.pack $(TH.lift m)) (T.pack $(TH.lift f)) $(TH.lift l) |] -- | Get current 'LogLoc'. -- -- depending on how accurately you want to record source location, -- you may want to use 'Logger' 's environment, or provide your own on every log. -- -- example usage: @info' $myLogLoc "log message"@ myLogLoc :: Q Exp myLogLoc = [| $(TH.location >>= liftLogLoc) |] -- | 'withEnv' specialized for 'LogLoc' withLogLoc :: (MonadLog LogLoc m) => LogLoc -> m a -> m a withLogLoc = withEnv