packages feed

ribosome-0.2.0.0: lib/Ribosome/Error/Report.hs

module Ribosome.Error.Report(
  ErrorReport(..),
  ReportError(..),
  logErrorReport,
  reportErrorWith,
  reportError,
  reportErrorOr,
  reportErrorOr_,
  printAllErrors,
) where

import Control.Monad.IO.Class (liftIO)
import Data.Foldable (traverse_)
import qualified Data.Map as Map (alter)
import Data.Text.Prettyprint.Doc (pretty, line, (<>))
import Data.Text.Prettyprint.Doc.Render.Terminal (putDoc)
import System.Log.Logger (logM, Priority(NOTICE, DEBUG))

import Ribosome.Api.Echo (echom)
import Ribosome.Control.Monad.Ribo (Ribo)
import qualified Ribosome.Control.Ribo as Ribo (name, modifyErrors, getErrors)
import Ribosome.Data.ErrorReport (ErrorReport(ErrorReport))
import Ribosome.Data.Errors (Errors(Errors), ComponentName(ComponentName), Error(Error))
import Ribosome.Data.Time (epochSeconds)

class ReportError a where
  errorReport :: a -> ErrorReport

instance ReportError [Char] where
  errorReport msg = ErrorReport msg [msg] NOTICE

instance ReportError [[Char]] where
  errorReport (msg:extra) = ErrorReport msg (msg:extra) NOTICE
  errorReport [] = ErrorReport "empty error" ["empty error"] DEBUG

storeError' :: Int -> String -> ErrorReport -> Errors -> Errors
storeError' time name report (Errors errors) =
  Errors (Map.alter alter (ComponentName name) errors)
  where
    err = Error time report
    alter Nothing = Just [err]
    alter (Just current) = Just (err:current)

storeError :: String -> ErrorReport -> Ribo d ()
storeError name e = do
  time <- epochSeconds
  Ribo.modifyErrors $ storeError' time name e

logErrorReport :: ErrorReport -> Ribo d ()
logErrorReport (ErrorReport user logMsgs prio) = do
  name <- Ribo.name
  liftIO $ traverse_ (logM name prio) logMsgs
  echom user

reportErrorWith :: String -> (a -> ErrorReport) -> a -> Ribo d ()
reportErrorWith name cons err = do
  storeError name report
  logErrorReport report
  where
    report = cons err

reportError :: ReportError a => String -> a -> Ribo d ()
reportError name =
  reportErrorWith name errorReport

reportErrorOr :: ReportError e => String -> (a -> Ribo d ()) -> Either e a -> Ribo d ()
reportErrorOr name =
  either $ reportError name

reportErrorOr_ :: ReportError e => String -> Ribo d () -> Either e a -> Ribo d ()
reportErrorOr_ name =
  reportErrorOr name . const

printAllErrors :: Ribo e ()
printAllErrors = do
  errors <- Ribo.getErrors
  liftIO $ putDoc $ (pretty errors <> line)