bugsnag-1.0.0.0: src/Network/Bugsnag/StackFrame.hs
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Network.Bugsnag.StackFrame
( attachBugsnagCode
, currentStackFrame
) where
import Prelude
import Data.Bugsnag
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text, pack, unpack)
import Instances.TH.Lift ()
import Language.Haskell.TH.Syntax
import Network.Bugsnag.CodeIndex
-- | Attempt to attach code to a 'StackFrame'
--
-- Looks up the content in the Index by File/LineNumber and, if found, sets it
-- on the record.
--
attachBugsnagCode :: CodeIndex -> StackFrame -> StackFrame
attachBugsnagCode index sf = sf
{ stackFrame_code = findBugsnagCode
(unpack $ stackFrame_file sf)
(stackFrame_lineNumber sf)
index
}
findBugsnagCode :: FilePath -> Int -> CodeIndex -> Maybe (HashMap Int Text)
findBugsnagCode path n = fmap HashMap.fromList
. findSourceRange path (begin, n + 3)
where
begin
| n < 3 = 0
| otherwise = n - 3
-- | Construct a 'StackFrame' from the point of this splice
--
-- Unfortunately there's no way to know the function, so that must be given:
--
currentStackFrame :: Q Exp
currentStackFrame = [|locStackFrame $(qLocation >>= liftLoc)|]
-- brittany-disable-next-binding
locStackFrame :: Loc -> Text -> StackFrame
locStackFrame (Loc path _ _ (ls, cs) _) func =
defaultStackFrame
{ stackFrame_file = pack path
, stackFrame_lineNumber = ls
, stackFrame_columnNumber = Just cs
, stackFrame_method = func
, stackFrame_inProject = Just True
-- N.B. this assumes we're unlikely to see adoption within libraries, or
-- that such a thing would even work. If this function's used, it's
-- assumed to be in end-user code.
, stackFrame_code = Nothing
}
-- brittany-disable-next-binding
-- Taken from monad-logger
liftLoc :: Loc -> Q Exp
liftLoc (Loc a b c (d1, d2) (e1, e2)) = [|Loc
$(lift a)
$(lift b)
$(lift c)
($(lift d1), $(lift d2))
($(lift e1), $(lift e2))
|]