-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Message passing concurrency as extensible-effect -- -- Please see the README on GitHub at -- https://github.com/sheyll/extensible-effects-concurrent#readme @package extensible-effects-concurrent @version 0.29.1 -- | Add-ons to Exception and Exception module Control.Eff.ExceptionExtra -- | Catch Exception thrown by an effect. liftTry :: forall e r a. (HasCallStack, Exception e, Lifted IO r) => Eff r a -> Eff r (Either e a) -- | Very similar to liftEither but for Maybes. Unlike -- liftMaybe this will throw the given value (instead of using -- Fail). maybeThrow :: Member (Exc x) e => x -> Maybe a -> Eff e a instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) -- | An RFC 5434 inspired log message and convenience functions for logging -- them. module Control.Eff.Log.Message -- | A message data type inspired by the RFC-5424 Syslog Protocol data LogMessage MkLogMessage :: !Facility -> !Severity -> Maybe UTCTime -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [StructuredDataElement] -> Maybe ThreadId -> Maybe SrcLoc -> Text -> LogMessage [_lmFacility] :: LogMessage -> !Facility [_lmSeverity] :: LogMessage -> !Severity [_lmTimestamp] :: LogMessage -> Maybe UTCTime [_lmHostname] :: LogMessage -> Maybe Text [_lmAppName] :: LogMessage -> Maybe Text [_lmProcessId] :: LogMessage -> Maybe Text [_lmMessageId] :: LogMessage -> Maybe Text [_lmStructuredData] :: LogMessage -> [StructuredDataElement] [_lmThreadId] :: LogMessage -> Maybe ThreadId [_lmSrcLoc] :: LogMessage -> Maybe SrcLoc [_lmMessage] :: LogMessage -> Text -- | A lens for the Facility of a LogMessage lmFacility :: Functor f => (Facility -> f Facility) -> LogMessage -> f LogMessage -- | A lens for the Severity of a LogMessage lmSeverity :: Functor f => (Severity -> f Severity) -> LogMessage -> f LogMessage -- | A lens for the UTC time of a LogMessage The function -- setLogMessageTimestamp can be used to set the field. lmTimestamp :: Functor f => (Maybe UTCTime -> f (Maybe UTCTime)) -> LogMessage -> f LogMessage -- | A lens for the hostname of a LogMessage The function -- setLogMessageHostname can be used to set the field. lmHostname :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the RFC 5424 application name of a LogMessage -- -- One useful pattern for using this field, is to implement log filters -- that allow info and debug message from the application itself while -- only allowing warning and error messages from third party libraries: -- --
-- debugLogsForAppName myAppName lm = -- view lmAppName lm == Just myAppName || lmSeverityIsAtLeast warningSeverity lm ---- -- This concept is also implemented in discriminateByAppName. lmAppName :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined of process id of a LogMessage lmProcessId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined message id of a LogMessage lmMessageId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the StructuredDataElement of a LogMessage lmStructuredData :: Functor f => ([StructuredDataElement] -> f [StructuredDataElement]) -> LogMessage -> f LogMessage -- | A lens for the SrcLoc of a LogMessage lmSrcLoc :: Functor f => (Maybe SrcLoc -> f (Maybe SrcLoc)) -> LogMessage -> f LogMessage -- | A lens for the ThreadId of a LogMessage The function -- setLogMessageThreadId can be used to set the field. lmThreadId :: Functor f => (Maybe ThreadId -> f (Maybe ThreadId)) -> LogMessage -> f LogMessage -- | A lens for the user defined textual message of a LogMessage lmMessage :: Functor f => (Text -> f Text) -> LogMessage -> f LogMessage -- | Put the source location of the given callstack in lmSrcLoc setCallStack :: CallStack -> LogMessage -> LogMessage -- | Prefix the lmMessage. prefixLogMessagesWith :: Text -> LogMessage -> LogMessage -- | An IO action that sets the current UTC time in lmTimestamp. setLogMessageTimestamp :: LogMessage -> IO LogMessage -- | An IO action appends the the ThreadId of the calling process -- (see myThreadId) to lmMessage. setLogMessageThreadId :: LogMessage -> IO LogMessage -- | An IO action that sets the current hosts fully qualified hostname in -- lmHostname. setLogMessageHostname :: LogMessage -> IO LogMessage -- | Construct a LogMessage with errorSeverity errorMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with informationalSeverity infoMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with debugSeverity debugMessage :: HasCallStack => Text -> LogMessage -- | Things that can become a LogMessage class ToLogMessage a -- | Convert the value to a LogMessage toLogMessage :: ToLogMessage a => a -> LogMessage -- | Construct a LogMessage with errorSeverity errorMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with informationalSeverity infoMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with debugSeverity debugMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | The filter predicate for message that shall be logged. -- -- See Control.Eff.Log#LogPredicate type LogPredicate = LogMessage -> Bool -- | All messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. allLogMessages :: LogPredicate -- | No messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. noLogMessages :: LogPredicate -- | Match LogMessages that have exactly the given severity. See -- lmSeverityIsAtLeast. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIs :: Severity -> LogPredicate -- | Match LogMessages that have the given severity or worse. -- See lmSeverityIs. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIsAtLeast :: Severity -> LogPredicate -- | Match LogMessages whose lmMessage starts with the given -- string. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmMessageStartsWith :: Text -> LogPredicate -- | Apply a LogPredicate based on the lmAppName and delegate -- to one of two LogPredicates. -- -- One useful application for this is to allow info and debug message -- from one application, e.g. the current application itself, while at -- the same time allowing only warning and error messages from third -- party libraries. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. discriminateByAppName :: Text -> LogPredicate -> LogPredicate -> LogPredicate -- | RFC-5424 defines how structured data can be included in a log message. data StructuredDataElement SdElement :: !Text -> ![SdParameter] -> StructuredDataElement [_sdElementId] :: StructuredDataElement -> !Text [_sdElementParameters] :: StructuredDataElement -> ![SdParameter] -- | Component of an RFC-5424 StructuredDataElement data SdParameter MkSdParameter :: !Text -> !Text -> SdParameter -- | A lens for the key or ID of a group of RFC 5424 key-value pairs. sdElementId :: Functor f => (Text -> f Text) -> StructuredDataElement -> f StructuredDataElement -- | A lens for SdParameters sdElementParameters :: Functor f => ([SdParameter] -> f [SdParameter]) -> StructuredDataElement -> f StructuredDataElement -- | An rfc 5424 severity data Severity -- | Smart constructor for the RFC-5424 emergency LogMessage -- Severity. This corresponds to the severity value 0. See -- lmSeverity. emergencySeverity :: Severity -- | Smart constructor for the RFC-5424 alert LogMessage -- Severity. This corresponds to the severity value 1. See -- lmSeverity. alertSeverity :: Severity -- | Smart constructor for the RFC-5424 critical LogMessage -- Severity. This corresponds to the severity value 2. See -- lmSeverity. criticalSeverity :: Severity -- | Smart constructor for the RFC-5424 error LogMessage -- Severity. This corresponds to the severity value 3. See -- lmSeverity. errorSeverity :: Severity -- | Smart constructor for the RFC-5424 warning LogMessage -- Severity. This corresponds to the severity value 4. See -- lmSeverity. warningSeverity :: Severity -- | Smart constructor for the RFC-5424 notice LogMessage -- Severity. This corresponds to the severity value 5. See -- lmSeverity. noticeSeverity :: Severity -- | Smart constructor for the RFC-5424 informational -- LogMessage Severity. This corresponds to the severity -- value 6. See lmSeverity. informationalSeverity :: Severity -- | Smart constructor for the RFC-5424 debug LogMessage -- Severity. This corresponds to the severity value 7. See -- lmSeverity. debugSeverity :: Severity -- | An rfc 5424 facility newtype Facility Facility :: Int -> Facility [fromFacility] :: Facility -> Int -- | Smart constructor for the RFC-5424 LogMessage facility -- kernelMessages. See lmFacility. kernelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- userLevelMessages. See lmFacility. userLevelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- mailSystem. See lmFacility. mailSystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- systemDaemons. See lmFacility. systemDaemons :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages4. See lmFacility. securityAuthorizationMessages4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- linePrinterSubsystem. See lmFacility. linePrinterSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- networkNewsSubsystem. See lmFacility. networkNewsSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- uucpSubsystem. See lmFacility. uucpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon. See lmFacility. clockDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages10. See lmFacility. securityAuthorizationMessages10 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ftpDaemon. See lmFacility. ftpDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ntpSubsystem. See lmFacility. ntpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAuditFacility. See lmFacility. logAuditFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAlertFacility. See lmFacility. logAlertFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon2. See lmFacility. clockDaemon2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local0. See lmFacility. local0 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local1. See lmFacility. local1 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local2. See lmFacility. local2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local3. See lmFacility. local3 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local4. See lmFacility. local4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local5. See lmFacility. local5 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local6. See lmFacility. local6 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local7. See lmFacility. local7 :: Facility instance Control.Eff.Log.Message.ToLogMessage Control.Eff.Log.Message.LogMessage instance Control.Eff.Log.Message.ToLogMessage Data.Text.Internal.Text instance Data.String.IsString Control.Eff.Log.Message.LogMessage instance GHC.Generics.Generic Control.Eff.Log.Message.LogMessage instance GHC.Classes.Eq Control.Eff.Log.Message.LogMessage instance Control.DeepSeq.NFData Control.Eff.Log.Message.Facility instance GHC.Generics.Generic Control.Eff.Log.Message.Facility instance GHC.Show.Show Control.Eff.Log.Message.Facility instance GHC.Classes.Ord Control.Eff.Log.Message.Facility instance GHC.Classes.Eq Control.Eff.Log.Message.Facility instance Control.DeepSeq.NFData Control.Eff.Log.Message.Severity instance GHC.Generics.Generic Control.Eff.Log.Message.Severity instance GHC.Classes.Ord Control.Eff.Log.Message.Severity instance GHC.Classes.Eq Control.Eff.Log.Message.Severity instance GHC.Show.Show Control.Eff.Log.Message.StructuredDataElement instance GHC.Generics.Generic Control.Eff.Log.Message.StructuredDataElement instance GHC.Classes.Ord Control.Eff.Log.Message.StructuredDataElement instance GHC.Classes.Eq Control.Eff.Log.Message.StructuredDataElement instance GHC.Show.Show Control.Eff.Log.Message.SdParameter instance GHC.Generics.Generic Control.Eff.Log.Message.SdParameter instance GHC.Classes.Ord Control.Eff.Log.Message.SdParameter instance GHC.Classes.Eq Control.Eff.Log.Message.SdParameter instance Data.Default.Class.Default Control.Eff.Log.Message.LogMessage instance GHC.Show.Show Control.Eff.Log.Message.LogMessage instance Control.DeepSeq.NFData Control.Eff.Log.Message.LogMessage instance Data.Default.Class.Default Control.Eff.Log.Message.Facility instance GHC.Show.Show Control.Eff.Log.Message.Severity instance Data.Default.Class.Default Control.Eff.Log.Message.Severity instance Control.DeepSeq.NFData Control.Eff.Log.Message.StructuredDataElement instance Control.DeepSeq.NFData Control.Eff.Log.Message.SdParameter -- | Rendering functions for LogMessages. module Control.Eff.Log.MessageRenderer -- | LogMessage rendering function type LogMessageRenderer a = LogMessage -> a -- | Render the LogMessage to contain the severity, message, -- message-id, pid. -- -- Omit hostname, PID and timestamp. -- -- Render the header using renderSyslogSeverity -- -- Useful for logging to devlog renderLogMessageSyslog :: LogMessageRenderer Text -- | Render a LogMessage human readable, for console logging renderLogMessageConsoleLog :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164. renderRFC3164 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use RFC5424 time stamps. renderRFC3164WithRFC5424Timestamps :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use the custom LogMessageTimeRenderer. renderRFC3164WithTimestamp :: LogMessageTimeRenderer -> LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBody. renderRFC5424 :: LogMessageRenderer Text -- | Render the header and strucuted data of a LogMessage according -- to the rules in the RFC-5424, but do not render the lmMessage. renderRFC5424Header :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424, -- like renderRFC5424 but suppress the source location -- information. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBodyNoLocation. renderRFC5424NoLocation :: LogMessageRenderer Text -- | Render the severity and facility as described in RFC-3164 -- -- Render e.g. as <192>. -- -- Useful as header for syslog compatible log output. renderSyslogSeverityAndFacility :: LogMessageRenderer Text -- | Render the source location as: at filepath:linenumber. renderLogMessageSrcLoc :: LogMessageRenderer (Maybe Text) -- | Render a field of a LogMessage using the corresponsing lens. renderMaybeLogMessageLens :: Text -> Getter LogMessage (Maybe Text) -> LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBodyNoLocation :: LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBody :: LogMessageRenderer Text -- | Print the body of a LogMessage with fix size fields (60) -- for the message itself and 30 characters for the location renderLogMessageBodyFixWidth :: LogMessageRenderer Text -- | A rendering function for the lmTimestamp field. data LogMessageTimeRenderer -- | Make a LogMessageTimeRenderer using formatTime in the -- defaultLocale. mkLogMessageTimeRenderer :: String -> LogMessageTimeRenderer -- | Don't render the time stamp suppressTimestamp :: LogMessageTimeRenderer -- | Render the time stamp using "%h %d %H:%M:%S" rfc3164Timestamp :: LogMessageTimeRenderer -- | Render the time stamp to iso8601DateFormat (Just -- "%H:%M:%S%6QZ") rfc5424Timestamp :: LogMessageTimeRenderer -- | Render the time stamp like rfc5424Timestamp does, but omit the -- terminal Z character. rfc5424NoZTimestamp :: LogMessageTimeRenderer -- | The LogWriter type encapsulates an effectful function to write -- LogMessages. -- -- Used in conjunction with the HandleLogWriter class, it can be -- used to write messages from within an effectful computation. module Control.Eff.Log.Writer -- | A function that takes a log message and returns an effect that -- logs the message. newtype LogWriter writerM MkLogWriter :: (LogMessage -> LogWriterM writerM ()) -> LogWriter writerM [runLogWriter] :: LogWriter writerM -> LogMessage -> LogWriterM writerM () -- | A Reader specialized for LogWriters -- -- The existing Reader couldn't be used together with -- SetMember, so this lazy reader was written, specialized to -- reading LogWriter. data LogWriterReader h v -- | Modify the current LogWriter. localLogWriterReader :: forall h e a. SetMember LogWriterReader (LogWriterReader h) e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | Get the current LogWriter. askLogWriter :: SetMember LogWriterReader (LogWriterReader h) e => Eff e (LogWriter h) -- | Provide the LogWriter -- -- Exposed for custom extensions, if in doubt use withLogging. runLogWriterReader :: LogWriter h -> Eff (LogWriterReader h : e) a -> Eff e a -- | The instances of this class are the monads that define (side-) -- effect(s) of writting logs. class HandleLogWriter (writer :: Type -> Type) where { -- | The Effects required by the handleLogWriterEffect -- method. data family LogWriterM writer a; } -- | Run the side effect of a LogWriter in a compatible Eff. handleLogWriterEffect :: (HandleLogWriter writer, Member writer e) => LogWriterM writer () -> Eff e () -- | Write a message using the LogWriter found in the environment. -- -- The semantics of this function are a combination of -- runLogWriter and handleLogWriterEffect, with the -- LogWriter read from a LogWriterReader. liftWriteLogMessage :: (HandleLogWriter writer, SetMember LogWriterReader (LogWriterReader writer) e, Member writer e) => LogMessage -> Eff e () -- | This LogWriter will discard all messages. -- -- NOTE: This is just an alias for def noOpLogWriter :: Applicative (LogWriterM m) => LogWriter m -- | A LogWriter that applies a predicate to the LogMessage -- and delegates to to the given writer of the predicate is satisfied. filteringLogWriter :: Monad (LogWriterM e) => LogPredicate -> LogWriter e -> LogWriter e -- | A LogWriter that applies a function to the LogMessage -- and delegates the result to to the given writer. mappingLogWriter :: (LogMessage -> LogMessage) -> LogWriter e -> LogWriter e -- | Like mappingLogWriter allow the function that changes the -- LogMessage to have effects. mappingLogWriterM :: Monad (LogWriterM e) => (LogMessage -> LogWriterM e LogMessage) -> LogWriter e -> LogWriter e instance GHC.Base.Monad (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Internal.Lift GHC.Types.IO)) instance GHC.Base.Functor (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Internal.Lift GHC.Types.IO)) instance GHC.Base.Applicative (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Internal.Lift GHC.Types.IO)) instance GHC.Base.Monad (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Writer.Strict.Writer Control.Eff.Log.Message.LogMessage)) instance GHC.Base.Applicative (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Writer.Strict.Writer Control.Eff.Log.Message.LogMessage)) instance GHC.Base.Functor (Control.Eff.Log.Writer.LogWriterM (Control.Eff.Writer.Strict.Writer Control.Eff.Log.Message.LogMessage)) instance GHC.Base.Applicative (Control.Eff.Log.Writer.LogWriterM w) => Data.Default.Class.Default (Control.Eff.Log.Writer.LogWriter w) instance Control.Eff.Internal.Handle (Control.Eff.Log.Writer.LogWriterReader h) e a (Control.Eff.Log.Writer.LogWriter h -> k) instance (Control.Monad.Base.MonadBase m m, Control.Eff.Internal.LiftedBase m r) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : r)) instance (Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance Control.Eff.Log.Writer.HandleLogWriter (Control.Eff.Internal.Lift GHC.Types.IO) instance Control.Eff.Log.Writer.HandleLogWriter (Control.Eff.Writer.Strict.Writer Control.Eff.Log.Message.LogMessage) -- | A memory efficient, streaming, logging effect with support for -- efficiently not logging when no logs are required. -- -- Good support for logging to a file or to the network, as well as -- asynchronous logging in another thread. module Control.Eff.Log.Handler -- | Log a message. -- -- All logging goes through this function. -- -- This function is the only place where the LogPredicate is -- applied. -- -- Also, LogMessages are evaluated using deepseq, -- after they pass the LogPredicate. logMsg :: forall e. (HasCallStack, Member Logs e) => LogMessage -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity :: forall e. (HasCallStack, Member Logs e) => Severity -> Text -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity' :: forall e. (HasCallStack, Member Logs e) => Severity -> String -> Eff e () -- | Log a String as emergencySeverity. logEmergency :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a String as emergencySeverity. logEmergency' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a message with alertSeverity. logAlert :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a message with alertSeverity. logAlert' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a criticalSeverity message. logCritical :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a criticalSeverity message. logCritical' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a errorSeverity message. logError :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a errorSeverity message. logError' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a warningSeverity message. logWarning :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a warningSeverity message. logWarning' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a noticeSeverity message. logNotice :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a noticeSeverity message. logNotice' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a informationalSeverity message. logInfo :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a informationalSeverity message. logInfo' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a debugSeverity message. logDebug :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a debugSeverity message. logDebug' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Include LogMessages that match a LogPredicate. -- -- excludeLogMessages p allows log message to be logged if p -- m -- -- Although it is enough if the previous predicate holds. See -- excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate includeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Exclude LogMessages that match a LogPredicate. -- -- excludeLogMessages p discards logs if p m -- -- Also the previous predicate must also hold for a message to be logged. -- See excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate excludeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Keep only those messages, for which a predicate holds. -- -- E.g. to keep only messages which begin with OMG: -- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad (LogWriterM h)) => LogWriter h -> Eff e a -> Eff e a
-- | Change the current LogWriter.
modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriter
censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression,
-- as in censorLogs but with a effectful function.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriterM
censorLogsM :: (LogsTo h e, Monad (LogWriterM h)) => (LogMessage -> LogWriterM h LogMessage) -> Eff e a -> Eff e a
-- | This effect sends LogMessages and is a reader for a
-- LogPredicate.
--
-- Logs are sent via logMsg; for more information about log
-- predicates, see Control.Eff.Log#LogPredicate
--
-- This effect is handled via withLogging.
data Logs v
-- | A constraint alias for effects that requires a LogWriterReader,
-- as well as that the contained LogWriterReader has a
-- HandleLogWriter instance.
--
-- The requirements of this constraint are provided by:
--
-- -- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b instance GHC.Base.Functor (Control.Eff.Log.Writer.LogWriterM Control.Eff.Log.Handler.Logs) instance (Control.Monad.Base.MonadBase m m, Control.Eff.Internal.LiftedBase m e, Control.Eff.Log.Handler.LogsTo (Control.Eff.Internal.Lift m) (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e), Control.Eff.Log.Handler.LogsTo (Control.Eff.Internal.Lift m) (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e), Control.Eff.Log.Handler.LogsTo (Control.Eff.Internal.Lift m) (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance Control.Eff.Internal.Handle Control.Eff.Log.Handler.Logs e a (Control.Eff.Log.Message.LogPredicate -> k) instance (Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance Control.Eff.Log.Writer.HandleLogWriter Control.Eff.Log.Handler.Logs instance GHC.Base.Applicative (Control.Eff.Log.Writer.LogWriterM Control.Eff.Log.Handler.Logs) instance GHC.Base.Monad (Control.Eff.Log.Writer.LogWriterM Control.Eff.Log.Handler.Logs) -- | The message passing effect. -- -- This module describes an abstract message passing effect, and a -- process effect, mimicking Erlang's process and message semantics. -- -- Two scheduler implementations for the Process effect are -- provided: -- --
-- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Partition a SomeExitReason back into either a NoRecovery -- or a Recoverable Interrupt fromSomeExitReason :: SomeExitReason -> Either (Interrupt 'NoRecovery) (Interrupt 'Recoverable) -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () -- | Handle all Interrupts of an Processes by wrapping them -- up in interruptToExit and then do a process Shutdown. provideInterruptsShutdown :: forall e a. Eff (Processes e) a -> Eff (SafeProcesses e) a -- | Handle Interrupts arising during process operations, e.g. when -- a linked process crashes while we wait in a -- receiveSelectedMessage via a call to interrupt. handleInterrupts :: (HasCallStack, Member Interrupts r) => (Interrupt 'Recoverable -> Eff r a) -> Eff r a -> Eff r a -- | Like handleInterrupts, but instead of passing the -- Interrupt to a handler function, Either is returned. tryUninterrupted :: (HasCallStack, Member Interrupts r) => Eff r a -> Eff r (Either (Interrupt 'Recoverable) a) -- | Handle Interrupts arising during process operations, e.g. when -- a linked process crashes while we wait in a -- receiveSelectedMessage via a call to interrupt. exitOnInterrupt :: (HasCallStack, HasProcesses r q) => Eff r a -> Eff r a -- | Handle interrupts by logging them with logProcessExit and -- otherwise ignoring them. logInterrupts :: forall r. (Member Logs r, HasCallStack, Member Interrupts r) => Eff r () -> Eff r () -- | Handle Interrupts arising during process operations, e.g. when -- a linked process crashes while we wait in a -- receiveSelectedMessage via a call to interrupt. provideInterrupts :: HasCallStack => Eff (Interrupts : r) a -> Eff r (Either (Interrupt 'Recoverable) a) -- | Wrap all (left) Interrupts into interruptToExit and -- return the (right) NoRecovery Interrupts as is. mergeEitherInterruptAndExitReason :: Either (Interrupt 'Recoverable) (Interrupt 'NoRecovery) -> Interrupt 'NoRecovery -- | Serialize and send a message to the process in a Receiver. -- -- EXPERIMENTAL sendToReceiver :: (NFData o, HasProcesses r q) => Receiver o -> o -> Eff r () -- | A ProcessId and a Serializer. EXPERIMENTAL -- -- See sendToReceiver. data Receiver a Receiver :: ProcessId -> (a -> out) -> Receiver a [_receiverPid] :: Receiver a -> ProcessId [_receiverSerializer] :: Receiver a -> a -> out receiverPid :: forall a_aHxu. Lens' (Receiver a_aHxu) ProcessId instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.Receiver o) instance GHC.Classes.Eq (Control.Eff.Concurrent.Process.Receiver o) instance GHC.Classes.Ord (Control.Eff.Concurrent.Process.Receiver o) instance Data.Functor.Contravariant.Contravariant Control.Eff.Concurrent.Process.Receiver instance Data.Typeable.Internal.Typeable protocol => GHC.Show.Show (Control.Eff.Concurrent.Process.Receiver protocol) instance GHC.Show.Show v => GHC.Show.Show (Control.Eff.Concurrent.Process.ResumeProcess v) instance GHC.Generics.Generic1 Control.Eff.Concurrent.Process.ResumeProcess instance GHC.Generics.Generic (Control.Eff.Concurrent.Process.ResumeProcess v) instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessDown instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessDown instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessDown instance GHC.Generics.Generic Control.Eff.Concurrent.Process.MonitorReference instance GHC.Classes.Ord Control.Eff.Concurrent.Process.MonitorReference instance GHC.Classes.Eq Control.Eff.Concurrent.Process.MonitorReference instance GHC.Read.Read Control.Eff.Concurrent.Process.MonitorReference instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessId instance GHC.Real.Real Control.Eff.Concurrent.Process.ProcessId instance GHC.Real.Integral Control.Eff.Concurrent.Process.ProcessId instance GHC.Enum.Enum Control.Eff.Concurrent.Process.ProcessId instance GHC.Num.Num Control.Eff.Concurrent.Process.ProcessId instance GHC.Enum.Bounded Control.Eff.Concurrent.Process.ProcessId instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessId instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessId instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessState instance GHC.Enum.Enum Control.Eff.Concurrent.Process.ProcessState instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessState instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessState instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessState instance GHC.Read.Read Control.Eff.Concurrent.Process.ProcessState instance GHC.Base.Functor Control.Eff.Concurrent.Process.MessageSelector instance GHC.Base.Semigroup a => GHC.Base.Monoid (Control.Eff.Concurrent.Process.MessageSelector a) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Control.Eff.Concurrent.Process.MessageSelector a) instance GHC.Base.Monoid Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Base.Semigroup Control.Eff.Concurrent.Process.ProcessDetails instance Data.String.IsString Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessDetails instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Base.Monoid Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Base.Semigroup Control.Eff.Concurrent.Process.ProcessTitle instance Data.String.IsString Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessTitle instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Show.Show (Control.Eff.Concurrent.Process.Process r b) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.ResumeProcess a) instance Control.DeepSeq.NFData1 Control.Eff.Concurrent.Process.ResumeProcess instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessDown instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessDown instance GHC.Classes.Ord Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Classes.Eq Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Show.Show Control.Eff.Concurrent.Process.SomeExitReason instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Show.Show (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Exception.Type.Exception (Control.Eff.Concurrent.Process.Interrupt 'Control.Eff.Concurrent.Process.Recoverable) instance GHC.Exception.Type.Exception (Control.Eff.Concurrent.Process.Interrupt 'Control.Eff.Concurrent.Process.NoRecovery) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Classes.Ord (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Classes.Eq (Control.Eff.Concurrent.Process.Interrupt x) instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.MonitorReference instance GHC.Show.Show Control.Eff.Concurrent.Process.MonitorReference instance GHC.Read.Read Control.Eff.Concurrent.Process.ProcessId instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessId instance GHC.Show.Show Control.Eff.Concurrent.Process.ExitSeverity instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ExitSeverity instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Show.Show Control.Eff.Concurrent.Process.ExitRecovery instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessState instance Data.Default.Class.Default Control.Eff.Concurrent.Process.ProcessState instance GHC.Base.Applicative Control.Eff.Concurrent.Process.MessageSelector instance GHC.Base.Alternative Control.Eff.Concurrent.Process.MessageSelector instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.Serializer message) instance Data.Typeable.Internal.Typeable message => GHC.Show.Show (Control.Eff.Concurrent.Process.Serializer message) instance Data.Functor.Contravariant.Contravariant Control.Eff.Concurrent.Process.Serializer instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.StrictDynamic instance GHC.Show.Show Control.Eff.Concurrent.Process.StrictDynamic instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessTitle -- | Types and functions for type-safe(er) interaction between processes. -- -- All messages sent between processes are eventually converted to -- Dynamic values which carry little type information. -- -- A step towards a more controlled and type safe process interaction -- model is done with the facilities defined in this module. -- -- The metaphor for communication is a stateless protocol that -- describes the messages handled by a process. -- -- A protocol is represented by a custom data type, often a -- phantom type, which is then used to form specific instances of -- type classes data/type families, to determine the messages, the -- replies, the servers and clients, associated with specific task, that -- needs to be executed concurrently. -- -- This module contains a mechanism to specify what kind of messages (aka -- requests) an Endpoint can handle. -- -- The Endpoint wraps a ProcessId and carries the protocol -- phantom-type, to indicate the messages that a process repsonds to. -- -- The associated data type Pdu defines the messages or -- requests along with the corresponding responses. -- -- Request handling can be either blocking, if a response is required, or -- non-blocking. -- -- A process can serve a specific protocol by using the functions -- provided by the Control.Eff.Concurrent.Protocol.EffectfulServer -- and Control.Eff.Concurrent.Protocol.EffectfulServer modules. -- -- To enable a process to use such a service, the functions -- provided in Control.Eff.Concurrent.Protocol.Client should be -- used. module Control.Eff.Concurrent.Protocol -- | This type class and the associated data family defines the protocol -- data units (PDU) of a protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- instance Typeable r => HasPdu BookShop r where
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
-- deriving Typeable
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
class Typeable protocol => HasPdu (protocol :: Type) where {
-- | A type level list Protocol phantom types included in the associated
-- Pdu instance.
--
-- This is just a helper for better compiler error messages. It relies on
-- Embeds to add the constraint HasPduPrism.
type family EmbeddedPduList protocol :: [Type];
-- | The protocol data unit type for the given protocol.
data family Pdu protocol (reply :: Synchronicity);
type EmbeddedPduList protocol = '[];
}
-- | Deserialize a Pdu from a Dynamic i.e. from a message
-- received by a process.
deserializePdu :: Typeable (Pdu protocol reply) => Dynamic -> Maybe (Pdu protocol reply)
-- | A constraint that requires that the outer Pdu has a
-- clause to embed values from the inner Pdu.
--
-- Also, this constraint requires a HasPduPrism instance, as a
-- proof for a possible conversion of an embedded Pdu value into
-- to the enclosing Pdu.
--
-- This generates better compiler error messages, when an embedding of a
-- Pdu into another.
--
-- This is provided by HasPdu instances. The instances are
-- required to provide a list of embedded Pdu values in
-- EmbeddedPduList.
--
-- Note that every type embeds itself, so Embeds x x always
-- holds.
type Embeds outer inner = (HasPduPrism outer inner, CheckEmbeds outer inner, HasPdu outer)
-- | The (promoted) constructors of this type specify (at the type level)
-- the reply behavior of a specific constructor of an Pdu
-- instance.
data Synchronicity
-- | Specify that handling a request is a blocking operation with a
-- specific return type, e.g. ('Synchronous (Either RentalError
-- RentalId))
Synchronous :: Type -> Synchronicity
-- | Non-blocking, asynchronous, request handling
Asynchronous :: Synchronicity
-- | This type function takes an Pdu and analysis the reply type,
-- i.e. the Synchronicity and evaluates to either t for
-- an Pdu x (Synchronous t) or to '()' for an Pdu x
-- Asynchronous.
type family ProtocolReply (s :: Synchronicity)
-- | A set of constraints for types that can evaluated via NFData,
-- compared via Ord and presented dynamically via Typeable,
-- and represented both as values via Show.
type Tangible i = (NFData i, Typeable i, Show i)
-- | A Constraint that bundles the requirements for the Pdu
-- values of a protocol.
--
-- This ensures that Pdus can be strictly and deeply evaluated and
-- shown such that for example logging is possible.
type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r), HasPdu p)
-- | A server process for protocol.
--
-- Protocols are represented by phantom types, which are used in
-- different places to index type families and type class instances.
--
-- A Process can send and receive any messages. An Endpoint
-- wraps around a ProcessId and carries a phantom type to indicate
-- the kinds of messages accepted by the process.
--
-- As a metaphor, communication between processes can be thought of
-- waiting for and sending protocol data units belonging to some
-- protocol.
newtype Endpoint protocol
Endpoint :: ProcessId -> Endpoint protocol
[_fromEndpoint] :: Endpoint protocol -> ProcessId
fromEndpoint :: forall protocol_aTMy protocol_aUUM. Iso (Endpoint protocol_aTMy) (Endpoint protocol_aUUM) ProcessId ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | A class for Pdu instances that embed other Pdu.
--
-- This is a part of Embeds provide instances for your Pdus
-- but in client code use the Embeds constraint.
--
-- Instances of this class serve as proof to Embeds that a
-- conversion into another Pdu actually exists.
--
-- A Prism for the embedded Pdu is the center of this class
--
-- Laws: embeddedPdu = prism' embedPdu fromPdu
class (Typeable protocol, Typeable embeddedProtocol) => HasPduPrism protocol embeddedProtocol
-- | A Prism for the embedded Pdus.
embeddedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result)
-- | Embed the Pdu value of an embedded protocol into the
-- corresponding Pdu value.
embedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu embeddedProtocol result -> Pdu protocol result
-- | Examine a Pdu value from the outer protocol, and return it, if
-- it embeds a Pdu of embedded protocol, otherwise return
-- Nothing/
fromPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu protocol result -> Maybe (Pdu embeddedProtocol result)
-- | Convert an Endpoint to an endpoint for an embedded protocol.
--
-- See Embeds, fromEmbeddedEndpoint.
toEmbeddedEndpoint :: forall inner outer. Embeds outer inner => Endpoint outer -> Endpoint inner
-- | Convert an Endpoint to an endpoint for a server, that embeds
-- the protocol.
--
-- See Embeds, toEmbeddedEndpoint.
fromEmbeddedEndpoint :: forall outer inner. HasPduPrism outer inner => Endpoint inner -> Endpoint outer
instance forall k (protocol :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance forall k (protocol :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance forall k (protocol :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance Data.Typeable.Internal.Typeable a => Control.Eff.Concurrent.Protocol.HasPduPrism a a
instance (Data.Typeable.Internal.Typeable a1, Data.Typeable.Internal.Typeable a2) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2) a1
instance (Data.Typeable.Internal.Typeable a1, Data.Typeable.Internal.Typeable a2) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2) a2
instance (Data.Typeable.Internal.Typeable a1, Data.Typeable.Internal.Typeable a2, Data.Typeable.Internal.Typeable a3) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3) a1
instance (Data.Typeable.Internal.Typeable a1, Data.Typeable.Internal.Typeable a2, Data.Typeable.Internal.Typeable a3) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3) a2
instance (Data.Typeable.Internal.Typeable a1, Data.Typeable.Internal.Typeable a2, Data.Typeable.Internal.Typeable a3) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3) a3
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4) a1
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4) a2
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4) a3
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4) a4
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4, a5) a1
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4, a5) a2
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4, a5) a3
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4, a5) a4
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPduPrism (a1, a2, a3, a4, a5) a5
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2) => Control.Eff.Concurrent.Protocol.HasPdu (a1, a2)
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3) => Control.Eff.Concurrent.Protocol.HasPdu (a1, a2, a3)
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4) => Control.Eff.Concurrent.Protocol.HasPdu (a1, a2, a3, a4)
instance (Control.Eff.Concurrent.Protocol.HasPdu a1, Control.Eff.Concurrent.Protocol.HasPdu a2, Control.Eff.Concurrent.Protocol.HasPdu a3, Control.Eff.Concurrent.Protocol.HasPdu a4, Control.Eff.Concurrent.Protocol.HasPdu a5) => Control.Eff.Concurrent.Protocol.HasPdu (a1, a2, a3, a4, a5)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2) r)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3) r)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a4 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a4 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4) r)
instance (Data.Typeable.Internal.Typeable r, Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a4 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a5 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4, a5) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a4 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a5 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4, a5) r)
instance forall k (protocol :: k). Data.Typeable.Internal.Typeable protocol => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Endpoint protocol)
-- | Proxies and containers for casts and calls.
module Control.Eff.Concurrent.Protocol.Wrapper
-- | A wrapper sum type for calls and casts for the Pdus of a
-- protocol
data Request protocol
[Call] :: forall protocol reply. (Tangible reply, TangiblePdu protocol ( 'Synchronous reply)) => RequestOrigin protocol reply -> Pdu protocol ( 'Synchronous reply) -> Request protocol
[Cast] :: forall protocol. (TangiblePdu protocol 'Asynchronous, NFData (Pdu protocol 'Asynchronous)) => Pdu protocol 'Asynchronous -> Request protocol
-- | Answer a Call by sending the reply value to the client process.
--
-- The ProcessId, the RequestOrigin and the Reply
-- Serializer are stored in the ReplyTarget.
sendReply :: (HasProcesses eff q, Tangible reply, Typeable protocol) => ReplyTarget protocol reply -> reply -> Eff eff ()
-- | Target of a Call reply.
--
-- This combines a RequestOrigin with a Serializer for a
-- Reply using Arg. There are to smart constructors for
-- this type: replyTarget and embeddedReplyTarget.
--
-- Because of Arg the Eq and Ord instances are
-- implemented via the RequestOrigin instances.
newtype ReplyTarget p r
MkReplyTarget :: Arg (RequestOrigin p r) (Serializer (Reply p r)) -> ReplyTarget p r
-- | Smart constructor for a ReplyTarget.
--
-- To build a ReplyTarget for an Embeds instance use
-- embeddedReplyTarget.
replyTarget :: Serializer (Reply p reply) -> RequestOrigin p reply -> ReplyTarget p reply
-- | A simple Lens for the RequestOrigin of a
-- ReplyTarget.
replyTargetOrigin :: Lens' (ReplyTarget p reply) (RequestOrigin p reply)
-- | A simple Lens for the Reply Serializer of a
-- ReplyTarget.
replyTargetSerializer :: Lens' (ReplyTarget p reply) (Serializer (Reply p reply))
-- | Smart constructor for an embedded ReplyTarget.
--
-- This combines replyTarget and toEmbeddedReplyTarget.
embeddedReplyTarget :: Embeds outer inner => Serializer (Reply outer reply) -> RequestOrigin outer reply -> ReplyTarget inner reply
-- | Convert a ReplyTarget to be usable for embedded replies.
--
-- This combines a toEmbeddedOrigin with
-- embedReplySerializer to produce a ReplyTarget that can
-- be passed to functions defined soley on an embedded protocol.
toEmbeddedReplyTarget :: Embeds outer inner => ReplyTarget outer reply -> ReplyTarget inner reply
-- | Wraps the source ProcessId and a unique identifier for a
-- Call.
data RequestOrigin (proto :: Type) reply
RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply
[_requestOriginPid] :: RequestOrigin reply -> !ProcessId
[_requestOriginCallRef] :: RequestOrigin reply -> !Int
-- | Turn an embedded RequestOrigin to a RequestOrigin
-- for the bigger request.
--
-- This is the inverse of toEmbeddedOrigin.
--
-- This function is strict in all parameters.
embedRequestOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin inner reply -> RequestOrigin outer reply
-- | Turn an RequestOrigin to an origin for an embedded request (See
-- Embeds).
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedReplySerializer.
toEmbeddedOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin outer reply -> RequestOrigin inner reply
-- | The wrapper around replies to Calls.
data Reply protocol reply
[Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply
-- | Turn a Serializer for a Pdu instance that contains
-- embedded Pdu values into a Reply Serializer for
-- the embedded Pdu.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also toEmbeddedOrigin.
embedReplySerializer :: forall outer inner reply. Embeds outer inner => Serializer (Reply outer reply) -> Serializer (Reply inner reply)
-- | Create a new, unique RequestOrigin value for the current
-- process.
makeRequestOrigin :: (Typeable r, NFData r, HasProcesses e q0) => Eff e (RequestOrigin p r)
instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Wrapper.ReplyTarget p r)
instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Wrapper.ReplyTarget p r)
instance forall proto k (reply :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Wrapper.RequestOrigin proto reply)
instance forall proto k (reply :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Wrapper.RequestOrigin proto reply)
instance forall proto k (reply :: k). GHC.Generics.Generic (Control.Eff.Concurrent.Protocol.Wrapper.RequestOrigin proto reply)
instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Wrapper.ReplyTarget p r)
instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Wrapper.ReplyTarget p r)
instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Wrapper.Request protocol)
instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Wrapper.Request protocol)
instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Wrapper.Reply p r)
instance GHC.Show.Show r => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Wrapper.Reply p r)
instance forall k p (r :: k). GHC.Show.Show (Control.Eff.Concurrent.Protocol.Wrapper.RequestOrigin p r)
instance forall k p (r :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Wrapper.RequestOrigin p r)
-- | Functions for timeouts when receiving messages.
--
-- NOTE: If you use a single threaded scheduler, these functions will not
-- work as expected. (This is an open TODO)
module Control.Eff.Concurrent.Process.Timer
-- | A number of micro seconds.
newtype Timeout
TimeoutMicros :: Int -> Timeout
[fromTimeoutMicros] :: Timeout -> Int
-- | The reference to a timer started by startTimer, required to
-- stop a timer via cancelTimer.
data TimerReference
-- | A value to be sent when timer started with startTimer has
-- elapsed.
data TimerElapsed
-- | Send a message to a given process after waiting. The message is
-- created by applying the function parameter to the
-- TimerReference, such that the message can directly refer to the
-- timer.
sendAfter :: forall r q message. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
-- | Start a new timer, after the time has elapsed, TimerElapsed is
-- sent to calling process. The message also contains the
-- TimerReference returned by this function. Use
-- cancelTimer to cancel the timer. Use selectTimerElapsed
-- to receive the message using receiveSelectedMessage. To receive
-- messages with guarded with a timeout see receiveAfter.
startTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => Timeout -> Eff r TimerReference
-- | Cancel a timer started with startTimer.
cancelTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => TimerReference -> Eff r ()
-- | A MessageSelector matching TimerElapsed messages created
-- by startTimer.
selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Nothing. This is based on
-- receiveSelectedAfter.
receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Left TimerElapsed. This
-- is based on selectTimerElapsed and startTimer.
receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
-- | Like receiveWithMonitor combined with
-- receiveSelectedAfter.
receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Enum.Enum Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Real.Real Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Real.Integral Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Num.Num Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.TimerReference
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Enum.Enum Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Real.Real Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Real.Integral Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Num.Num Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.Timeout
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.Timeout
-- | Logging via extensible-effects
--
-- Logging consist of two effects:
--
-- -- exampleLogging :: IO () -- exampleLogging = -- runLift -- $ withLogging consoleLogWriter -- $ do -- logDebug "test 1.1" -- logError "test 1.2" -- censorLogs (prefixLogMessagesWith "NESTED: ") -- $ do -- addLogWriter debugTraceLogWriter -- $ setLogPredicate (\m -> (view lmMessage m) /= "not logged") -- $ do -- logInfo "not logged" -- logMsg "test 2.1" -- logWarning "test 2.2" -- logCritical "test 1.3" ---- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad (LogWriterM h)) => LogWriter h -> Eff e a -> Eff e a
-- | Change the current LogWriter.
modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriter
censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression,
-- as in censorLogs but with a effectful function.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriterM
censorLogsM :: (LogsTo h e, Monad (LogWriterM h)) => (LogMessage -> LogWriterM h LogMessage) -> Eff e a -> Eff e a
-- | This effect sends LogMessages and is a reader for a
-- LogPredicate.
--
-- Logs are sent via logMsg; for more information about log
-- predicates, see Control.Eff.Log#LogPredicate
--
-- This effect is handled via withLogging.
data Logs v
-- | A constraint alias for effects that requires a LogWriterReader,
-- as well as that the contained LogWriterReader has a
-- HandleLogWriter instance.
--
-- The requirements of this constraint are provided by:
--
-- -- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b -- | Utilities to implement effectful server-loops. module Control.Eff.Concurrent.Protocol.EffectfulServer -- | A type class for effectful server loops. -- -- This type class serves as interface for other abstractions, for -- example process supervision -- -- The methods of this class handle Events Requests for -- Pdu instance. -- -- Instances can by index types for Pdu family directly, or -- indirectly via the ServerPdu type family. -- -- To builder servers serving multiple protocols, use the generic -- Pdu instances, for which Embeds instances exist, like -- 2-,3-,4-, or 5-tuple. class Server (a :: Type) (e :: [Type -> Type]) where { -- | The value that defines what is required to initiate a Server -- loop. data family Init a e; -- | The index type of the Events that this server processes. This -- is the first parameter to the Request and therefore of the -- Pdu family. type family ServerPdu a :: Type; -- | Effects of the implementation type family ServerEffects a e :: [Type -> Type]; type ServerPdu a = a; type ServerEffects a e = e; } -- | Return the ProcessTitle. -- -- Usually you should rely on the default implementation serverTitle :: Server a e => Init a e -> ProcessTitle -- | Return the ProcessTitle. -- -- Usually you should rely on the default implementation serverTitle :: (Server a e, Typeable (ServerPdu a)) => Init a e -> ProcessTitle -- | Process the effects of the implementation runEffects :: Server a e => Endpoint (ServerPdu a) -> Init a e -> Eff (ServerEffects a e) x -> Eff e x -- | Process the effects of the implementation runEffects :: (Server a e, ServerEffects a e ~ e) => Endpoint (ServerPdu a) -> Init a e -> Eff (ServerEffects a e) x -> Eff e x -- | Update the Model based on the Event. onEvent :: Server a e => Endpoint (ServerPdu a) -> Init a e -> Event (ServerPdu a) -> Eff (ServerEffects a e) () -- | Update the Model based on the Event. onEvent :: (Server a e, Show (Init a e), Member Logs (ServerEffects a e)) => Endpoint (ServerPdu a) -> Init a e -> Event (ServerPdu a) -> Eff (ServerEffects a e) () -- | This event sum-type is used to communicate incoming messages and other -- events to the instances of Server. data Event a -- | A Synchronous message was received. If an implementation wants -- to delegate nested Pdus, it can use -- toEmbeddedReplyTarget to convert a ReplyTarget safely to -- the embedded protocol. [OnCall] :: forall a r. (Tangible r, TangiblePdu a ( 'Synchronous r)) => ReplyTarget a r -> Pdu a ( 'Synchronous r) -> Event a [OnCast] :: forall a. TangiblePdu a 'Asynchronous => Pdu a 'Asynchronous -> Event a [OnInterrupt] :: Interrupt 'Recoverable -> Event a [OnDown] :: ProcessDown -> Event a [OnTimeOut] :: TimerElapsed -> Event a [OnMessage] :: StrictDynamic -> Event a -- | Execute the server loop. start :: forall a r q h. (Server a (Processes q), Typeable a, Typeable (ServerPdu a), LogsTo h (Processes q), HasProcesses (ServerEffects a (Processes q)) q, HasProcesses r q, HasCallStack) => Init a (Processes q) -> Eff r (Endpoint (ServerPdu a)) -- | Execute the server loop. startLink :: forall a r q h. (Typeable a, Typeable (ServerPdu a), Server a (Processes q), LogsTo h (Processes q), HasProcesses (ServerEffects a (Processes q)) q, HasProcesses r q, HasCallStack) => Init a (Processes q) -> Eff r (Endpoint (ServerPdu a)) -- | Execute the server loop. protocolServerLoop :: forall q h a. (Server a (Processes q), LogsTo h (Processes q), HasProcesses (ServerEffects a (Processes q)) q, Typeable a, Typeable (ServerPdu a)) => Init a (Processes q) -> Eff (Processes q) () instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.EffectfulServer.Event a) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.EffectfulServer.Event a) -- | Utilities to implement server-loops with builtin state and -- TEA-like naming. module Control.Eff.Concurrent.Protocol.StatefulServer -- | A type class for server loops. -- -- This class serves as interface for other mechanisms, for example -- process supervision -- -- The methods of this class handle Events and Requests -- for Pdu instances. -- -- Instances can by index types for Pdu family directly, or -- indirectly via the ServerPdu type family. -- -- To builder servers serving multiple protocols, use the generic -- Pdu instances, for which Embeds instances exist, like -- 2-,3-,4-, or 5-tuple. -- -- The naming is inspired by The Elm Architecture, without the -- view callback. -- -- This class is based on -- Control.Eff.Concurrent.Protocol.EffectfulServer and adds a -- default State and Reader effect. class (Typeable (Protocol a)) => Server (a :: Type) q where { -- | The value that defines what is required to initiate a Server -- loop. data family StartArgument a q; -- | The index type of the Events that this server processes. This -- is the first parameter to the Request and therefore of the -- Pdu family. type family Protocol a :: Type; -- | Type of the model data, given to every invocation of -- update via the ModelState effect. The model of a -- server loop is changed through incoming Events. It is -- initially calculated by setup. type family Model a :: Type; -- | Type of read-only state. type family Settings a :: Type; type Protocol a = a; type Model a = (); type Settings a = (); } -- | Return an initial Model and Settings setup :: Server a q => Endpoint (Protocol a) -> StartArgument a q -> Eff q (Model a, Settings a) -- | Return an initial Model and Settings setup :: (Server a q, Default (Model a), Default (Settings a)) => Endpoint (Protocol a) -> StartArgument a q -> Eff q (Model a, Settings a) -- | Update the Model based on the Event. update :: Server a q => Endpoint (Protocol a) -> StartArgument a q -> Event (Protocol a) -> Eff (ModelState a : (SettingsReader a : q)) () -- | Execute the server loop. start :: forall a r q h. (HasCallStack, Typeable a, LogsTo h (Processes q), Server (Stateful a) (Processes q), Server a (Processes q), HasProcesses r q) => StartArgument a (Processes q) -> Eff r (Endpoint (Protocol a)) -- | Execute the server loop. startLink :: forall a r q h. (HasCallStack, Typeable a, LogsTo h (Processes q), Server (Stateful a) (Processes q), Server a (Processes q), HasProcesses r q) => StartArgument a (Processes q) -> Eff r (Endpoint (Protocol a)) -- | The Effect type of mutable Model in a Server -- instance. type ModelState a = State (Model a) -- | Modify the Model of a Server. modifyModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e () -- | Modify the Model of a Server and return the old value. getAndModifyModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e (Model a) -- | Modify the Model of a Server and return the new value. modifyAndGetModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e (Model a) -- | Return the Model of a Server. getModel :: forall a e. Member (ModelState a) e => Eff e (Model a) -- | Overwrite the Model of a Server. putModel :: forall a e. Member (ModelState a) e => Model a -> Eff e () -- | Overwrite the Model of a Server, return the old value. getAndPutModel :: forall a e. Member (ModelState a) e => Model a -> Eff e (Model a) -- | Return a element selected by a Lens of the Model of a -- Server. useModel :: forall a b e. Member (ModelState a) e => Getting b (Model a) b -> Eff e b -- | Run an action that modifies portions of the Model of a -- Server defined by the given Lens. zoomModel :: forall a b c e. Member (ModelState a) e => Lens' (Model a) b -> Eff (State b : e) c -> Eff e c -- | The Effect type of readonly Settings in a Server -- instance. type SettingsReader a = Reader (Settings a) -- | Return the read-only Settings of a Server askSettings :: forall a e. Member (SettingsReader a) e => Eff e (Settings a) -- | Return the read-only Settings of a Server as viewed -- through a Lens viewSettings :: forall a b e. Member (SettingsReader a) e => Getting b (Settings a) b -> Eff e b -- | This event sum-type is used to communicate incoming messages and other -- events to the instances of Server. data Event a -- | A Synchronous message was received. If an implementation wants -- to delegate nested Pdus, it can use -- toEmbeddedReplyTarget to convert a ReplyTarget safely to -- the embedded protocol. [OnCall] :: forall a r. (Tangible r, TangiblePdu a ( 'Synchronous r)) => ReplyTarget a r -> Pdu a ( 'Synchronous r) -> Event a [OnCast] :: forall a. TangiblePdu a 'Asynchronous => Pdu a 'Asynchronous -> Event a [OnInterrupt] :: Interrupt 'Recoverable -> Event a [OnDown] :: ProcessDown -> Event a [OnTimeOut] :: TimerElapsed -> Event a [OnMessage] :: StrictDynamic -> Event a instance Control.Eff.Concurrent.Protocol.StatefulServer.Server a q => Control.Eff.Concurrent.Protocol.EffectfulServer.Server (Control.Eff.Concurrent.Protocol.StatefulServer.Stateful a) q -- | Functions for protocol clients. -- -- This modules is required to write clients that sendPdus. module Control.Eff.Concurrent.Protocol.Client -- | Send a request Pdu that has no reply and return immediately. -- -- The type signature enforces that the corresponding Pdu clause -- is Asynchronous. The operation never fails, if it is important -- to know if the message was delivered, use call instead. -- -- The message will be reduced to normal form (rnf) in the -- caller process. cast :: forall destination protocol r q. (HasCallStack, HasProcesses r q, HasPdu destination, HasPdu protocol, Tangible (Pdu destination 'Asynchronous), Embeds destination protocol) => Endpoint destination -> Pdu protocol 'Asynchronous -> Eff r () -- | Send a request Pdu and wait for the server to return a result -- value. -- -- The type signature enforces that the corresponding Pdu clause -- is Synchronous. -- -- Always prefer callWithTimeout over call call :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Embeds destination protocol, HasCallStack) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Eff r result -- | Send an request Pdu and wait for the server to return a result -- value. -- -- The type signature enforces that the corresponding Pdu clause -- is Synchronous. -- -- If the server that was called dies, this function interrupts the -- process with ProcessDown. If the server takes longer to reply -- than the given timeout, this function interrupts the process with -- TimeoutInterrupt. -- -- Always prefer this function over call callWithTimeout :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack, Embeds destination protocol) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result -- | Like castEndpointReader, but uses embedPdu to embed the -- value. -- -- This function makes use of AmbigousTypes and TypeApplications. -- -- When not working with an embedded Pdu use -- castEndpointReader. castSingleton :: forall outer inner q e. (HasCallStack, Member (EndpointReader outer) e, Tangible (Pdu outer 'Asynchronous), HasProcesses e q, HasPdu outer, HasPdu inner, Embeds outer inner, Embeds outer outer) => Pdu inner 'Asynchronous -> Eff e () -- | Like cast but take the Endpoint from the reader provided -- by runEndpointReader. -- -- When working with an embedded Pdu use castSingleton. castEndpointReader :: forall o r q. (HasEndpointReader o r, HasProcesses r q, Tangible (Pdu o 'Asynchronous), HasCallStack, HasPdu o, Embeds o o) => Pdu o 'Asynchronous -> Eff r () -- | Like callEndpointReader, uses embedPdu to embed the -- value. -- -- This function makes use of AmbigousTypes and TypeApplications. -- -- When not working with an embedded Pdu use -- callEndpointReader. callSingleton :: forall outer inner reply q e. (HasCallStack, Member (EndpointReader outer) e, Embeds outer inner, Embeds outer outer, HasProcesses e q, TangiblePdu outer ( 'Synchronous reply), TangiblePdu inner ( 'Synchronous reply), Tangible reply) => Pdu inner ( 'Synchronous reply) -> Eff e reply -- | Like call but take the Endpoint from the reader provided -- by runEndpointReader. -- -- When working with an embedded Pdu use callSingleton. callEndpointReader :: forall reply o r q. (HasEndpointReader o r, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), HasProcesses r q, Embeds o o) => Pdu o ( 'Synchronous reply) -> Eff r reply -- | Instead of passing around a Endpoint value and passing to -- functions like cast or call, a Endpoint can -- provided by a Reader effect, if there is only a single -- server for a given Pdu instance. This type alias is -- convenience to express that an effect has Process and a reader -- for a Endpoint. type HasEndpointReader o r = (Typeable o, Member (EndpointReader o) r) -- | The reader effect for ProcessIds for Pdus, see -- runEndpointReader type EndpointReader o = Reader (Endpoint o) -- | Get the Endpoint registered with runEndpointReader. askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o) -- | Run a reader effect that contains the one server handling a -- specific Pdu instance. runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a -- | A process supervisor spawns and monitors child processes. -- -- The child processes are mapped to symbolic identifier values: -- Child-IDs. -- -- This is the barest, most minimal version of a supervisor. Children can -- be started, but not restarted. -- -- Children can efficiently be looked-up by an id-value, and when the -- supervisor is shutdown, all children will be shutdown these are -- actually all the features of this supervisor implementation. -- -- Also, this minimalist supervisor only knows how to spawn a single kind -- of child process. -- -- When a supervisor spawns a new child process, it expects the child -- process to return a ProcessId. The supervisor will -- monitor the child process. -- -- This is in stark contrast to how Erlang/OTP handles things; In the OTP -- Supervisor, the child has to link to the parent. This allows the child -- spec to be more flexible in that no pid has to be passed from -- the child start function to the supervisor process, and also, a child -- may break free from the supervisor by unlinking. -- -- Now while this seems nice at first, this might actually cause -- surprising results, since it is usually expected that stopping a -- supervisor also stops the children, or that a child exit shows up in -- the logging originating from the former supervisor. -- -- The approach here is to allow any child to link to the supervisor to -- realize when the supervisor was violently killed, and otherwise give -- the child no chance to unlink itself from its supervisor. -- -- This module is far simpler than the Erlang/OTP counter part, of a -- simple_one_for_one supervisor. -- -- The future of this supervisor might not be a-lot more than it -- currently is. The ability to restart processes might be implemented -- outside of this supervisor module. -- -- One way to do that is to implement the restart logic in a separate -- module, since the child-id can be reused when a child exits. module Control.Eff.Concurrent.Protocol.Supervisor -- | The index type of Server supervisors. -- -- A Sup p manages the life cycle of the processes, -- running the Server p methods of that specific type. -- -- The supervisor maps an identifier value of type ChildId -- p to an Endpoint p. data Sup (p :: Type) -- | The type of value used to index running Server processes -- managed by a Sup. -- -- Note, that the type you provide must be Tangible. type family ChildId p -- | The value that defines what is required to initiate a Server -- loop. data family StartArgument a q supConfigChildStopTimeout :: StartArgument (Sup p) (Processes q) -> Timeout -- | Runtime-Errors occurring when spawning child-processes. data SpawnErr p AlreadyStarted :: ChildId p -> Endpoint (Protocol p) -> SpawnErr p -- | Start and link a new supervisor process with the given -- SpawnFununction. -- -- To spawn new child processes use spawnChild. startSupervisor :: forall p e. (HasCallStack, LogIo (Processes e), TangibleSup p, Server (Sup p) (Processes e)) => StartArgument (Sup p) (Processes e) -> Eff (Processes e) (Endpoint (Sup p)) -- | Stop the supervisor and shutdown all processes. -- -- Block until the supervisor has finished. stopSupervisor :: (HasCallStack, HasProcesses e q, Member Logs e, Lifted IO e, TangibleSup p) => Endpoint (Sup p) -> Eff e () -- | Check if a supervisor process is still alive. isSupervisorAlive :: forall p q0 e. (HasCallStack, Member Logs e, Typeable p, HasProcesses e q0) => Endpoint (Sup p) -> Eff e Bool -- | Monitor a supervisor process. monitorSupervisor :: forall p q0 e. (HasCallStack, Member Logs e, HasProcesses e q0, TangibleSup p) => Endpoint (Sup p) -> Eff e MonitorReference -- | Return a Text describing the current state of the supervisor. getDiagnosticInfo :: forall p e q0. (HasCallStack, HasProcesses e q0, TangibleSup p) => Endpoint (Sup p) -> Eff e Text -- | Start, link and monitor a new child process using the -- SpawnFun passed to startSupervisor. spawnChild :: forall p q0 e. (HasCallStack, Member Logs e, HasProcesses e q0, TangibleSup p, Typeable (Protocol p)) => Endpoint (Sup p) -> ChildId p -> Eff e (Either (SpawnErr p) (Endpoint (Protocol p))) -- | Lookup the given child-id and return the output value of the -- SpawnFun if the client process exists. lookupChild :: forall p e q0. (HasCallStack, Member Logs e, HasProcesses e q0, TangibleSup p, Typeable (Protocol p)) => Endpoint (Sup p) -> ChildId p -> Eff e (Maybe (Endpoint (Protocol p))) -- | Stop a child process, and block until the child has exited. -- -- Return True if a process with that ID was found, False -- if no process with the given ID was running. stopChild :: forall p e q0. (HasCallStack, Member Logs e, HasProcesses e q0, TangibleSup p) => Endpoint (Sup p) -> ChildId p -> Eff e Bool instance GHC.Generics.Generic (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance (Data.Typeable.Internal.Typeable (Control.Eff.Concurrent.Protocol.StatefulServer.Protocol p), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance Data.Typeable.Internal.Typeable p => Control.Eff.Concurrent.Protocol.HasPdu (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) instance (Control.Eff.Log.Handler.LogIo q, Control.Eff.Concurrent.Protocol.Supervisor.TangibleSup p, Control.Eff.Concurrent.Protocol.Tangible (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p), Control.Eff.Concurrent.Protocol.StatefulServer.Server p (Control.Eff.Concurrent.Process.Processes q)) => Control.Eff.Concurrent.Protocol.StatefulServer.Server (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) (Control.Eff.Concurrent.Process.Processes q) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) ('Control.Eff.Concurrent.Protocol.Synchronous r)) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) ('Control.Eff.Concurrent.Protocol.Synchronous r)) -- | Observer Effects -- -- This module supports the implementation of observerRegistry and -- observables. Expected use case is event propagation. -- -- The observable event sources and the observers are usually server -- processes for a protocol that embeds the ObserverRegistry and -- Observer Pdus respectively. -- -- A generic FIFO queue based observer can be found in -- Control.Eff.Concurrent.Protocol.Observer.Queue. module Control.Eff.Concurrent.Protocol.Observer -- | A protocol to communicate Observed events from a sources -- to many sinks. -- -- A sink is any process that serves a protocol with a Pdu -- instance that embeds the Observer Pdu via an HasPduPrism -- instance. -- -- This type has dual use, for one it serves as type-index for -- Pdu, i.e. HasPdu respectively, and secondly it contains -- an ObservationSink and a MonitorReference. -- -- The ObservationSink is used to serialize and send the -- Observed events, while the ProcessId serves as key for -- internal maps. newtype Observer event MkObserver :: Arg ProcessId (ObservationSink event) -> Observer event -- | The Information necessary to wrap an Observed event to a -- process specific message, e.g. the embedded Observer Pdu -- instance, and the MonitorReference of the destination process. data ObservationSink event -- | Convenience type alias. type IsObservable eventSource event = (Tangible event, Embeds eventSource (ObserverRegistry event), HasPdu eventSource) -- | Convenience type alias. type CanObserve eventSink event = (Tangible event, Embeds eventSink (Observer event), HasPdu eventSink) -- | The protocol data unit type for the given protocol. data family Pdu protocol (reply :: Synchronicity) -- | And an Observer to the set of recipients for all observations -- reported by observerRegistryNotify. Note that the -- observerRegistry are keyed by the observing process, i.e. a previous -- entry for the process contained in the Observer is overwritten. -- If you want multiple entries for a single process, just combine -- several filter functions. registerObserver :: forall event eventSink eventSource r q. (HasCallStack, HasProcesses r q, IsObservable eventSource event, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r () -- | Send the ForgetObserver message forgetObserver :: forall event eventSink eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), IsObservable eventSource event, CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r () -- | Send the ForgetObserver message, use a raw ProcessId as -- parameter. forgetObserverUnsafe :: forall event eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), IsObservable eventSource event) => Endpoint eventSource -> ProcessId -> Eff r () -- | A protocol for managing Observers, encompassing registration -- and de-registration of Observers. data ObserverRegistry (event :: Type) MkObserverRegistry :: Map ProcessId (ObservationSink event) -> ObserverRegistry [_observerRegistry] :: ObserverRegistry -> Map ProcessId (ObservationSink event) -- | Alias for the effect that contains the observers managed by -- evalObserverRegistryState type ObserverRegistryState event = State (ObserverRegistry event) -- | Report an observation to all observers. The process needs to -- evalObserverRegistryState and to -- observerRegistryHandlePdu. observerRegistryNotify :: forall event r q. (HasProcesses r q, Member (ObserverRegistryState event) r, Tangible event, HasCallStack) => event -> Eff r () -- | Keep track of registered Observers. -- -- Handle the ObserverRegistryState effect, i.e. run -- evalState on an emptyObserverRegistry. evalObserverRegistryState :: HasCallStack => Eff (ObserverRegistryState event : r) a -> Eff r a -- | The empty ObserverRegistryState emptyObserverRegistry :: ObserverRegistry event -- | Provide the implementation for the ObserverRegistry Protocol, -- this handled RegisterObserver and ForgetObserver -- messages. It also adds the ObserverRegistryState constraint to -- the effect list. observerRegistryHandlePdu :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => Pdu (ObserverRegistry event) 'Asynchronous -> Eff r () -- | Remove the entry in the ObserverRegistry for the -- ProcessId and return True if there was an entry, -- False otherwise. observerRegistryRemoveProcess :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => ProcessId -> Eff r Bool instance forall k (event :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Observer.Observer event) instance forall k (event :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Observer.Observer event) instance forall k (event :: k). GHC.Generics.Generic (Control.Eff.Concurrent.Protocol.Observer.ObservationSink event) instance Control.Eff.Concurrent.Protocol.Tangible event => Control.Eff.Concurrent.Protocol.HasPdu (Control.Eff.Concurrent.Protocol.Observer.ObserverRegistry event) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.ObserverRegistry event) r) instance Data.Typeable.Internal.Typeable event => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.ObserverRegistry event) r) instance forall k (event :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Observer.Observer event) instance forall k (event :: k). Data.Typeable.Internal.Typeable event => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Observer.Observer event) instance Control.Eff.Concurrent.Protocol.Tangible event => Control.Eff.Concurrent.Protocol.HasPdu (Control.Eff.Concurrent.Protocol.Observer.Observer event) instance Control.DeepSeq.NFData event => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.Observer event) r) instance GHC.Show.Show event => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.Observer event) r) instance forall k (event :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Observer.ObservationSink event) -- | A small process to capture and _share_ observation's by enqueueing -- them into an STM TBQueue. module Control.Eff.Concurrent.Protocol.Observer.Queue -- | Contains a TBQueue capturing observations. See observe. newtype ObservationQueue a ObservationQueue :: TBQueue a -> ObservationQueue a -- | A Reader for an ObservationQueue. type ObservationQueueReader a = Reader (ObservationQueue a) -- | Listen to, and capture observations in an ObservationQueue. -- -- Fork an Observer process that runs only while the body -- expression is executed. Register the observer to the observable -- process passed to this function. -- -- The captured observations can be obtained by await, -- tryRead and flush. -- -- The queue size is limited to the given number. -- --
-- import qualified Control.Eff.Concurrent.Observer.Queue as OQ -- -- foo = -- do -- observed <- start SomeObservable -- OQ.observe 100 observed $ do -- ... -- cast observed DoSomething -- evt <- OQ.await @TestEvent -- ... --observe :: forall event eventSource e q len b. (HasCallStack, HasProcesses e q, LogIo q, LogIo e, IsObservable eventSource event, Integral len, Server (ObservationQueue event) (Processes q), Tangible (Pdu eventSource 'Asynchronous)) => len -> Endpoint eventSource -> Eff (ObservationQueueReader event : e) b -> Eff e b -- | Read queued observations captured and enqueued in the shared -- ObservationQueue by observe. -- -- This blocks until something was captured or an interrupt or exceptions -- was thrown. For a non-blocking variant use tryRead or -- flush. await :: forall event r. (Member (ObservationQueueReader event) r, HasCallStack, MonadIO (Eff r), Typeable event, Member Logs r) => Eff r event -- | Read queued observations captured and enqueued in the shared -- ObservationQueue by observe. -- -- Return the oldest enqueued observation immediately or Nothing -- if the queue is empty. Use await to block until an observation -- is observerRegistryNotify. tryRead :: forall event r. (Member (ObservationQueueReader event) r, HasCallStack, MonadIO (Eff r), Typeable event, Member Logs r) => Eff r (Maybe event) -- | Read at once all currently queued observations captured and enqueued -- in the shared ObservationQueue by observe. -- -- This returns immediately all currently enqueued observations. For a -- blocking variant use await. flush :: forall event r. (Member (ObservationQueueReader event) r, HasCallStack, MonadIO (Eff r), Typeable event, Member Logs r) => Eff r [event] instance (Data.Typeable.Internal.Typeable event, Control.Eff.Internal.Lifted GHC.Types.IO q, Data.OpenUnion.Member Control.Eff.Log.Handler.Logs q) => Control.Eff.Concurrent.Protocol.StatefulServer.Server (Control.Eff.Concurrent.Protocol.Observer.Queue.ObservationQueue event) (Control.Eff.Concurrent.Process.Processes q) -- | This module provides support for executing Process actions from -- IO. -- -- One use case is interacting with processes from the REPL, e.g.: -- --
-- >>> import Control.Eff.Concurrent.Process.SingleThreadedScheduler (defaultMain) ---- --
-- >>> import Control.Eff.Loop ---- --
-- >>> import Data.Dynamic ---- --
-- >>> import Data.Maybe ---- --
-- >>> s <- forkInteractiveScheduler Control.Eff.Concurrent.Process.SingleThreadedScheduler.defaultMain ---- --
-- >>> fooPid <- submit s (spawn (foreverCheap (receiveAnyMessage SP >>= (logMsg . fromMaybe "Huh!??" . fromDynamic)))) ---- --
-- >>> fooPid -- <0.1.0> ---- --
-- >>> submit s (sendMessageAs SP fooPid "test") -- test ---- --
-- >>> submit s (sendShutdown SP fooPid) --module Control.Eff.Concurrent.Process.Interactive -- | Contains the communication channels to interact with a scheduler -- running in its' own thread. data SchedulerSession r -- | Fork a scheduler with a process that communicates with it via -- MVar, which is also the reason for the Lift IO -- constraint. forkInteractiveScheduler :: forall r. SetMember Lift (Lift IO) r => (Eff (Processes r) () -> IO ()) -> IO (SchedulerSession r) -- | Exit the scheduler immediately using an asynchronous exception. killInteractiveScheduler :: SchedulerSession r -> IO () -- | Send a Process effect to the main process of a scheduler, this -- blocks until the effect is executed. submit :: forall r a. SetMember Lift (Lift IO) r => SchedulerSession r -> Eff (Processes r) a -> IO a -- | Combination of submit and cast. submitCast :: forall o r. (SetMember Lift (Lift IO) r, HasPdu o, Tangible (Pdu o 'Asynchronous), Member Interrupts r) => SchedulerSession r -> Endpoint o -> Pdu o 'Asynchronous -> IO () -- | Combination of submit and cast. submitCall :: forall o q r. (SetMember Lift (Lift IO) r, Member Interrupts r, Tangible (Pdu o ( 'Synchronous q)), HasPdu o, Tangible q) => SchedulerSession r -> Endpoint o -> Pdu o ( 'Synchronous q) -> IO q -- | Build a Control.Eff.Concurrent.EffectfulServer from callbacks. -- -- This module contains in instance of Server that delegates to -- callback functions. module Control.Eff.Concurrent.Protocol.CallbackServer -- | Execute the server loop, that dispatches incoming events to either a -- set of Callbacks or CallbacksEff. start :: forall (tag :: Type) eLoop q h e. (HasCallStack, TangibleCallbacks tag eLoop q, Server (Server tag eLoop) (Processes q), LogsTo h (Processes q), HasProcesses e q) => CallbacksEff tag eLoop q -> Eff e (Endpoint tag) -- | Execute the server loop, that dispatches incoming events to either a -- set of Callbacks or CallbacksEff. startLink :: forall (tag :: Type) eLoop q h e. (HasCallStack, TangibleCallbacks tag eLoop q, Server (Server tag eLoop) (Processes q), LogsTo h (Processes q), HasProcesses e q) => CallbacksEff tag eLoop q -> Eff e (Endpoint tag) -- | Phantom type to indicate a callback based Server instance. data Server tag eLoop -- | The name/id of a Server for logging purposes. newtype ServerId (tag :: Type) MkServerId :: Text -> ServerId [_fromServerId] :: ServerId -> Text -- | This event sum-type is used to communicate incoming messages and other -- events to the instances of Server. data Event a -- | A Synchronous message was received. If an implementation wants -- to delegate nested Pdus, it can use -- toEmbeddedReplyTarget to convert a ReplyTarget safely to -- the embedded protocol. [OnCall] :: forall a r. (Tangible r, TangiblePdu a ( 'Synchronous r)) => ReplyTarget a r -> Pdu a ( 'Synchronous r) -> Event a [OnCast] :: forall a. TangiblePdu a 'Asynchronous => Pdu a 'Asynchronous -> Event a [OnInterrupt] :: Interrupt 'Recoverable -> Event a [OnDown] :: ProcessDown -> Event a [OnTimeOut] :: TimerElapsed -> Event a [OnMessage] :: StrictDynamic -> Event a -- | The constraints for a tangible Server instance. type TangibleCallbacks tag eLoop e = (HasProcesses eLoop e, Typeable e, Typeable eLoop, Typeable tag) -- | A convenience type alias for callbacks that do not need a custom -- effect. type Callbacks tag e = CallbacksEff tag (Processes e) e -- | A smart constructor for Callbacks. callbacks :: forall tag q h. (HasCallStack, TangibleCallbacks tag (Processes q) q, Server (Server tag (Processes q)) (Processes q), LogsTo h q) => (Endpoint tag -> Event tag -> Eff (Processes q) ()) -> ServerId tag -> Callbacks tag q -- | A simple smart constructor for Callbacks. onEvent :: forall tag q h. (HasCallStack, TangibleCallbacks tag (Processes q) q, Server (Server tag (Processes q)) (Processes q), LogsTo h q) => (Event tag -> Eff (Processes q) ()) -> ServerId (tag :: Type) -> Callbacks tag q -- | A convenience type alias for effectful callback based -- Server instances. -- -- See Callbacks. type CallbacksEff tag eLoop e = Init (Server tag eLoop) (Processes e) -- | A smart constructor for CallbacksEff. callbacksEff :: forall tag eLoop q h. (HasCallStack, TangibleCallbacks tag eLoop q, Server (Server tag eLoop) (Processes q), LogsTo h q) => (forall x. Endpoint tag -> Eff eLoop x -> Eff (Processes q) x) -> (Endpoint tag -> Event tag -> Eff eLoop ()) -> ServerId tag -> CallbacksEff tag eLoop q -- | A simple smart constructor for CallbacksEff. onEventEff :: (HasCallStack, TangibleCallbacks tag eLoop q, Server (Server tag eLoop) (Processes q), LogsTo h q) => (forall a. Eff eLoop a -> Eff (Processes q) a) -> (Event tag -> Eff eLoop ()) -> ServerId (tag :: Type) -> CallbacksEff tag eLoop q instance Data.String.IsString (Control.Eff.Concurrent.Protocol.CallbackServer.ServerId tag) instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.CallbackServer.ServerId tag) instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.CallbackServer.ServerId tag) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.CallbackServer.ServerId tag) instance Data.Typeable.Internal.Typeable tag => GHC.Show.Show (Control.Eff.Concurrent.Protocol.CallbackServer.ServerId tag) instance Control.Eff.Concurrent.Protocol.CallbackServer.TangibleCallbacks tag eLoop e => Control.Eff.Concurrent.Protocol.EffectfulServer.Server (Control.Eff.Concurrent.Protocol.CallbackServer.Server tag eLoop) (Control.Eff.Concurrent.Process.Processes e) instance Control.Eff.Concurrent.Protocol.CallbackServer.TangibleCallbacks tag eLoop e => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.EffectfulServer.Init (Control.Eff.Concurrent.Protocol.CallbackServer.Server tag eLoop) (Control.Eff.Concurrent.Process.Processes e)) instance Control.Eff.Concurrent.Protocol.CallbackServer.TangibleCallbacks tag eLoop e => GHC.Show.Show (Control.Eff.Concurrent.Protocol.EffectfulServer.Init (Control.Eff.Concurrent.Protocol.CallbackServer.Server tag eLoop) (Control.Eff.Concurrent.Process.Processes e)) -- | Capture LogMessages to a Writer. -- -- See exampleLogCapture module Control.Eff.LogWriter.Capture -- | A LogWriter monad that provides pure logging by capturing via -- the Writer effect. -- -- See exampleLogCapture captureLogWriter :: LogWriter CaptureLogWriter -- | A LogWriter monad that provides pure logging by capturing via -- the Writer effect. type CaptureLogs a = LogWriterM CaptureLogWriter a -- | Alias for the Writer that contains the captured -- LogMessages from CaptureLogs. type CaptureLogWriter = Writer LogMessage -- | Run a Writer for LogMessages. -- -- Such a Writer is needed to handle CaptureLogWriter runCaptureLogWriter :: Eff (CaptureLogWriter : e) a -> Eff e (a, [LogMessage]) -- | Functions for generic, IO-based LogWriters. -- -- This module is more low-level than the others in this directory. module Control.Eff.LogWriter.IO -- | A LogWriter that uses an IO action to write the message. -- -- This is just an alias for MkLogWriter but with IO as -- parameter. This reduces the need to apply something to the extra type -- argument @IO. -- -- Example use cases for this function are the consoleLogWriter -- and the ioHandleLogWriter. mkLogWriterIO :: HasCallStack => (LogMessage -> IO ()) -> LogWriter (Lift IO) -- | A LogWriter that renders LogMessages to strings via -- renderLogMessageConsoleLog and prints them to an Handle -- using hPutStrLn. ioHandleLogWriter :: HasCallStack => Handle -> LogWriter (Lift IO) -- | Decorate an IO based LogWriter to fill out these fields in -- LogMessages: -- --
-- exampleWithIoLogging :: IO () -- exampleWithIoLogging = -- runLift -- $ withIoLogging debugTraceLogWriter -- "my-app" -- local7 -- (lmSeverityIsAtLeast informationalSeverity) -- $ logInfo "Oh, hi there" --withIoLogging :: Lifted IO e => LogWriter (Lift IO) -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | The concrete list of Effects for logging with an IO based -- LogWriter, and a LogWriterReader. type LoggingAndIo = '[Logs, LogWriterReader (Lift IO), Lift IO] -- | Render a LogMessage but set the timestamp and thread id fields. printLogMessage :: LogMessage -> IO () -- | This helps to setup logging to a file. module Control.Eff.LogWriter.File -- | Enable logging to a file, with some LogMessage fields preset as -- described in withIoLogging. -- -- If the file or its directory does not exist, it will be created. -- -- Example: -- --
-- exampleWithFileLogging :: IO () -- exampleWithFileLogging = -- runLift -- $ withFileLogging "/var/log/my-app.log" "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withFileLogging :: (Lifted IO e, MonadBaseControl IO (Eff e)) => FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a file. -- -- If the file or its directory does not exist, it will be created. -- Example: -- --
-- exampleWithFileLogWriter :: IO () -- exampleWithFileLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withFileLogWriter "test.log" -- $ logInfo "Oh, hi there" --withFileLogWriter :: (LogIo e, MonadBaseControl IO (Eff e)) => FilePath -> Eff e b -> Eff e b -- | This helps to setup logging via Debug.Trace. module Control.Eff.LogWriter.DebugTrace -- | Enable logging via traceM using the debugTraceLogWriter. -- The logging monad type can be any type with a Monad -- instance. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogWriter :: IO () -- exampleWithTraceLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withTraceLogWriter -- $ logInfo "Oh, hi there" --withTraceLogWriter :: forall h e a. (Monad (LogWriterM h), LogsTo h e) => Eff e a -> Eff e a -- | Enable logging via traceM using the debugTraceLogWriter, -- with some LogMessage fields preset as in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogging :: IO () -- exampleWithTraceLogging = -- runLift -- $ withTraceLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" --withTraceLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Write LogMessages via traceM. debugTraceLogWriter :: forall h. Monad (LogWriterM h) => LogMessageRenderer Text -> LogWriter h -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.Console -- | Enable logging to standard output using the -- consoleLogWriter. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogWriter :: IO () -- exampleWithConsoleLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withConsoleLogWriter -- $ logInfo "Oh, hi there" --withConsoleLogWriter :: LogIo e => Eff e a -> Eff e a -- | Enable logging to standard output using the -- consoleLogWriter, with some LogMessage fields preset as -- in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogging :: IO () -- exampleWithConsoleLogging = -- runLift -- $ withConsoleLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withConsoleLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Write LogMessages to standard output, formatted with -- printLogMessage. -- -- It uses stdoutLogWriter with renderLogMessageConsoleLog. consoleLogWriter :: LogWriter (Lift IO) -- | A LogWriter that uses a LogMessageRenderer to render, -- and putStrLn to print it. stdoutLogWriter :: LogMessageRenderer Text -> LogWriter (Lift IO) -- | This module only exposes a LogWriter for asynchronous logging; module Control.Eff.LogWriter.Async -- | Move the current LogWriter into its own thread. -- -- A bounded queue is used to forward logs to the process. -- -- If an exception is received, the logging process will be killed. -- -- Log messages are deeply evaluated before being sent to the logger -- process, to prevent that lazy evaluation leads to heavy work being -- done in the logger process instead of the caller process. -- -- Example: -- --
-- exampleAsyncLogWriter :: IO () -- exampleAsyncLogWriter = -- runLift -- $ withLogging consoleLogWriter -- $ withAsyncLogWriter (1000::Int) -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), Integral len) => len -> Eff e a -> Eff e a -- | This is a wrapper around withAsyncLogWriter and -- withIoLogging. -- -- Example: -- --
-- exampleWithAsyncLogging :: IO () -- exampleWithAsyncLogging = -- runLift -- $ withAsyncLogWriter consoleLogWriter (1000::Int) "my-app" local0 allLogMessages -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogging :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter (Lift IO) -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | A coroutine based, single threaded scheduler for Processes. module Control.Eff.Concurrent.Process.SingleThreadedScheduler -- | Handle the Process effect, as well as all lower effects using -- an effect handler function. -- -- Execute the main Process and all the other processes -- spawned by it in the current thread concurrently, using a -- co-routine based, round-robin scheduler. If a process exits with eg.g -- exitNormally or exitWithError or is killed by another -- process Left ... is returned. Otherwise, the result will be -- wrapped in a Right. -- -- Every time a process _yields_ the effects are evaluated down to the a -- value of type m (Either String a). -- -- If the evaluator function runs the action down e.g. IO this -- might improve memory consumption, for long running services, with -- processes that loop endlessly. scheduleM :: forall m r a. Monad m => (forall b. Eff r b -> m b) -> m () -> Eff (Processes r) a -> m (Either (Interrupt 'NoRecovery) a) -- | Invoke scheduleM with lift yield as yield -- effect. scheduleMonadIOEff == scheduleM id (liftIO -- yield) scheduleMonadIOEff :: MonadIO (Eff r) => Eff (Processes r) a -> Eff r (Either (Interrupt 'NoRecovery) a) -- | Run processes that have the Logs and the Lift effects. -- The user must provide a log handler function. -- -- Log messages are evaluated strict. -- --
-- scheduleIOWithLogging == scheduleIO . withLogging --scheduleIOWithLogging :: HasCallStack => LogWriter (Lift IO) -> Eff EffectsIo a -> IO (Either (Interrupt 'NoRecovery) a) -- | Like scheduleIO but pure. The yield effect is -- just return (). schedulePure == runIdentity . -- scheduleM (Identity . run) (return ()) schedulePure :: Eff (Processes '[Logs, LogWriterReader Logs]) a -> Either (Interrupt 'NoRecovery) a -- | The effect list for Process effects in the single threaded pure -- scheduler. -- -- See PureBaseEffects and Processes type PureEffects = Processes PureBaseEffects -- | The effect list for Process effects in the single threaded pure -- scheduler. This is like SafeProcesses, no Interrupts are -- present. -- -- See PureBaseEffects and SafeProcesses type PureSafeEffects = SafeProcesses PureBaseEffects -- | The effect list for a pure, single threaded scheduler contains only -- Logs and the LogWriterReader for PureLogWriter. type PureBaseEffects = '[Logs, LogWriterReader Logs] -- | Constraint for the existence of the underlying scheduler effects. -- -- See PureBaseEffects type HasPureBaseEffects e = (HasCallStack, PureBaseEffects <:: e) -- | Execute a Process using scheduleM on top of Lift -- IO. All logging is written to the console using -- consoleLogWriter. -- -- To use another LogWriter use defaultMainWithLogWriter -- instead. defaultMain :: HasCallStack => Eff EffectsIo () -> IO () -- | Execute a Process using scheduleM on top of Lift -- IO. All logging is written using the given LogWriter. defaultMainWithLogWriter :: HasCallStack => LogWriter (Lift IO) -> Eff EffectsIo () -> IO () -- | Invoke scheduleM with lift yield as yield -- effect. scheduleIO runEff == scheduleM (runLift . runEff) -- (liftIO yield) scheduleIO :: MonadIO m => (forall b. Eff r b -> Eff '[Lift m] b) -> Eff (Processes r) a -> m (Either (Interrupt 'NoRecovery) a) -- | The effect list for Process effects in the single threaded -- scheduler. -- -- See BaseEffectsIo type EffectsIo = Processes BaseEffectsIo -- | The effect list for Process effects in the single threaded -- scheduler. This is like SafeProcesses, no Interrupts are -- present. -- -- See BaseEffectsIo. type SafeEffectsIo = SafeProcesses BaseEffectsIo -- | The effect list for the underlying scheduler. -- -- See LoggingAndIo type BaseEffectsIo = LoggingAndIo -- | Constraint for the existence of the underlying scheduler effects. type HasBaseEffectsIo e = (HasCallStack, Lifted IO e, LoggingAndIo <:: e) instance GHC.Show.Show (Control.Eff.Concurrent.Process.SingleThreadedScheduler.OnYield r a) instance GHC.Show.Show (Control.Eff.Concurrent.Process.SingleThreadedScheduler.STS r m) instance GHC.Show.Show Control.Eff.Concurrent.Process.SingleThreadedScheduler.ProcessInfo -- | Implement Erlang style message passing concurrency. -- -- This module contains spawn which handles the Process -- effects, using TQueues and withAsync. -- -- This aims to be a pragmatic implementation, so even logging is -- supported. -- -- At the core is a main process that enters schedule and -- creates all of the internal state stored in TVars to manage -- processes with message queues. module Control.Eff.Concurrent.Process.ForkIOScheduler -- | This is the main entry point to running a message passing concurrency -- application. This function takes a Process on top of the -- BaseEffects effect for concurrent logging. schedule :: HasCallStack => Eff Effects () -> Eff LoggingAndIo () -- | Start the message passing concurrency system then execute a -- Process on top of BaseEffects effect. All logging is -- sent to standard output. defaultMain :: HasCallStack => Eff Effects () -> IO () -- | Start the message passing concurrency system then execute a -- Process on top of BaseEffects effect. All logging is -- sent to standard output. defaultMainWithLogWriter :: HasCallStack => LogWriter (Lift IO) -> Eff Effects () -> IO () -- | The concrete list of Effects of processes compatible with this -- scheduler. This builds upon BaseEffects. type SafeEffects = SafeProcesses BaseEffects -- | The Effects for interruptable, concurrent processes, scheduled -- via forkIO. type Effects = Processes BaseEffects -- | The concrete list of Effects for this scheduler implementation. type BaseEffects = Reader SchedulerState : LoggingAndIo -- | Type class constraint to indicate that an effect union contains the -- effects required by every process and the scheduler implementation -- itself. type HasBaseEffects r = (HasCallStack, Lifted IO r, BaseEffects <:: r) instance GHC.Show.Show Control.Eff.Concurrent.Process.ForkIOScheduler.ProcessInfo instance Data.Default.Class.Default Control.Eff.Concurrent.Process.ForkIOScheduler.MessageQ -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.UDP -- | Enable logging to a (remote-) host via UDP. -- -- See exampleUdpRFC3164Logging withUDPLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => (LogMessage -> Text) -> String -> String -> Eff e b -> Eff e b -- | Enable logging to a remote host via UDP, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleUdpRFC3164Logging withUDPLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => (LogMessage -> Text) -> String -> String -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.UnixSocket -- | Enable logging to a (remote-) host via UnixSocket. -- -- See exampleDevLogSyslogLogging withUnixSocketLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => LogMessageRenderer Text -> FilePath -> Eff e b -> Eff e b -- | Enable logging to a unix domain socket, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleDevLogSyslogLogging withUnixSocketLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => LogMessageRenderer Text -> FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Examples for Logging. module Control.Eff.Log.Examples -- | Example code for: -- --
-- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () -- | Execute a and action and return the result; if the process is -- interrupted by an error or exception, or an explicit shutdown from -- another process, or through a crash of a linked process, i.e. whenever -- the exit reason satisfies isRecoverable, return the exit -- reason. executeAndResume :: forall q r v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r (Either (Interrupt 'Recoverable) v) -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrExit :: forall r q v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrThrow :: forall q r v. (HasProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Use executeAndResumeOrExit to execute YieldProcess. -- Refer to YieldProcess for more information. yieldProcess :: forall r q. (HasProcesses r q, HasCallStack) => Eff r () -- | Send a message to a process addressed by the ProcessId. See -- SendMessage. -- -- The message will be reduced to normal form (rnf) by/in the -- caller process. sendMessage :: forall r q o. (HasProcesses r q, HasCallStack, Typeable o, NFData o) => ProcessId -> o -> Eff r () -- | Send a Dynamic value to a process addressed by the -- ProcessId. See SendMessage. sendAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> StrictDynamic -> Eff r () -- | Exit a process addressed by the ProcessId. The process will -- exit, it might do some cleanup, but is ultimately unrecoverable. See -- SendShutdown. sendShutdown :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'NoRecovery -> Eff r () -- | Interrupts a process addressed by the ProcessId. The process -- might exit, or it may continue. | Like sendInterrupt, but also -- return True iff the process to exit exists. sendInterrupt :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'Recoverable -> Eff r () -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. If the new -- process is interrupted, the process will Shutdown with the -- Interrupt wrapped in interruptToExit. For specific use -- cases it might be better to use spawnRaw. spawn :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Like spawn but return (). spawn_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r () -- | Start a new process, and immediately link to it. spawnLink :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. The spawned -- process has only the raw SafeProcesses effects. For -- non-library code spawn might be better suited. spawnRaw :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r ProcessId -- | Like spawnRaw but return (). spawnRaw_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r () -- | Return True if the process is alive. isProcessAlive :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r Bool -- | Return the ProcessTitle, ProcessDetails and -- ProcessState, for the given process, if the process is alive. getProcessState :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r (Maybe (ProcessTitle, ProcessDetails, ProcessState)) -- | Replace the ProcessDetails of the process. updateProcessDetails :: forall r q. (HasCallStack, HasProcesses r q) => ProcessDetails -> Eff r () -- | Block until a message was received. See ReceiveSelectedMessage -- for more documentation. receiveAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => Eff r StrictDynamic -- | Block until a message was received, that is not Nothing after -- applying a callback to it. See ReceiveSelectedMessage for more -- documentation. receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, HasProcesses r q) => MessageSelector a -> Eff r a -- | Receive and cast the message to some Typeable instance. See -- ReceiveSelectedMessage for more documentation. This will wait -- for a message of the return type using receiveSelectedMessage receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, HasProcesses r q) => Eff r a -- | Remove and return all messages currently enqueued in the process -- message queue. flushMessages :: forall r q. (HasCallStack, HasProcesses r q) => Eff r [StrictDynamic] -- | Enter a loop to receive messages and pass them to a callback, until -- the function returns Just a result. Only the messages of the -- given type will be received. If the process is interrupted by an -- exception of by a SendShutdown from another process, with an -- exit reason that satisfies isRecoverable, then the callback -- will be invoked with Left Interrupt, otherwise -- the process will be exited with the same reason using -- exitBecause. See also ReceiveSelectedMessage for more -- documentation. receiveSelectedLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => MessageSelector a -> (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but not selective. See also -- selectAnyMessage, receiveSelectedLoop. receiveAnyLoop :: forall r q endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => (Either (Interrupt 'Recoverable) StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but refined to casting to a specific -- Typeable using selectMessage. receiveLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack, NFData a, Typeable a) => (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Returns the ProcessId of the current process. self :: (HasCallStack, HasSafeProcesses r q) => Eff r ProcessId -- | Generate a unique Int for the current process. makeReference :: (HasCallStack, HasProcesses r q) => Eff r Int -- | Monitor another process. When the monitored process exits a -- ProcessDown is sent to the calling process. The return value is -- a unique identifier for that monitor. There can be multiple monitors -- on the same process, and a message for each will be sent. If the -- process is already dead, the ProcessDown message will be sent -- immediately, without exit reason monitor :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r MonitorReference -- | Remove a monitor created with monitor. demonitor :: forall r q. (HasCallStack, HasProcesses r q) => MonitorReference -> Eff r () -- | monitor another process before while performing an action and -- demonitor afterwards. withMonitor :: (HasCallStack, HasProcesses r q) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a -- | A MessageSelector for receiving either a monitor of the given -- process or another message. receiveWithMonitor :: (HasCallStack, HasProcesses r q, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a) -- | Make an Interrupt for a ProcessDown message. -- -- For example: doSomething >>= either (interrupt . -- becauseProcessIsDown) return becauseProcessIsDown :: ProcessDown -> Interrupt 'Recoverable -- | A MessageSelector for the ProcessDown message of a -- specific process. -- -- The parameter is the value obtained by monitor. selectProcessDown :: MonitorReference -> MessageSelector ProcessDown -- | A MessageSelector for the ProcessDown message. of a -- specific process. -- -- In contrast to selectProcessDown this function matches the -- ProcessId. selectProcessDownByProcessId :: ProcessId -> MessageSelector ProcessDown -- | Connect the calling process to another process, such that if one of -- the processes crashes (i.e. isCrash returns True), the -- other is shutdown with the Interrupt -- LinkedProcessCrashed. linkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Unlink the calling process from the other process. unlinkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Exit the process with a Interrupt. exitBecause :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Interrupt 'NoRecovery -> Eff r a -- | Exit the process. exitNormally :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Eff r a -- | Exit the process with an error. exitWithError :: forall r q a. (HasCallStack, HasSafeProcesses r q) => String -> Eff r a -- | A ProcessId and a Serializer. EXPERIMENTAL -- -- See sendToReceiver. data Receiver a Receiver :: ProcessId -> (a -> out) -> Receiver a [_receiverPid] :: Receiver a -> ProcessId [_receiverSerializer] :: Receiver a -> a -> out fromProcessId :: Iso' ProcessId Int -- | Serialize and send a message to the process in a Receiver. -- -- EXPERIMENTAL sendToReceiver :: (NFData o, HasProcesses r q) => Receiver o -> o -> Eff r () receiverPid :: forall a_aHxu. Lens' (Receiver a_aHxu) ProcessId -- | The concrete list of Effects for this scheduler implementation. type BaseEffects = Reader SchedulerState : LoggingAndIo -- | Type class constraint to indicate that an effect union contains the -- effects required by every process and the scheduler implementation -- itself. type HasBaseEffects r = (HasCallStack, Lifted IO r, BaseEffects <:: r) -- | The Effects for interruptable, concurrent processes, scheduled -- via forkIO. type Effects = Processes BaseEffects -- | The concrete list of Effects of processes compatible with this -- scheduler. This builds upon BaseEffects. type SafeEffects = SafeProcesses BaseEffects -- | Start the message passing concurrency system then execute a -- Process on top of BaseEffects effect. All logging is -- sent to standard output. defaultMain :: HasCallStack => Eff Effects () -> IO () -- | Start the message passing concurrency system then execute a -- Process on top of BaseEffects effect. All logging is -- sent to standard output. defaultMainWithLogWriter :: HasCallStack => LogWriter (Lift IO) -> Eff Effects () -> IO () -- | This is the main entry point to running a message passing concurrency -- application. This function takes a Process on top of the -- BaseEffects effect for concurrent logging. schedule :: HasCallStack => Eff Effects () -> Eff LoggingAndIo () -- | A value to be sent when timer started with startTimer has -- elapsed. data TimerElapsed -- | The reference to a timer started by startTimer, required to -- stop a timer via cancelTimer. data TimerReference -- | A number of micro seconds. data Timeout -- | Wait for a message of the given type for the given time. When no -- message arrives in time, return Nothing. This is based on -- receiveSelectedAfter. receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a) -- | Wait for a message of the given type for the given time. When no -- message arrives in time, return Left TimerElapsed. This -- is based on selectTimerElapsed and startTimer. receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a) -- | Like receiveWithMonitor combined with -- receiveSelectedAfter. receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a) -- | A MessageSelector matching TimerElapsed messages created -- by startTimer. selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed -- | Send a message to a given process after waiting. The message is -- created by applying the function parameter to the -- TimerReference, such that the message can directly refer to the -- timer. sendAfter :: forall r q message. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference -- | Start a new timer, after the time has elapsed, TimerElapsed is -- sent to calling process. The message also contains the -- TimerReference returned by this function. Use -- cancelTimer to cancel the timer. Use selectTimerElapsed -- to receive the message using receiveSelectedMessage. To receive -- messages with guarded with a timeout see receiveAfter. startTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => Timeout -> Eff r TimerReference -- | Cancel a timer started with startTimer. cancelTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => TimerReference -> Eff r () -- | A class for Pdu instances that embed other Pdu. -- -- This is a part of Embeds provide instances for your Pdus -- but in client code use the Embeds constraint. -- -- Instances of this class serve as proof to Embeds that a -- conversion into another Pdu actually exists. -- -- A Prism for the embedded Pdu is the center of this class -- -- Laws: embeddedPdu = prism' embedPdu fromPdu class (Typeable protocol, Typeable embeddedProtocol) => HasPduPrism protocol embeddedProtocol -- | A Prism for the embedded Pdus. embeddedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result) -- | Embed the Pdu value of an embedded protocol into the -- corresponding Pdu value. embedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu embeddedProtocol result -> Pdu protocol result -- | Examine a Pdu value from the outer protocol, and return it, if -- it embeds a Pdu of embedded protocol, otherwise return -- Nothing/ fromPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu protocol result -> Maybe (Pdu embeddedProtocol result) -- | This type function takes an Pdu and analysis the reply type, -- i.e. the Synchronicity and evaluates to either t for -- an Pdu x (Synchronous t) or to '()' for an Pdu x -- Asynchronous. type family ProtocolReply (s :: Synchronicity) -- | The (promoted) constructors of this type specify (at the type level) -- the reply behavior of a specific constructor of an Pdu -- instance. data Synchronicity -- | Specify that handling a request is a blocking operation with a -- specific return type, e.g. ('Synchronous (Either RentalError -- RentalId)) Synchronous :: Type -> Synchronicity -- | Non-blocking, asynchronous, request handling Asynchronous :: Synchronicity -- | A Constraint that bundles the requirements for the Pdu -- values of a protocol. -- -- This ensures that Pdus can be strictly and deeply evaluated and -- shown such that for example logging is possible. type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r), HasPdu p) -- | A set of constraints for types that can evaluated via NFData, -- compared via Ord and presented dynamically via Typeable, -- and represented both as values via Show. type Tangible i = (NFData i, Typeable i, Show i) -- | A constraint that requires that the outer Pdu has a -- clause to embed values from the inner Pdu. -- -- Also, this constraint requires a HasPduPrism instance, as a -- proof for a possible conversion of an embedded Pdu value into -- to the enclosing Pdu. -- -- This generates better compiler error messages, when an embedding of a -- Pdu into another. -- -- This is provided by HasPdu instances. The instances are -- required to provide a list of embedded Pdu values in -- EmbeddedPduList. -- -- Note that every type embeds itself, so Embeds x x always -- holds. type Embeds outer inner = (HasPduPrism outer inner, CheckEmbeds outer inner, HasPdu outer) -- | This type class and the associated data family defines the protocol -- data units (PDU) of a protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- instance Typeable r => HasPdu BookShop r where
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
-- deriving Typeable
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
class Typeable protocol => HasPdu (protocol :: Type) where {
-- | A type level list Protocol phantom types included in the associated
-- Pdu instance.
--
-- This is just a helper for better compiler error messages. It relies on
-- Embeds to add the constraint HasPduPrism.
type family EmbeddedPduList protocol :: [Type];
-- | The protocol data unit type for the given protocol.
data family Pdu protocol (reply :: Synchronicity);
type EmbeddedPduList protocol = '[];
}
-- | A server process for protocol.
--
-- Protocols are represented by phantom types, which are used in
-- different places to index type families and type class instances.
--
-- A Process can send and receive any messages. An Endpoint
-- wraps around a ProcessId and carries a phantom type to indicate
-- the kinds of messages accepted by the process.
--
-- As a metaphor, communication between processes can be thought of
-- waiting for and sending protocol data units belonging to some
-- protocol.
newtype Endpoint protocol
Endpoint :: ProcessId -> Endpoint protocol
[_fromEndpoint] :: Endpoint protocol -> ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | Convert an Endpoint to an endpoint for an embedded protocol.
--
-- See Embeds, fromEmbeddedEndpoint.
toEmbeddedEndpoint :: forall inner outer. Embeds outer inner => Endpoint outer -> Endpoint inner
-- | Convert an Endpoint to an endpoint for a server, that embeds
-- the protocol.
--
-- See Embeds, toEmbeddedEndpoint.
fromEmbeddedEndpoint :: forall outer inner. HasPduPrism outer inner => Endpoint inner -> Endpoint outer
fromEndpoint :: forall protocol_aTMy protocol_aUUM. Iso (Endpoint protocol_aTMy) (Endpoint protocol_aUUM) ProcessId ProcessId
-- | The reader effect for ProcessIds for Pdus, see
-- runEndpointReader
type EndpointReader o = Reader (Endpoint o)
-- | Instead of passing around a Endpoint value and passing to
-- functions like cast or call, a Endpoint can
-- provided by a Reader effect, if there is only a single
-- server for a given Pdu instance. This type alias is
-- convenience to express that an effect has Process and a reader
-- for a Endpoint.
type HasEndpointReader o r = (Typeable o, Member (EndpointReader o) r)
-- | Send a request Pdu that has no reply and return immediately.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Asynchronous. The operation never fails, if it is important
-- to know if the message was delivered, use call instead.
--
-- The message will be reduced to normal form (rnf) in the
-- caller process.
cast :: forall destination protocol r q. (HasCallStack, HasProcesses r q, HasPdu destination, HasPdu protocol, Tangible (Pdu destination 'Asynchronous), Embeds destination protocol) => Endpoint destination -> Pdu protocol 'Asynchronous -> Eff r ()
-- | Send a request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- Always prefer callWithTimeout over call
call :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Embeds destination protocol, HasCallStack) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Eff r result
-- | Send an request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- If the server that was called dies, this function interrupts the
-- process with ProcessDown. If the server takes longer to reply
-- than the given timeout, this function interrupts the process with
-- TimeoutInterrupt.
--
-- Always prefer this function over call
callWithTimeout :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack, Embeds destination protocol) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result
-- | Run a reader effect that contains the one server handling a
-- specific Pdu instance.
runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a
-- | Get the Endpoint registered with runEndpointReader.
askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o)
-- | Like call but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use callSingleton.
callEndpointReader :: forall reply o r q. (HasEndpointReader o r, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), HasProcesses r q, Embeds o o) => Pdu o ( 'Synchronous reply) -> Eff r reply
-- | Like cast but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use castSingleton.
castEndpointReader :: forall o r q. (HasEndpointReader o r, HasProcesses r q, Tangible (Pdu o 'Asynchronous), HasCallStack, HasPdu o, Embeds o o) => Pdu o 'Asynchronous -> Eff r ()
-- | Like callEndpointReader, uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- callEndpointReader.
callSingleton :: forall outer inner reply q e. (HasCallStack, Member (EndpointReader outer) e, Embeds outer inner, Embeds outer outer, HasProcesses e q, TangiblePdu outer ( 'Synchronous reply), TangiblePdu inner ( 'Synchronous reply), Tangible reply) => Pdu inner ( 'Synchronous reply) -> Eff e reply
-- | Like castEndpointReader, but uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- castEndpointReader.
castSingleton :: forall outer inner q e. (HasCallStack, Member (EndpointReader outer) e, Tangible (Pdu outer 'Asynchronous), HasProcesses e q, HasPdu outer, HasPdu inner, Embeds outer inner, Embeds outer outer) => Pdu inner 'Asynchronous -> Eff e ()
-- | Target of a Call reply.
--
-- This combines a RequestOrigin with a Serializer for a
-- Reply using Arg. There are to smart constructors for
-- this type: replyTarget and embeddedReplyTarget.
--
-- Because of Arg the Eq and Ord instances are
-- implemented via the RequestOrigin instances.
newtype ReplyTarget p r
MkReplyTarget :: Arg (RequestOrigin p r) (Serializer (Reply p r)) -> ReplyTarget p r
-- | Wraps the source ProcessId and a unique identifier for a
-- Call.
data RequestOrigin (proto :: Type) reply
RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply
[_requestOriginPid] :: RequestOrigin reply -> !ProcessId
[_requestOriginCallRef] :: RequestOrigin reply -> !Int
-- | The wrapper around replies to Calls.
data Reply protocol reply
[Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply
-- | A wrapper sum type for calls and casts for the Pdus of a
-- protocol
data Request protocol
[Call] :: forall protocol reply. (Tangible reply, TangiblePdu protocol ( 'Synchronous reply)) => RequestOrigin protocol reply -> Pdu protocol ( 'Synchronous reply) -> Request protocol
[Cast] :: forall protocol. (TangiblePdu protocol 'Asynchronous, NFData (Pdu protocol 'Asynchronous)) => Pdu protocol 'Asynchronous -> Request protocol
-- | Create a new, unique RequestOrigin value for the current
-- process.
makeRequestOrigin :: (Typeable r, NFData r, HasProcesses e q0) => Eff e (RequestOrigin p r)
-- | Turn an RequestOrigin to an origin for an embedded request (See
-- Embeds).
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedReplySerializer.
toEmbeddedOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin outer reply -> RequestOrigin inner reply
-- | Turn an embedded RequestOrigin to a RequestOrigin
-- for the bigger request.
--
-- This is the inverse of toEmbeddedOrigin.
--
-- This function is strict in all parameters.
embedRequestOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin inner reply -> RequestOrigin outer reply
-- | Turn a Serializer for a Pdu instance that contains
-- embedded Pdu values into a Reply Serializer for
-- the embedded Pdu.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also toEmbeddedOrigin.
embedReplySerializer :: forall outer inner reply. Embeds outer inner => Serializer (Reply outer reply) -> Serializer (Reply inner reply)
-- | Answer a Call by sending the reply value to the client process.
--
-- The ProcessId, the RequestOrigin and the Reply
-- Serializer are stored in the ReplyTarget.
sendReply :: (HasProcesses eff q, Tangible reply, Typeable protocol) => ReplyTarget protocol reply -> reply -> Eff eff ()
-- | Smart constructor for a ReplyTarget.
--
-- To build a ReplyTarget for an Embeds instance use
-- embeddedReplyTarget.
replyTarget :: Serializer (Reply p reply) -> RequestOrigin p reply -> ReplyTarget p reply
-- | A simple Lens for the RequestOrigin of a
-- ReplyTarget.
replyTargetOrigin :: Lens' (ReplyTarget p reply) (RequestOrigin p reply)
-- | A simple Lens for the Reply Serializer of a
-- ReplyTarget.
replyTargetSerializer :: Lens' (ReplyTarget p reply) (Serializer (Reply p reply))
-- | Smart constructor for an embedded ReplyTarget.
--
-- This combines replyTarget and toEmbeddedReplyTarget.
embeddedReplyTarget :: Embeds outer inner => Serializer (Reply outer reply) -> RequestOrigin outer reply -> ReplyTarget inner reply
-- | Convert a ReplyTarget to be usable for embedded replies.
--
-- This combines a toEmbeddedOrigin with
-- embedReplySerializer to produce a ReplyTarget that can
-- be passed to functions defined soley on an embedded protocol.
toEmbeddedReplyTarget :: Embeds outer inner => ReplyTarget outer reply -> ReplyTarget inner reply
-- | The protocol data unit type for the given protocol.
data family Pdu protocol (reply :: Synchronicity)
-- | Alias for the effect that contains the observers managed by
-- evalObserverRegistryState
type ObserverRegistryState event = State (ObserverRegistry event)
-- | A protocol for managing Observers, encompassing registration
-- and de-registration of Observers.
data ObserverRegistry (event :: Type)
MkObserverRegistry :: Map ProcessId (ObservationSink event) -> ObserverRegistry
[_observerRegistry] :: ObserverRegistry -> Map ProcessId (ObservationSink event)
-- | Convenience type alias.
type CanObserve eventSink event = (Tangible event, Embeds eventSink (Observer event), HasPdu eventSink)
-- | Convenience type alias.
type IsObservable eventSource event = (Tangible event, Embeds eventSource (ObserverRegistry event), HasPdu eventSource)
-- | The Information necessary to wrap an Observed event to a
-- process specific message, e.g. the embedded Observer Pdu
-- instance, and the MonitorReference of the destination process.
data ObservationSink event
-- | A protocol to communicate Observed events from a sources
-- to many sinks.
--
-- A sink is any process that serves a protocol with a Pdu
-- instance that embeds the Observer Pdu via an HasPduPrism
-- instance.
--
-- This type has dual use, for one it serves as type-index for
-- Pdu, i.e. HasPdu respectively, and secondly it contains
-- an ObservationSink and a MonitorReference.
--
-- The ObservationSink is used to serialize and send the
-- Observed events, while the ProcessId serves as key for
-- internal maps.
newtype Observer event
MkObserver :: Arg ProcessId (ObservationSink event) -> Observer event
-- | And an Observer to the set of recipients for all observations
-- reported by observerRegistryNotify. Note that the
-- observerRegistry are keyed by the observing process, i.e. a previous
-- entry for the process contained in the Observer is overwritten.
-- If you want multiple entries for a single process, just combine
-- several filter functions.
registerObserver :: forall event eventSink eventSource r q. (HasCallStack, HasProcesses r q, IsObservable eventSource event, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message
forgetObserver :: forall event eventSink eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), IsObservable eventSource event, CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message, use a raw ProcessId as
-- parameter.
forgetObserverUnsafe :: forall event eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), IsObservable eventSource event) => Endpoint eventSource -> ProcessId -> Eff r ()
-- | Provide the implementation for the ObserverRegistry Protocol,
-- this handled RegisterObserver and ForgetObserver
-- messages. It also adds the ObserverRegistryState constraint to
-- the effect list.
observerRegistryHandlePdu :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => Pdu (ObserverRegistry event) 'Asynchronous -> Eff r ()
-- | Remove the entry in the ObserverRegistry for the
-- ProcessId and return True if there was an entry,
-- False otherwise.
observerRegistryRemoveProcess :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => ProcessId -> Eff r Bool
-- | Keep track of registered Observers.
--
-- Handle the ObserverRegistryState effect, i.e. run
-- evalState on an emptyObserverRegistry.
evalObserverRegistryState :: HasCallStack => Eff (ObserverRegistryState event : r) a -> Eff r a
-- | The empty ObserverRegistryState
emptyObserverRegistry :: ObserverRegistry event
-- | Report an observation to all observers. The process needs to
-- evalObserverRegistryState and to
-- observerRegistryHandlePdu.
observerRegistryNotify :: forall event r q. (HasProcesses r q, Member (ObserverRegistryState event) r, Tangible event, HasCallStack) => event -> Eff r ()
-- | Concurrent, communicating processes, executed using a single-threaded
-- scheduler, with support for IO and Logs.
--
-- This module re-exports most of the library.
--
-- There are several scheduler implementations to choose from.
--
-- This module re-exports the impure parts of
-- Control.Eff.Concurrent.Process.SingleThreadedScheduler.
--
-- To use another scheduler implementation, don't import this module, but
-- instead import one of:
--
--
module Control.Eff.Concurrent.SingleThreaded
-- | An rfc 5424 facility
newtype Facility
Facility :: Int -> Facility
[fromFacility] :: Facility -> Int
-- | An rfc 5424 severity
data Severity
-- | Component of an RFC-5424 StructuredDataElement
data SdParameter
MkSdParameter :: !Text -> !Text -> SdParameter
-- | RFC-5424 defines how structured data can be included in a log message.
data StructuredDataElement
SdElement :: !Text -> ![SdParameter] -> StructuredDataElement
[_sdElementId] :: StructuredDataElement -> !Text
[_sdElementParameters] :: StructuredDataElement -> ![SdParameter]
-- | A message data type inspired by the RFC-5424 Syslog Protocol
data LogMessage
MkLogMessage :: !Facility -> !Severity -> Maybe UTCTime -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [StructuredDataElement] -> Maybe ThreadId -> Maybe SrcLoc -> Text -> LogMessage
[_lmFacility] :: LogMessage -> !Facility
[_lmSeverity] :: LogMessage -> !Severity
[_lmTimestamp] :: LogMessage -> Maybe UTCTime
[_lmHostname] :: LogMessage -> Maybe Text
[_lmAppName] :: LogMessage -> Maybe Text
[_lmProcessId] :: LogMessage -> Maybe Text
[_lmMessageId] :: LogMessage -> Maybe Text
[_lmStructuredData] :: LogMessage -> [StructuredDataElement]
[_lmThreadId] :: LogMessage -> Maybe ThreadId
[_lmSrcLoc] :: LogMessage -> Maybe SrcLoc
[_lmMessage] :: LogMessage -> Text
-- | Smart constructor for the RFC-5424 emergency LogMessage
-- Severity. This corresponds to the severity value 0. See
-- lmSeverity.
emergencySeverity :: Severity
-- | Smart constructor for the RFC-5424 alert LogMessage
-- Severity. This corresponds to the severity value 1. See
-- lmSeverity.
alertSeverity :: Severity
-- | Smart constructor for the RFC-5424 critical LogMessage
-- Severity. This corresponds to the severity value 2. See
-- lmSeverity.
criticalSeverity :: Severity
-- | Smart constructor for the RFC-5424 error LogMessage
-- Severity. This corresponds to the severity value 3. See
-- lmSeverity.
errorSeverity :: Severity
-- | Smart constructor for the RFC-5424 warning LogMessage
-- Severity. This corresponds to the severity value 4. See
-- lmSeverity.
warningSeverity :: Severity
-- | Smart constructor for the RFC-5424 notice LogMessage
-- Severity. This corresponds to the severity value 5. See
-- lmSeverity.
noticeSeverity :: Severity
-- | Smart constructor for the RFC-5424 informational
-- LogMessage Severity. This corresponds to the severity
-- value 6. See lmSeverity.
informationalSeverity :: Severity
-- | Smart constructor for the RFC-5424 debug LogMessage
-- Severity. This corresponds to the severity value 7. See
-- lmSeverity.
debugSeverity :: Severity
-- | Smart constructor for the RFC-5424 LogMessage facility
-- kernelMessages. See lmFacility.
kernelMessages :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- userLevelMessages. See lmFacility.
userLevelMessages :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- mailSystem. See lmFacility.
mailSystem :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- systemDaemons. See lmFacility.
systemDaemons :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- securityAuthorizationMessages4. See lmFacility.
securityAuthorizationMessages4 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- linePrinterSubsystem. See lmFacility.
linePrinterSubsystem :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- networkNewsSubsystem. See lmFacility.
networkNewsSubsystem :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- uucpSubsystem. See lmFacility.
uucpSubsystem :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- clockDaemon. See lmFacility.
clockDaemon :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- securityAuthorizationMessages10. See lmFacility.
securityAuthorizationMessages10 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- ftpDaemon. See lmFacility.
ftpDaemon :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- ntpSubsystem. See lmFacility.
ntpSubsystem :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- logAuditFacility. See lmFacility.
logAuditFacility :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- logAlertFacility. See lmFacility.
logAlertFacility :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- clockDaemon2. See lmFacility.
clockDaemon2 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local0. See lmFacility.
local0 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local1. See lmFacility.
local1 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local2. See lmFacility.
local2 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local3. See lmFacility.
local3 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local4. See lmFacility.
local4 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local5. See lmFacility.
local5 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local6. See lmFacility.
local6 :: Facility
-- | Smart constructor for the RFC-5424 LogMessage facility
-- local7. See lmFacility.
local7 :: Facility
-- | A lens for the key or ID of a group of RFC 5424 key-value pairs.
sdElementId :: Functor f => (Text -> f Text) -> StructuredDataElement -> f StructuredDataElement
-- | A lens for SdParameters
sdElementParameters :: Functor f => ([SdParameter] -> f [SdParameter]) -> StructuredDataElement -> f StructuredDataElement
-- | The filter predicate for message that shall be logged.
--
-- See Control.Eff.Log#LogPredicate
type LogPredicate = LogMessage -> Bool
-- | Things that can become a LogMessage
class ToLogMessage a
-- | Convert the value to a LogMessage
toLogMessage :: ToLogMessage a => a -> LogMessage
-- | A lens for the RFC 5424 application name of a LogMessage
--
-- One useful pattern for using this field, is to implement log filters
-- that allow info and debug message from the application itself while
-- only allowing warning and error messages from third party libraries:
--
-- -- debugLogsForAppName myAppName lm = -- view lmAppName lm == Just myAppName || lmSeverityIsAtLeast warningSeverity lm ---- -- This concept is also implemented in discriminateByAppName. lmAppName :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the Facility of a LogMessage lmFacility :: Functor f => (Facility -> f Facility) -> LogMessage -> f LogMessage -- | A lens for the hostname of a LogMessage The function -- setLogMessageHostname can be used to set the field. lmHostname :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the user defined textual message of a LogMessage lmMessage :: Functor f => (Text -> f Text) -> LogMessage -> f LogMessage -- | A lens for a user defined message id of a LogMessage lmMessageId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined of process id of a LogMessage lmProcessId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the Severity of a LogMessage lmSeverity :: Functor f => (Severity -> f Severity) -> LogMessage -> f LogMessage -- | A lens for the SrcLoc of a LogMessage lmSrcLoc :: Functor f => (Maybe SrcLoc -> f (Maybe SrcLoc)) -> LogMessage -> f LogMessage -- | A lens for the StructuredDataElement of a LogMessage lmStructuredData :: Functor f => ([StructuredDataElement] -> f [StructuredDataElement]) -> LogMessage -> f LogMessage -- | A lens for the ThreadId of a LogMessage The function -- setLogMessageThreadId can be used to set the field. lmThreadId :: Functor f => (Maybe ThreadId -> f (Maybe ThreadId)) -> LogMessage -> f LogMessage -- | A lens for the UTC time of a LogMessage The function -- setLogMessageTimestamp can be used to set the field. lmTimestamp :: Functor f => (Maybe UTCTime -> f (Maybe UTCTime)) -> LogMessage -> f LogMessage -- | Put the source location of the given callstack in lmSrcLoc setCallStack :: CallStack -> LogMessage -> LogMessage -- | Prefix the lmMessage. prefixLogMessagesWith :: Text -> LogMessage -> LogMessage -- | An IO action that sets the current UTC time in lmTimestamp. setLogMessageTimestamp :: LogMessage -> IO LogMessage -- | An IO action appends the the ThreadId of the calling process -- (see myThreadId) to lmMessage. setLogMessageThreadId :: LogMessage -> IO LogMessage -- | An IO action that sets the current hosts fully qualified hostname in -- lmHostname. setLogMessageHostname :: LogMessage -> IO LogMessage -- | Construct a LogMessage with errorSeverity errorMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with informationalSeverity infoMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with debugSeverity debugMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with errorSeverity errorMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with informationalSeverity infoMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with debugSeverity debugMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | All messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. allLogMessages :: LogPredicate -- | No messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. noLogMessages :: LogPredicate -- | Match LogMessages that have exactly the given severity. See -- lmSeverityIsAtLeast. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIs :: Severity -> LogPredicate -- | Match LogMessages that have the given severity or worse. -- See lmSeverityIs. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIsAtLeast :: Severity -> LogPredicate -- | Match LogMessages whose lmMessage starts with the given -- string. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmMessageStartsWith :: Text -> LogPredicate -- | Apply a LogPredicate based on the lmAppName and delegate -- to one of two LogPredicates. -- -- One useful application for this is to allow info and debug message -- from one application, e.g. the current application itself, while at -- the same time allowing only warning and error messages from third -- party libraries. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. discriminateByAppName :: Text -> LogPredicate -> LogPredicate -> LogPredicate -- | A rendering function for the lmTimestamp field. data LogMessageTimeRenderer -- | LogMessage rendering function type LogMessageRenderer a = LogMessage -> a -- | Make a LogMessageTimeRenderer using formatTime in the -- defaultLocale. mkLogMessageTimeRenderer :: String -> LogMessageTimeRenderer -- | Don't render the time stamp suppressTimestamp :: LogMessageTimeRenderer -- | Render the time stamp using "%h %d %H:%M:%S" rfc3164Timestamp :: LogMessageTimeRenderer -- | Render the time stamp to iso8601DateFormat (Just -- "%H:%M:%S%6QZ") rfc5424Timestamp :: LogMessageTimeRenderer -- | Render the time stamp like rfc5424Timestamp does, but omit the -- terminal Z character. rfc5424NoZTimestamp :: LogMessageTimeRenderer -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBody :: LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBodyNoLocation :: LogMessageRenderer Text -- | Print the body of a LogMessage with fix size fields (60) -- for the message itself and 30 characters for the location renderLogMessageBodyFixWidth :: LogMessageRenderer Text -- | Render a field of a LogMessage using the corresponsing lens. renderMaybeLogMessageLens :: Text -> Getter LogMessage (Maybe Text) -> LogMessageRenderer Text -- | Render the source location as: at filepath:linenumber. renderLogMessageSrcLoc :: LogMessageRenderer (Maybe Text) -- | Render the severity and facility as described in RFC-3164 -- -- Render e.g. as <192>. -- -- Useful as header for syslog compatible log output. renderSyslogSeverityAndFacility :: LogMessageRenderer Text -- | Render the LogMessage to contain the severity, message, -- message-id, pid. -- -- Omit hostname, PID and timestamp. -- -- Render the header using renderSyslogSeverity -- -- Useful for logging to devlog renderLogMessageSyslog :: LogMessageRenderer Text -- | Render a LogMessage human readable, for console logging renderLogMessageConsoleLog :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164. renderRFC3164 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use RFC5424 time stamps. renderRFC3164WithRFC5424Timestamps :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use the custom LogMessageTimeRenderer. renderRFC3164WithTimestamp :: LogMessageTimeRenderer -> LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBody. renderRFC5424 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424, -- like renderRFC5424 but suppress the source location -- information. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBodyNoLocation. renderRFC5424NoLocation :: LogMessageRenderer Text -- | Render the header and strucuted data of a LogMessage according -- to the rules in the RFC-5424, but do not render the lmMessage. renderRFC5424Header :: LogMessageRenderer Text -- | The instances of this class are the monads that define (side-) -- effect(s) of writting logs. class HandleLogWriter (writer :: Type -> Type) where { -- | The Effects required by the handleLogWriterEffect -- method. data family LogWriterM writer a; } -- | Run the side effect of a LogWriter in a compatible Eff. handleLogWriterEffect :: (HandleLogWriter writer, Member writer e) => LogWriterM writer () -> Eff e () -- | Write a message using the LogWriter found in the environment. -- -- The semantics of this function are a combination of -- runLogWriter and handleLogWriterEffect, with the -- LogWriter read from a LogWriterReader. liftWriteLogMessage :: (HandleLogWriter writer, SetMember LogWriterReader (LogWriterReader writer) e, Member writer e) => LogMessage -> Eff e () -- | A Reader specialized for LogWriters -- -- The existing Reader couldn't be used together with -- SetMember, so this lazy reader was written, specialized to -- reading LogWriter. data LogWriterReader h v -- | A function that takes a log message and returns an effect that -- logs the message. newtype LogWriter writerM MkLogWriter :: (LogMessage -> LogWriterM writerM ()) -> LogWriter writerM [runLogWriter] :: LogWriter writerM -> LogMessage -> LogWriterM writerM () -- | Provide the LogWriter -- -- Exposed for custom extensions, if in doubt use withLogging. runLogWriterReader :: LogWriter h -> Eff (LogWriterReader h : e) a -> Eff e a -- | Get the current LogWriter. askLogWriter :: SetMember LogWriterReader (LogWriterReader h) e => Eff e (LogWriter h) -- | Modify the current LogWriter. localLogWriterReader :: forall h e a. SetMember LogWriterReader (LogWriterReader h) e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | This LogWriter will discard all messages. -- -- NOTE: This is just an alias for def noOpLogWriter :: Applicative (LogWriterM m) => LogWriter m -- | A LogWriter that applies a predicate to the LogMessage -- and delegates to to the given writer of the predicate is satisfied. filteringLogWriter :: Monad (LogWriterM e) => LogPredicate -> LogWriter e -> LogWriter e -- | A LogWriter that applies a function to the LogMessage -- and delegates the result to to the given writer. mappingLogWriter :: (LogMessage -> LogMessage) -> LogWriter e -> LogWriter e -- | Like mappingLogWriter allow the function that changes the -- LogMessage to have effects. mappingLogWriterM :: Monad (LogWriterM e) => (LogMessage -> LogWriterM e LogMessage) -> LogWriter e -> LogWriter e -- | A constraint that required LogsTo IO e and -- Lifted IO e. type LogIo e = (LogsTo (Lift IO) e, Lifted IO e) -- | A constraint alias for effects that requires a LogWriterReader, -- as well as that the contained LogWriterReader has a -- HandleLogWriter instance. -- -- The requirements of this constraint are provided by: -- --
-- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Log a message. -- -- All logging goes through this function. -- -- This function is the only place where the LogPredicate is -- applied. -- -- Also, LogMessages are evaluated using deepseq, -- after they pass the LogPredicate. logMsg :: forall e. (HasCallStack, Member Logs e) => LogMessage -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity :: forall e. (HasCallStack, Member Logs e) => Severity -> Text -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity' :: forall e. (HasCallStack, Member Logs e) => Severity -> String -> Eff e () -- | Log a String as emergencySeverity. logEmergency :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a message with alertSeverity. logAlert :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a criticalSeverity message. logCritical :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a errorSeverity message. logError :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a warningSeverity message. logWarning :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a noticeSeverity message. logNotice :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a informationalSeverity message. logInfo :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a debugSeverity message. logDebug :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a String as emergencySeverity. logEmergency' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a message with alertSeverity. logAlert' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a criticalSeverity message. logCritical' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a errorSeverity message. logError' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a warningSeverity message. logWarning' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a noticeSeverity message. logNotice' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a informationalSeverity message. logInfo' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a debugSeverity message. logDebug' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Keep only those messages, for which a predicate holds. -- -- E.g. to keep only messages which begin with OMG: -- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Include LogMessages that match a LogPredicate. -- -- excludeLogMessages p allows log message to be logged if p -- m -- -- Although it is enough if the previous predicate holds. See -- excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate includeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Exclude LogMessages that match a LogPredicate. -- -- excludeLogMessages p discards logs if p m -- -- Also the previous predicate must also hold for a message to be logged. -- See excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate excludeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b -- | Change the current LogWriter. modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Modify the the LogMessages written in the given sub-expression. -- -- Note: This is equivalent to modifyLogWriter . -- mappingLogWriter censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a -- | Modify the the LogMessages written in the given sub-expression, -- as in censorLogs but with a effectful function. -- -- Note: This is equivalent to modifyLogWriter . -- mappingLogWriterM censorLogsM :: (LogsTo h e, Monad (LogWriterM h)) => (LogMessage -> LogWriterM h LogMessage) -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad (LogWriterM h)) => LogWriter h -> Eff e a -> Eff e a
-- | Each process is identified by a single process id, that stays constant
-- throughout the life cycle of a process. Also, message sending relies
-- on these values to address messages to processes.
newtype ProcessId
ProcessId :: Int -> ProcessId
[_fromProcessId] :: ProcessId -> Int
-- | A monitored process exited. This message is sent to a process by the
-- scheduler, when a process that was monitored died.
data ProcessDown
ProcessDown :: !MonitorReference -> !SomeExitReason -> !ProcessId -> ProcessDown
[downReference] :: ProcessDown -> !MonitorReference
[downReason] :: ProcessDown -> !SomeExitReason
[downProcess] :: ProcessDown -> !ProcessId
-- | A value that contains a unique reference of a process monitoring.
data MonitorReference
MonitorReference :: Int -> ProcessId -> MonitorReference
[monitorIndex] :: MonitorReference -> Int
[monitoredProcess] :: MonitorReference -> ProcessId
-- | An existential wrapper around Interrupt
data SomeExitReason
[SomeExitReason] :: Interrupt x -> SomeExitReason
-- | Exceptions containing Interrupts. See
-- handleInterrupts, exitOnInterrupt or
-- provideInterrupts
type Interrupts = Exc (Interrupt 'Recoverable)
-- | A constraint for an effect set that requires the presence of
-- SafeProcesses.
--
-- This constrains the effect list to look like this: [e1 ... eN,
-- Process [e(N+1) .. e(N+k)], e(N+1) .. e(N+k)]
--
-- It contrains e to support the (only) Process effect.
--
-- This is more relaxed that HasProcesses since it does not
-- require Interrupts.
type HasSafeProcesses e inner = (SetMember Process (Process inner) e)
-- | Cons Process onto a list of effects. This is called
-- SafeProcesses because the the actions cannot be interrupted
-- in.
type SafeProcesses r = Process r : r
-- | A constraint for an effect set that requires the presence of
-- Processes.
--
-- This constrains the effect list to look like this: [e1 ... eN,
-- Interrupts, Process [e(N+1) .. e(N+k)], e(N+1) ..
-- e(N+k)]
--
-- It contrains e beyond HasSafeProcesses to encompass
-- Interrupts.
type HasProcesses e inner = (HasSafeProcesses e inner, Member Interrupts e)
-- | This adds a layer of the Interrupts effect on top of
-- Processes
type Processes e = Interrupts : SafeProcesses e
-- | Interrupts which are Recoverable.
type RecoverableInterrupt = Interrupt 'Recoverable
-- | A sum-type with reasons for why a process operation, such as receiving
-- messages, is interrupted in the scheduling loop.
--
-- This includes errors, that can occur when scheduling messages.
data Interrupt (t :: ExitRecovery)
-- | A process has finished a unit of work and might exit or work on
-- something else. This is primarily used for interrupting infinite
-- server loops, allowing for additional cleanup work before exiting
-- (e.g. with ExitNormally)
[NormalExitRequested] :: Interrupt 'Recoverable
-- | A process that should be running was not running.
[OtherProcessNotRunning] :: ProcessId -> Interrupt 'Recoverable
-- | A Recoverable timeout has occurred.
[TimeoutInterrupt] :: String -> Interrupt 'Recoverable
-- | A linked process is down
[LinkedProcessCrashed] :: ProcessId -> Interrupt 'Recoverable
-- | An exit reason that has an error message and is Recoverable.
[ErrorInterrupt] :: String -> Interrupt 'Recoverable
-- | A process function returned or exited without any error.
[ExitNormally] :: Interrupt 'NoRecovery
-- | An error causes the process to exit immediately. For example an
-- unexpected runtime exception was thrown, i.e. an exception derived
-- from SomeException Or a Recoverable Interrupt was not
-- recovered.
[ExitUnhandledError] :: Text -> Interrupt 'NoRecovery
-- | A process shall exit immediately, without any cleanup was cancelled
-- (e.g. killed, in cancel)
[ExitProcessCancelled] :: Interrupt 'NoRecovery
-- | This value indicates whether a process exited in way consistent with
-- the planned behaviour or not.
data ExitSeverity
NormalExit :: ExitSeverity
Crash :: ExitSeverity
-- | This kind is used to indicate if a Interrupt can be treated
-- like a short interrupt which can be handled or ignored.
data ExitRecovery
Recoverable :: ExitRecovery
NoRecovery :: ExitRecovery
-- | A function that decided if the next message will be received by
-- ReceiveSelectedMessage. It conveniently is an instance of
-- Alternative so the message selector can be combined: > >
-- selectInt :: MessageSelector Int > selectInt = selectMessage >
-- > selectString :: MessageSelector String > selectString =
-- selectMessage > > selectIntOrString :: MessageSelector (Either
-- Int String) > selectIntOrString = > Left $
-- selectTimeout| Right $ selectString
data MessageSelector a
-- | Every Process action returns it's actual result wrapped in this
-- type. It will allow to signal errors as well as pass on normal results
-- such as incoming messages.
data ResumeProcess v
-- | The current operation of the process was interrupted with a
-- Interrupt. If isRecoverable holds for the given reason,
-- the process may choose to continue.
[Interrupted] :: Interrupt 'Recoverable -> ResumeProcess v
-- | The process may resume to do work, using the given result.
[ResumeWith] :: a -> ResumeProcess a
-- | Serialize a message into a StrictDynamic value to be
-- sent via sendAnyMessage.
--
-- This indirection allows, among other things, the composition of
-- Servers.
newtype Serializer message
MkSerializer :: (message -> StrictDynamic) -> Serializer message
[runSerializer] :: Serializer message -> message -> StrictDynamic
-- | Data flows between Processes via these messages.
--
-- This is just a newtype wrapper around Dynamic. The reason this
-- type exists is to force construction through the code in this module,
-- which always evaluates a message to normal form before
-- sending it to another process.
data StrictDynamic
-- | A multi-line text describing the current state of a process for
-- debugging purposes.
newtype ProcessDetails
MkProcessDetails :: Text -> ProcessDetails
[_fromProcessDetails] :: ProcessDetails -> Text
-- | A short title for a Process for logging purposes.
newtype ProcessTitle
MkProcessTitle :: Text -> ProcessTitle
[_fromProcessTitle] :: ProcessTitle -> Text
-- | The process effect is the basis for message passing concurrency. This
-- effect describes an interface for concurrent, communicating isolated
-- processes identified uniquely by a process-id.
--
-- Processes can raise exceptions that can be caught, exit gracefully or
-- with an error, or be killed by other processes, with the option of
-- ignoring the shutdown request.
--
-- Process Scheduling is implemented in different modules. All scheduler
-- implementations should follow some basic rules:
--
-- -- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () -- | Execute a and action and return the result; if the process is -- interrupted by an error or exception, or an explicit shutdown from -- another process, or through a crash of a linked process, i.e. whenever -- the exit reason satisfies isRecoverable, return the exit -- reason. executeAndResume :: forall q r v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r (Either (Interrupt 'Recoverable) v) -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrExit :: forall r q v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrThrow :: forall q r v. (HasProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Use executeAndResumeOrExit to execute YieldProcess. -- Refer to YieldProcess for more information. yieldProcess :: forall r q. (HasProcesses r q, HasCallStack) => Eff r () -- | Send a message to a process addressed by the ProcessId. See -- SendMessage. -- -- The message will be reduced to normal form (rnf) by/in the -- caller process. sendMessage :: forall r q o. (HasProcesses r q, HasCallStack, Typeable o, NFData o) => ProcessId -> o -> Eff r () -- | Send a Dynamic value to a process addressed by the -- ProcessId. See SendMessage. sendAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> StrictDynamic -> Eff r () -- | Exit a process addressed by the ProcessId. The process will -- exit, it might do some cleanup, but is ultimately unrecoverable. See -- SendShutdown. sendShutdown :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'NoRecovery -> Eff r () -- | Interrupts a process addressed by the ProcessId. The process -- might exit, or it may continue. | Like sendInterrupt, but also -- return True iff the process to exit exists. sendInterrupt :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'Recoverable -> Eff r () -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. If the new -- process is interrupted, the process will Shutdown with the -- Interrupt wrapped in interruptToExit. For specific use -- cases it might be better to use spawnRaw. spawn :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Like spawn but return (). spawn_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r () -- | Start a new process, and immediately link to it. spawnLink :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. The spawned -- process has only the raw SafeProcesses effects. For -- non-library code spawn might be better suited. spawnRaw :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r ProcessId -- | Like spawnRaw but return (). spawnRaw_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r () -- | Return True if the process is alive. isProcessAlive :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r Bool -- | Return the ProcessTitle, ProcessDetails and -- ProcessState, for the given process, if the process is alive. getProcessState :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r (Maybe (ProcessTitle, ProcessDetails, ProcessState)) -- | Replace the ProcessDetails of the process. updateProcessDetails :: forall r q. (HasCallStack, HasProcesses r q) => ProcessDetails -> Eff r () -- | Block until a message was received. See ReceiveSelectedMessage -- for more documentation. receiveAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => Eff r StrictDynamic -- | Block until a message was received, that is not Nothing after -- applying a callback to it. See ReceiveSelectedMessage for more -- documentation. receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, HasProcesses r q) => MessageSelector a -> Eff r a -- | Receive and cast the message to some Typeable instance. See -- ReceiveSelectedMessage for more documentation. This will wait -- for a message of the return type using receiveSelectedMessage receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, HasProcesses r q) => Eff r a -- | Remove and return all messages currently enqueued in the process -- message queue. flushMessages :: forall r q. (HasCallStack, HasProcesses r q) => Eff r [StrictDynamic] -- | Enter a loop to receive messages and pass them to a callback, until -- the function returns Just a result. Only the messages of the -- given type will be received. If the process is interrupted by an -- exception of by a SendShutdown from another process, with an -- exit reason that satisfies isRecoverable, then the callback -- will be invoked with Left Interrupt, otherwise -- the process will be exited with the same reason using -- exitBecause. See also ReceiveSelectedMessage for more -- documentation. receiveSelectedLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => MessageSelector a -> (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but not selective. See also -- selectAnyMessage, receiveSelectedLoop. receiveAnyLoop :: forall r q endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => (Either (Interrupt 'Recoverable) StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but refined to casting to a specific -- Typeable using selectMessage. receiveLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack, NFData a, Typeable a) => (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Returns the ProcessId of the current process. self :: (HasCallStack, HasSafeProcesses r q) => Eff r ProcessId -- | Generate a unique Int for the current process. makeReference :: (HasCallStack, HasProcesses r q) => Eff r Int -- | Monitor another process. When the monitored process exits a -- ProcessDown is sent to the calling process. The return value is -- a unique identifier for that monitor. There can be multiple monitors -- on the same process, and a message for each will be sent. If the -- process is already dead, the ProcessDown message will be sent -- immediately, without exit reason monitor :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r MonitorReference -- | Remove a monitor created with monitor. demonitor :: forall r q. (HasCallStack, HasProcesses r q) => MonitorReference -> Eff r () -- | monitor another process before while performing an action and -- demonitor afterwards. withMonitor :: (HasCallStack, HasProcesses r q) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a -- | A MessageSelector for receiving either a monitor of the given -- process or another message. receiveWithMonitor :: (HasCallStack, HasProcesses r q, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a) -- | Make an Interrupt for a ProcessDown message. -- -- For example: doSomething >>= either (interrupt . -- becauseProcessIsDown) return becauseProcessIsDown :: ProcessDown -> Interrupt 'Recoverable -- | A MessageSelector for the ProcessDown message of a -- specific process. -- -- The parameter is the value obtained by monitor. selectProcessDown :: MonitorReference -> MessageSelector ProcessDown -- | A MessageSelector for the ProcessDown message. of a -- specific process. -- -- In contrast to selectProcessDown this function matches the -- ProcessId. selectProcessDownByProcessId :: ProcessId -> MessageSelector ProcessDown -- | Connect the calling process to another process, such that if one of -- the processes crashes (i.e. isCrash returns True), the -- other is shutdown with the Interrupt -- LinkedProcessCrashed. linkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Unlink the calling process from the other process. unlinkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Exit the process with a Interrupt. exitBecause :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Interrupt 'NoRecovery -> Eff r a -- | Exit the process. exitNormally :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Eff r a -- | Exit the process with an error. exitWithError :: forall r q a. (HasCallStack, HasSafeProcesses r q) => String -> Eff r a -- | A ProcessId and a Serializer. EXPERIMENTAL -- -- See sendToReceiver. data Receiver a Receiver :: ProcessId -> (a -> out) -> Receiver a [_receiverPid] :: Receiver a -> ProcessId [_receiverSerializer] :: Receiver a -> a -> out fromProcessId :: Iso' ProcessId Int -- | Serialize and send a message to the process in a Receiver. -- -- EXPERIMENTAL sendToReceiver :: (NFData o, HasProcesses r q) => Receiver o -> o -> Eff r () receiverPid :: forall a_aHxu. Lens' (Receiver a_aHxu) ProcessId -- | A class for Pdu instances that embed other Pdu. -- -- This is a part of Embeds provide instances for your Pdus -- but in client code use the Embeds constraint. -- -- Instances of this class serve as proof to Embeds that a -- conversion into another Pdu actually exists. -- -- A Prism for the embedded Pdu is the center of this class -- -- Laws: embeddedPdu = prism' embedPdu fromPdu class (Typeable protocol, Typeable embeddedProtocol) => HasPduPrism protocol embeddedProtocol -- | A Prism for the embedded Pdus. embeddedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result) -- | Embed the Pdu value of an embedded protocol into the -- corresponding Pdu value. embedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu embeddedProtocol result -> Pdu protocol result -- | Examine a Pdu value from the outer protocol, and return it, if -- it embeds a Pdu of embedded protocol, otherwise return -- Nothing/ fromPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu protocol result -> Maybe (Pdu embeddedProtocol result) -- | This type function takes an Pdu and analysis the reply type, -- i.e. the Synchronicity and evaluates to either t for -- an Pdu x (Synchronous t) or to '()' for an Pdu x -- Asynchronous. type family ProtocolReply (s :: Synchronicity) -- | The (promoted) constructors of this type specify (at the type level) -- the reply behavior of a specific constructor of an Pdu -- instance. data Synchronicity -- | Specify that handling a request is a blocking operation with a -- specific return type, e.g. ('Synchronous (Either RentalError -- RentalId)) Synchronous :: Type -> Synchronicity -- | Non-blocking, asynchronous, request handling Asynchronous :: Synchronicity -- | A Constraint that bundles the requirements for the Pdu -- values of a protocol. -- -- This ensures that Pdus can be strictly and deeply evaluated and -- shown such that for example logging is possible. type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r), HasPdu p) -- | A set of constraints for types that can evaluated via NFData, -- compared via Ord and presented dynamically via Typeable, -- and represented both as values via Show. type Tangible i = (NFData i, Typeable i, Show i) -- | A constraint that requires that the outer Pdu has a -- clause to embed values from the inner Pdu. -- -- Also, this constraint requires a HasPduPrism instance, as a -- proof for a possible conversion of an embedded Pdu value into -- to the enclosing Pdu. -- -- This generates better compiler error messages, when an embedding of a -- Pdu into another. -- -- This is provided by HasPdu instances. The instances are -- required to provide a list of embedded Pdu values in -- EmbeddedPduList. -- -- Note that every type embeds itself, so Embeds x x always -- holds. type Embeds outer inner = (HasPduPrism outer inner, CheckEmbeds outer inner, HasPdu outer) -- | This type class and the associated data family defines the protocol -- data units (PDU) of a protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- instance Typeable r => HasPdu BookShop r where
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
-- deriving Typeable
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
class Typeable protocol => HasPdu (protocol :: Type) where {
-- | A type level list Protocol phantom types included in the associated
-- Pdu instance.
--
-- This is just a helper for better compiler error messages. It relies on
-- Embeds to add the constraint HasPduPrism.
type family EmbeddedPduList protocol :: [Type];
-- | The protocol data unit type for the given protocol.
data family Pdu protocol (reply :: Synchronicity);
type EmbeddedPduList protocol = '[];
}
-- | A server process for protocol.
--
-- Protocols are represented by phantom types, which are used in
-- different places to index type families and type class instances.
--
-- A Process can send and receive any messages. An Endpoint
-- wraps around a ProcessId and carries a phantom type to indicate
-- the kinds of messages accepted by the process.
--
-- As a metaphor, communication between processes can be thought of
-- waiting for and sending protocol data units belonging to some
-- protocol.
newtype Endpoint protocol
Endpoint :: ProcessId -> Endpoint protocol
[_fromEndpoint] :: Endpoint protocol -> ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | Convert an Endpoint to an endpoint for an embedded protocol.
--
-- See Embeds, fromEmbeddedEndpoint.
toEmbeddedEndpoint :: forall inner outer. Embeds outer inner => Endpoint outer -> Endpoint inner
-- | Convert an Endpoint to an endpoint for a server, that embeds
-- the protocol.
--
-- See Embeds, toEmbeddedEndpoint.
fromEmbeddedEndpoint :: forall outer inner. HasPduPrism outer inner => Endpoint inner -> Endpoint outer
fromEndpoint :: forall protocol_aTMy protocol_aUUM. Iso (Endpoint protocol_aTMy) (Endpoint protocol_aUUM) ProcessId ProcessId
-- | Target of a Call reply.
--
-- This combines a RequestOrigin with a Serializer for a
-- Reply using Arg. There are to smart constructors for
-- this type: replyTarget and embeddedReplyTarget.
--
-- Because of Arg the Eq and Ord instances are
-- implemented via the RequestOrigin instances.
newtype ReplyTarget p r
MkReplyTarget :: Arg (RequestOrigin p r) (Serializer (Reply p r)) -> ReplyTarget p r
-- | Wraps the source ProcessId and a unique identifier for a
-- Call.
data RequestOrigin (proto :: Type) reply
RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply
[_requestOriginPid] :: RequestOrigin reply -> !ProcessId
[_requestOriginCallRef] :: RequestOrigin reply -> !Int
-- | The wrapper around replies to Calls.
data Reply protocol reply
[Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply
-- | A wrapper sum type for calls and casts for the Pdus of a
-- protocol
data Request protocol
[Call] :: forall protocol reply. (Tangible reply, TangiblePdu protocol ( 'Synchronous reply)) => RequestOrigin protocol reply -> Pdu protocol ( 'Synchronous reply) -> Request protocol
[Cast] :: forall protocol. (TangiblePdu protocol 'Asynchronous, NFData (Pdu protocol 'Asynchronous)) => Pdu protocol 'Asynchronous -> Request protocol
-- | Create a new, unique RequestOrigin value for the current
-- process.
makeRequestOrigin :: (Typeable r, NFData r, HasProcesses e q0) => Eff e (RequestOrigin p r)
-- | Turn an RequestOrigin to an origin for an embedded request (See
-- Embeds).
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedReplySerializer.
toEmbeddedOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin outer reply -> RequestOrigin inner reply
-- | Turn an embedded RequestOrigin to a RequestOrigin
-- for the bigger request.
--
-- This is the inverse of toEmbeddedOrigin.
--
-- This function is strict in all parameters.
embedRequestOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin inner reply -> RequestOrigin outer reply
-- | Turn a Serializer for a Pdu instance that contains
-- embedded Pdu values into a Reply Serializer for
-- the embedded Pdu.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also toEmbeddedOrigin.
embedReplySerializer :: forall outer inner reply. Embeds outer inner => Serializer (Reply outer reply) -> Serializer (Reply inner reply)
-- | Answer a Call by sending the reply value to the client process.
--
-- The ProcessId, the RequestOrigin and the Reply
-- Serializer are stored in the ReplyTarget.
sendReply :: (HasProcesses eff q, Tangible reply, Typeable protocol) => ReplyTarget protocol reply -> reply -> Eff eff ()
-- | Smart constructor for a ReplyTarget.
--
-- To build a ReplyTarget for an Embeds instance use
-- embeddedReplyTarget.
replyTarget :: Serializer (Reply p reply) -> RequestOrigin p reply -> ReplyTarget p reply
-- | A simple Lens for the RequestOrigin of a
-- ReplyTarget.
replyTargetOrigin :: Lens' (ReplyTarget p reply) (RequestOrigin p reply)
-- | A simple Lens for the Reply Serializer of a
-- ReplyTarget.
replyTargetSerializer :: Lens' (ReplyTarget p reply) (Serializer (Reply p reply))
-- | Smart constructor for an embedded ReplyTarget.
--
-- This combines replyTarget and toEmbeddedReplyTarget.
embeddedReplyTarget :: Embeds outer inner => Serializer (Reply outer reply) -> RequestOrigin outer reply -> ReplyTarget inner reply
-- | Convert a ReplyTarget to be usable for embedded replies.
--
-- This combines a toEmbeddedOrigin with
-- embedReplySerializer to produce a ReplyTarget that can
-- be passed to functions defined soley on an embedded protocol.
toEmbeddedReplyTarget :: Embeds outer inner => ReplyTarget outer reply -> ReplyTarget inner reply
-- | A value to be sent when timer started with startTimer has
-- elapsed.
data TimerElapsed
-- | The reference to a timer started by startTimer, required to
-- stop a timer via cancelTimer.
data TimerReference
-- | A number of micro seconds.
data Timeout
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Nothing. This is based on
-- receiveSelectedAfter.
receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Left TimerElapsed. This
-- is based on selectTimerElapsed and startTimer.
receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
-- | Like receiveWithMonitor combined with
-- receiveSelectedAfter.
receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
-- | A MessageSelector matching TimerElapsed messages created
-- by startTimer.
selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed
-- | Send a message to a given process after waiting. The message is
-- created by applying the function parameter to the
-- TimerReference, such that the message can directly refer to the
-- timer.
sendAfter :: forall r q message. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
-- | Start a new timer, after the time has elapsed, TimerElapsed is
-- sent to calling process. The message also contains the
-- TimerReference returned by this function. Use
-- cancelTimer to cancel the timer. Use selectTimerElapsed
-- to receive the message using receiveSelectedMessage. To receive
-- messages with guarded with a timeout see receiveAfter.
startTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => Timeout -> Eff r TimerReference
-- | Cancel a timer started with startTimer.
cancelTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => TimerReference -> Eff r ()
-- | The reader effect for ProcessIds for Pdus, see
-- runEndpointReader
type EndpointReader o = Reader (Endpoint o)
-- | Instead of passing around a Endpoint value and passing to
-- functions like cast or call, a Endpoint can
-- provided by a Reader effect, if there is only a single
-- server for a given Pdu instance. This type alias is
-- convenience to express that an effect has Process and a reader
-- for a Endpoint.
type HasEndpointReader o r = (Typeable o, Member (EndpointReader o) r)
-- | Send a request Pdu that has no reply and return immediately.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Asynchronous. The operation never fails, if it is important
-- to know if the message was delivered, use call instead.
--
-- The message will be reduced to normal form (rnf) in the
-- caller process.
cast :: forall destination protocol r q. (HasCallStack, HasProcesses r q, HasPdu destination, HasPdu protocol, Tangible (Pdu destination 'Asynchronous), Embeds destination protocol) => Endpoint destination -> Pdu protocol 'Asynchronous -> Eff r ()
-- | Send a request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- Always prefer callWithTimeout over call
call :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Embeds destination protocol, HasCallStack) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Eff r result
-- | Send an request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- If the server that was called dies, this function interrupts the
-- process with ProcessDown. If the server takes longer to reply
-- than the given timeout, this function interrupts the process with
-- TimeoutInterrupt.
--
-- Always prefer this function over call
callWithTimeout :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack, Embeds destination protocol) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result
-- | Run a reader effect that contains the one server handling a
-- specific Pdu instance.
runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a
-- | Get the Endpoint registered with runEndpointReader.
askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o)
-- | Like call but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use callSingleton.
callEndpointReader :: forall reply o r q. (HasEndpointReader o r, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), HasProcesses r q, Embeds o o) => Pdu o ( 'Synchronous reply) -> Eff r reply
-- | Like cast but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use castSingleton.
castEndpointReader :: forall o r q. (HasEndpointReader o r, HasProcesses r q, Tangible (Pdu o 'Asynchronous), HasCallStack, HasPdu o, Embeds o o) => Pdu o 'Asynchronous -> Eff r ()
-- | Like callEndpointReader, uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- callEndpointReader.
callSingleton :: forall outer inner reply q e. (HasCallStack, Member (EndpointReader outer) e, Embeds outer inner, Embeds outer outer, HasProcesses e q, TangiblePdu outer ( 'Synchronous reply), TangiblePdu inner ( 'Synchronous reply), Tangible reply) => Pdu inner ( 'Synchronous reply) -> Eff e reply
-- | Like castEndpointReader, but uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- castEndpointReader.
castSingleton :: forall outer inner q e. (HasCallStack, Member (EndpointReader outer) e, Tangible (Pdu outer 'Asynchronous), HasProcesses e q, HasPdu outer, HasPdu inner, Embeds outer inner, Embeds outer outer) => Pdu inner 'Asynchronous -> Eff e ()
-- | Alias for the effect that contains the observers managed by
-- evalObserverRegistryState
type ObserverRegistryState event = State (ObserverRegistry event)
-- | A protocol for managing Observers, encompassing registration
-- and de-registration of Observers.
data ObserverRegistry (event :: Type)
MkObserverRegistry :: Map ProcessId (ObservationSink event) -> ObserverRegistry
[_observerRegistry] :: ObserverRegistry -> Map ProcessId (ObservationSink event)
-- | Convenience type alias.
type CanObserve eventSink event = (Tangible event, Embeds eventSink (Observer event), HasPdu eventSink)
-- | Convenience type alias.
type IsObservable eventSource event = (Tangible event, Embeds eventSource (ObserverRegistry event), HasPdu eventSource)
-- | The Information necessary to wrap an Observed event to a
-- process specific message, e.g. the embedded Observer Pdu
-- instance, and the MonitorReference of the destination process.
data ObservationSink event
-- | A protocol to communicate Observed events from a sources
-- to many sinks.
--
-- A sink is any process that serves a protocol with a Pdu
-- instance that embeds the Observer Pdu via an HasPduPrism
-- instance.
--
-- This type has dual use, for one it serves as type-index for
-- Pdu, i.e. HasPdu respectively, and secondly it contains
-- an ObservationSink and a MonitorReference.
--
-- The ObservationSink is used to serialize and send the
-- Observed events, while the ProcessId serves as key for
-- internal maps.
newtype Observer event
MkObserver :: Arg ProcessId (ObservationSink event) -> Observer event
-- | And an Observer to the set of recipients for all observations
-- reported by observerRegistryNotify. Note that the
-- observerRegistry are keyed by the observing process, i.e. a previous
-- entry for the process contained in the Observer is overwritten.
-- If you want multiple entries for a single process, just combine
-- several filter functions.
registerObserver :: forall event eventSink eventSource r q. (HasCallStack, HasProcesses r q, IsObservable eventSource event, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message
forgetObserver :: forall event eventSink eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), IsObservable eventSource event, CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message, use a raw ProcessId as
-- parameter.
forgetObserverUnsafe :: forall event eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), IsObservable eventSource event) => Endpoint eventSource -> ProcessId -> Eff r ()
-- | Provide the implementation for the ObserverRegistry Protocol,
-- this handled RegisterObserver and ForgetObserver
-- messages. It also adds the ObserverRegistryState constraint to
-- the effect list.
observerRegistryHandlePdu :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => Pdu (ObserverRegistry event) 'Asynchronous -> Eff r ()
-- | Remove the entry in the ObserverRegistry for the
-- ProcessId and return True if there was an entry,
-- False otherwise.
observerRegistryRemoveProcess :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => ProcessId -> Eff r Bool
-- | Keep track of registered Observers.
--
-- Handle the ObserverRegistryState effect, i.e. run
-- evalState on an emptyObserverRegistry.
evalObserverRegistryState :: HasCallStack => Eff (ObserverRegistryState event : r) a -> Eff r a
-- | The empty ObserverRegistryState
emptyObserverRegistry :: ObserverRegistry event
-- | Report an observation to all observers. The process needs to
-- evalObserverRegistryState and to
-- observerRegistryHandlePdu.
observerRegistryNotify :: forall event r q. (HasProcesses r q, Member (ObserverRegistryState event) r, Tangible event, HasCallStack) => event -> Eff r ()
-- | Alias for the Writer that contains the captured
-- LogMessages from CaptureLogs.
type CaptureLogWriter = Writer LogMessage
-- | A LogWriter monad that provides pure logging by capturing via
-- the Writer effect.
type CaptureLogs a = LogWriterM CaptureLogWriter a
-- | A LogWriter monad that provides pure logging by capturing via
-- the Writer effect.
--
-- See exampleLogCapture
captureLogWriter :: LogWriter CaptureLogWriter
-- | Run a Writer for LogMessages.
--
-- Such a Writer is needed to handle CaptureLogWriter
runCaptureLogWriter :: Eff (CaptureLogWriter : e) a -> Eff e (a, [LogMessage])
-- | The concrete list of Effects for logging with an IO based
-- LogWriter, and a LogWriterReader.
type LoggingAndIo = '[Logs, LogWriterReader (Lift IO), Lift IO]
-- | A LogWriter that uses an IO action to write the message.
--
-- This is just an alias for MkLogWriter but with IO as
-- parameter. This reduces the need to apply something to the extra type
-- argument @IO.
--
-- Example use cases for this function are the consoleLogWriter
-- and the ioHandleLogWriter.
mkLogWriterIO :: HasCallStack => (LogMessage -> IO ()) -> LogWriter (Lift IO)
-- | A LogWriter that renders LogMessages to strings via
-- renderLogMessageConsoleLog and prints them to an Handle
-- using hPutStrLn.
ioHandleLogWriter :: HasCallStack => Handle -> LogWriter (Lift IO)
-- | Enable logging to IO using the defaultIoLogWriter.
--
-- Example:
--
-- -- exampleWithIoLogging :: IO () -- exampleWithIoLogging = -- runLift -- $ withIoLogging debugTraceLogWriter -- "my-app" -- local7 -- (lmSeverityIsAtLeast informationalSeverity) -- $ logInfo "Oh, hi there" --withIoLogging :: Lifted IO e => LogWriter (Lift IO) -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Decorate an IO based LogWriter to fill out these fields in -- LogMessages: -- --
-- exampleWithFileLogging :: IO () -- exampleWithFileLogging = -- runLift -- $ withFileLogging "/var/log/my-app.log" "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withFileLogging :: (Lifted IO e, MonadBaseControl IO (Eff e)) => FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a file. -- -- If the file or its directory does not exist, it will be created. -- Example: -- --
-- exampleWithFileLogWriter :: IO () -- exampleWithFileLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withFileLogWriter "test.log" -- $ logInfo "Oh, hi there" --withFileLogWriter :: (LogIo e, MonadBaseControl IO (Eff e)) => FilePath -> Eff e b -> Eff e b -- | Enable logging via traceM using the debugTraceLogWriter, -- with some LogMessage fields preset as in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogging :: IO () -- exampleWithTraceLogging = -- runLift -- $ withTraceLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" --withTraceLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging via traceM using the debugTraceLogWriter. -- The logging monad type can be any type with a Monad -- instance. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogWriter :: IO () -- exampleWithTraceLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withTraceLogWriter -- $ logInfo "Oh, hi there" --withTraceLogWriter :: forall h e a. (Monad (LogWriterM h), LogsTo h e) => Eff e a -> Eff e a -- | Write LogMessages via traceM. debugTraceLogWriter :: forall h. Monad (LogWriterM h) => LogMessageRenderer Text -> LogWriter h -- | Enable logging to standard output using the -- consoleLogWriter, with some LogMessage fields preset as -- in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogging :: IO () -- exampleWithConsoleLogging = -- runLift -- $ withConsoleLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withConsoleLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to standard output using the -- consoleLogWriter. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogWriter :: IO () -- exampleWithConsoleLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withConsoleLogWriter -- $ logInfo "Oh, hi there" --withConsoleLogWriter :: LogIo e => Eff e a -> Eff e a -- | Write LogMessages to standard output, formatted with -- printLogMessage. -- -- It uses stdoutLogWriter with renderLogMessageConsoleLog. consoleLogWriter :: LogWriter (Lift IO) -- | A LogWriter that uses a LogMessageRenderer to render, -- and putStrLn to print it. stdoutLogWriter :: LogMessageRenderer Text -> LogWriter (Lift IO) -- | This is a wrapper around withAsyncLogWriter and -- withIoLogging. -- -- Example: -- --
-- exampleWithAsyncLogging :: IO () -- exampleWithAsyncLogging = -- runLift -- $ withAsyncLogWriter consoleLogWriter (1000::Int) "my-app" local0 allLogMessages -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogging :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter (Lift IO) -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Move the current LogWriter into its own thread. -- -- A bounded queue is used to forward logs to the process. -- -- If an exception is received, the logging process will be killed. -- -- Log messages are deeply evaluated before being sent to the logger -- process, to prevent that lazy evaluation leads to heavy work being -- done in the logger process instead of the caller process. -- -- Example: -- --
-- exampleAsyncLogWriter :: IO () -- exampleAsyncLogWriter = -- runLift -- $ withLogging consoleLogWriter -- $ withAsyncLogWriter (1000::Int) -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), Integral len) => len -> Eff e a -> Eff e a -- | Enable logging to a remote host via UDP, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleUdpRFC3164Logging withUDPLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => (LogMessage -> Text) -> String -> String -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a (remote-) host via UDP. -- -- See exampleUdpRFC3164Logging withUDPLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => (LogMessage -> Text) -> String -> String -> Eff e b -> Eff e b -- | Enable logging to a unix domain socket, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleDevLogSyslogLogging withUnixSocketLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => LogMessageRenderer Text -> FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a (remote-) host via UnixSocket. -- -- See exampleDevLogSyslogLogging withUnixSocketLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => LogMessageRenderer Text -> FilePath -> Eff e b -> Eff e b -- | A version of forever that hopefully tricks GHC into -- not creating a space leak. The intuition is, that we -- want to do something that is cheap, and hence should be -- recomputed instead of shared. foreverCheap :: Monad m => m a -> m () -- | A version of replicateM_ that hopefully tricks GHC into -- not creating a space leak. The intuition is, that we -- want to do something that is cheap, and hence should be -- recomputed instead of shared. replicateCheapM_ :: Monad m => Int -> m a -> m () -- | Run the Effects using a single threaded, coroutine based, -- scheduler from -- Control.Eff.Concurrent.Process.SingleThreadedScheduler. schedule :: HasCallStack => LogWriter (Lift IO) -> Eff Effects a -> IO (Either (Interrupt 'NoRecovery) a) -- | Execute a Process using scheduleM on top of Lift -- IO. All logging is written to the console using -- consoleLogWriter. -- -- To use another LogWriter use defaultMainWithLogWriter -- instead. defaultMain :: HasCallStack => Eff EffectsIo () -> IO () -- | Execute a Process using scheduleM on top of Lift -- IO. All logging is written using the given LogWriter. defaultMainWithLogWriter :: HasCallStack => LogWriter (Lift IO) -> Eff EffectsIo () -> IO () -- | The effect list for Process effects in the single threaded -- scheduler. -- -- See EffectsIo type Effects = EffectsIo -- | The effect list for Process effects in the single threaded -- scheduler. This is like SafeProcesses, no Interrupts are -- present. -- -- See SafeEffectsIo type SafeEffects = SafeEffectsIo -- | The effect list for the underlying scheduler. -- -- See BaseEffectsIo type BaseEffects = BaseEffectsIo -- | Constraint for the existence of the underlying scheduler effects. -- -- See HasBaseEffectsIo type HasBaseEffects e = HasBaseEffectsIo e -- | Concurrent, communicating processes, executed using a pure, -- single-threaded scheduler. -- -- This module re-exports most of the library. -- -- There are several scheduler implementations to choose from. -- -- This module re-exports the pure parts of -- Control.Eff.Concurrent.Process.SingleThreadedScheduler. -- -- To use another scheduler implementation, don't import this module, but -- instead import one of: -- -- module Control.Eff.Concurrent.Pure -- | An rfc 5424 facility newtype Facility Facility :: Int -> Facility [fromFacility] :: Facility -> Int -- | An rfc 5424 severity data Severity -- | Component of an RFC-5424 StructuredDataElement data SdParameter MkSdParameter :: !Text -> !Text -> SdParameter -- | RFC-5424 defines how structured data can be included in a log message. data StructuredDataElement SdElement :: !Text -> ![SdParameter] -> StructuredDataElement [_sdElementId] :: StructuredDataElement -> !Text [_sdElementParameters] :: StructuredDataElement -> ![SdParameter] -- | A message data type inspired by the RFC-5424 Syslog Protocol data LogMessage MkLogMessage :: !Facility -> !Severity -> Maybe UTCTime -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [StructuredDataElement] -> Maybe ThreadId -> Maybe SrcLoc -> Text -> LogMessage [_lmFacility] :: LogMessage -> !Facility [_lmSeverity] :: LogMessage -> !Severity [_lmTimestamp] :: LogMessage -> Maybe UTCTime [_lmHostname] :: LogMessage -> Maybe Text [_lmAppName] :: LogMessage -> Maybe Text [_lmProcessId] :: LogMessage -> Maybe Text [_lmMessageId] :: LogMessage -> Maybe Text [_lmStructuredData] :: LogMessage -> [StructuredDataElement] [_lmThreadId] :: LogMessage -> Maybe ThreadId [_lmSrcLoc] :: LogMessage -> Maybe SrcLoc [_lmMessage] :: LogMessage -> Text -- | Smart constructor for the RFC-5424 emergency LogMessage -- Severity. This corresponds to the severity value 0. See -- lmSeverity. emergencySeverity :: Severity -- | Smart constructor for the RFC-5424 alert LogMessage -- Severity. This corresponds to the severity value 1. See -- lmSeverity. alertSeverity :: Severity -- | Smart constructor for the RFC-5424 critical LogMessage -- Severity. This corresponds to the severity value 2. See -- lmSeverity. criticalSeverity :: Severity -- | Smart constructor for the RFC-5424 error LogMessage -- Severity. This corresponds to the severity value 3. See -- lmSeverity. errorSeverity :: Severity -- | Smart constructor for the RFC-5424 warning LogMessage -- Severity. This corresponds to the severity value 4. See -- lmSeverity. warningSeverity :: Severity -- | Smart constructor for the RFC-5424 notice LogMessage -- Severity. This corresponds to the severity value 5. See -- lmSeverity. noticeSeverity :: Severity -- | Smart constructor for the RFC-5424 informational -- LogMessage Severity. This corresponds to the severity -- value 6. See lmSeverity. informationalSeverity :: Severity -- | Smart constructor for the RFC-5424 debug LogMessage -- Severity. This corresponds to the severity value 7. See -- lmSeverity. debugSeverity :: Severity -- | Smart constructor for the RFC-5424 LogMessage facility -- kernelMessages. See lmFacility. kernelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- userLevelMessages. See lmFacility. userLevelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- mailSystem. See lmFacility. mailSystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- systemDaemons. See lmFacility. systemDaemons :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages4. See lmFacility. securityAuthorizationMessages4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- linePrinterSubsystem. See lmFacility. linePrinterSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- networkNewsSubsystem. See lmFacility. networkNewsSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- uucpSubsystem. See lmFacility. uucpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon. See lmFacility. clockDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages10. See lmFacility. securityAuthorizationMessages10 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ftpDaemon. See lmFacility. ftpDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ntpSubsystem. See lmFacility. ntpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAuditFacility. See lmFacility. logAuditFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAlertFacility. See lmFacility. logAlertFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon2. See lmFacility. clockDaemon2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local0. See lmFacility. local0 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local1. See lmFacility. local1 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local2. See lmFacility. local2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local3. See lmFacility. local3 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local4. See lmFacility. local4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local5. See lmFacility. local5 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local6. See lmFacility. local6 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local7. See lmFacility. local7 :: Facility -- | A lens for the key or ID of a group of RFC 5424 key-value pairs. sdElementId :: Functor f => (Text -> f Text) -> StructuredDataElement -> f StructuredDataElement -- | A lens for SdParameters sdElementParameters :: Functor f => ([SdParameter] -> f [SdParameter]) -> StructuredDataElement -> f StructuredDataElement -- | The filter predicate for message that shall be logged. -- -- See Control.Eff.Log#LogPredicate type LogPredicate = LogMessage -> Bool -- | Things that can become a LogMessage class ToLogMessage a -- | Convert the value to a LogMessage toLogMessage :: ToLogMessage a => a -> LogMessage -- | A lens for the RFC 5424 application name of a LogMessage -- -- One useful pattern for using this field, is to implement log filters -- that allow info and debug message from the application itself while -- only allowing warning and error messages from third party libraries: -- --
-- debugLogsForAppName myAppName lm = -- view lmAppName lm == Just myAppName || lmSeverityIsAtLeast warningSeverity lm ---- -- This concept is also implemented in discriminateByAppName. lmAppName :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the Facility of a LogMessage lmFacility :: Functor f => (Facility -> f Facility) -> LogMessage -> f LogMessage -- | A lens for the hostname of a LogMessage The function -- setLogMessageHostname can be used to set the field. lmHostname :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the user defined textual message of a LogMessage lmMessage :: Functor f => (Text -> f Text) -> LogMessage -> f LogMessage -- | A lens for a user defined message id of a LogMessage lmMessageId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined of process id of a LogMessage lmProcessId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the Severity of a LogMessage lmSeverity :: Functor f => (Severity -> f Severity) -> LogMessage -> f LogMessage -- | A lens for the SrcLoc of a LogMessage lmSrcLoc :: Functor f => (Maybe SrcLoc -> f (Maybe SrcLoc)) -> LogMessage -> f LogMessage -- | A lens for the StructuredDataElement of a LogMessage lmStructuredData :: Functor f => ([StructuredDataElement] -> f [StructuredDataElement]) -> LogMessage -> f LogMessage -- | A lens for the ThreadId of a LogMessage The function -- setLogMessageThreadId can be used to set the field. lmThreadId :: Functor f => (Maybe ThreadId -> f (Maybe ThreadId)) -> LogMessage -> f LogMessage -- | A lens for the UTC time of a LogMessage The function -- setLogMessageTimestamp can be used to set the field. lmTimestamp :: Functor f => (Maybe UTCTime -> f (Maybe UTCTime)) -> LogMessage -> f LogMessage -- | Put the source location of the given callstack in lmSrcLoc setCallStack :: CallStack -> LogMessage -> LogMessage -- | Prefix the lmMessage. prefixLogMessagesWith :: Text -> LogMessage -> LogMessage -- | An IO action that sets the current UTC time in lmTimestamp. setLogMessageTimestamp :: LogMessage -> IO LogMessage -- | An IO action appends the the ThreadId of the calling process -- (see myThreadId) to lmMessage. setLogMessageThreadId :: LogMessage -> IO LogMessage -- | An IO action that sets the current hosts fully qualified hostname in -- lmHostname. setLogMessageHostname :: LogMessage -> IO LogMessage -- | Construct a LogMessage with errorSeverity errorMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with informationalSeverity infoMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with debugSeverity debugMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with errorSeverity errorMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with informationalSeverity infoMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with debugSeverity debugMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | All messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. allLogMessages :: LogPredicate -- | No messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. noLogMessages :: LogPredicate -- | Match LogMessages that have exactly the given severity. See -- lmSeverityIsAtLeast. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIs :: Severity -> LogPredicate -- | Match LogMessages that have the given severity or worse. -- See lmSeverityIs. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIsAtLeast :: Severity -> LogPredicate -- | Match LogMessages whose lmMessage starts with the given -- string. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmMessageStartsWith :: Text -> LogPredicate -- | Apply a LogPredicate based on the lmAppName and delegate -- to one of two LogPredicates. -- -- One useful application for this is to allow info and debug message -- from one application, e.g. the current application itself, while at -- the same time allowing only warning and error messages from third -- party libraries. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. discriminateByAppName :: Text -> LogPredicate -> LogPredicate -> LogPredicate -- | A rendering function for the lmTimestamp field. data LogMessageTimeRenderer -- | LogMessage rendering function type LogMessageRenderer a = LogMessage -> a -- | Make a LogMessageTimeRenderer using formatTime in the -- defaultLocale. mkLogMessageTimeRenderer :: String -> LogMessageTimeRenderer -- | Don't render the time stamp suppressTimestamp :: LogMessageTimeRenderer -- | Render the time stamp using "%h %d %H:%M:%S" rfc3164Timestamp :: LogMessageTimeRenderer -- | Render the time stamp to iso8601DateFormat (Just -- "%H:%M:%S%6QZ") rfc5424Timestamp :: LogMessageTimeRenderer -- | Render the time stamp like rfc5424Timestamp does, but omit the -- terminal Z character. rfc5424NoZTimestamp :: LogMessageTimeRenderer -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBody :: LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBodyNoLocation :: LogMessageRenderer Text -- | Print the body of a LogMessage with fix size fields (60) -- for the message itself and 30 characters for the location renderLogMessageBodyFixWidth :: LogMessageRenderer Text -- | Render a field of a LogMessage using the corresponsing lens. renderMaybeLogMessageLens :: Text -> Getter LogMessage (Maybe Text) -> LogMessageRenderer Text -- | Render the source location as: at filepath:linenumber. renderLogMessageSrcLoc :: LogMessageRenderer (Maybe Text) -- | Render the severity and facility as described in RFC-3164 -- -- Render e.g. as <192>. -- -- Useful as header for syslog compatible log output. renderSyslogSeverityAndFacility :: LogMessageRenderer Text -- | Render the LogMessage to contain the severity, message, -- message-id, pid. -- -- Omit hostname, PID and timestamp. -- -- Render the header using renderSyslogSeverity -- -- Useful for logging to devlog renderLogMessageSyslog :: LogMessageRenderer Text -- | Render a LogMessage human readable, for console logging renderLogMessageConsoleLog :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164. renderRFC3164 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use RFC5424 time stamps. renderRFC3164WithRFC5424Timestamps :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use the custom LogMessageTimeRenderer. renderRFC3164WithTimestamp :: LogMessageTimeRenderer -> LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBody. renderRFC5424 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424, -- like renderRFC5424 but suppress the source location -- information. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBodyNoLocation. renderRFC5424NoLocation :: LogMessageRenderer Text -- | Render the header and strucuted data of a LogMessage according -- to the rules in the RFC-5424, but do not render the lmMessage. renderRFC5424Header :: LogMessageRenderer Text -- | The instances of this class are the monads that define (side-) -- effect(s) of writting logs. class HandleLogWriter (writer :: Type -> Type) where { -- | The Effects required by the handleLogWriterEffect -- method. data family LogWriterM writer a; } -- | Run the side effect of a LogWriter in a compatible Eff. handleLogWriterEffect :: (HandleLogWriter writer, Member writer e) => LogWriterM writer () -> Eff e () -- | Write a message using the LogWriter found in the environment. -- -- The semantics of this function are a combination of -- runLogWriter and handleLogWriterEffect, with the -- LogWriter read from a LogWriterReader. liftWriteLogMessage :: (HandleLogWriter writer, SetMember LogWriterReader (LogWriterReader writer) e, Member writer e) => LogMessage -> Eff e () -- | A Reader specialized for LogWriters -- -- The existing Reader couldn't be used together with -- SetMember, so this lazy reader was written, specialized to -- reading LogWriter. data LogWriterReader h v -- | A function that takes a log message and returns an effect that -- logs the message. newtype LogWriter writerM MkLogWriter :: (LogMessage -> LogWriterM writerM ()) -> LogWriter writerM [runLogWriter] :: LogWriter writerM -> LogMessage -> LogWriterM writerM () -- | Provide the LogWriter -- -- Exposed for custom extensions, if in doubt use withLogging. runLogWriterReader :: LogWriter h -> Eff (LogWriterReader h : e) a -> Eff e a -- | Get the current LogWriter. askLogWriter :: SetMember LogWriterReader (LogWriterReader h) e => Eff e (LogWriter h) -- | Modify the current LogWriter. localLogWriterReader :: forall h e a. SetMember LogWriterReader (LogWriterReader h) e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | This LogWriter will discard all messages. -- -- NOTE: This is just an alias for def noOpLogWriter :: Applicative (LogWriterM m) => LogWriter m -- | A LogWriter that applies a predicate to the LogMessage -- and delegates to to the given writer of the predicate is satisfied. filteringLogWriter :: Monad (LogWriterM e) => LogPredicate -> LogWriter e -> LogWriter e -- | A LogWriter that applies a function to the LogMessage -- and delegates the result to to the given writer. mappingLogWriter :: (LogMessage -> LogMessage) -> LogWriter e -> LogWriter e -- | Like mappingLogWriter allow the function that changes the -- LogMessage to have effects. mappingLogWriterM :: Monad (LogWriterM e) => (LogMessage -> LogWriterM e LogMessage) -> LogWriter e -> LogWriter e -- | A constraint that required LogsTo IO e and -- Lifted IO e. type LogIo e = (LogsTo (Lift IO) e, Lifted IO e) -- | A constraint alias for effects that requires a LogWriterReader, -- as well as that the contained LogWriterReader has a -- HandleLogWriter instance. -- -- The requirements of this constraint are provided by: -- --
-- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative (LogWriterM h), LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Log a message. -- -- All logging goes through this function. -- -- This function is the only place where the LogPredicate is -- applied. -- -- Also, LogMessages are evaluated using deepseq, -- after they pass the LogPredicate. logMsg :: forall e. (HasCallStack, Member Logs e) => LogMessage -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity :: forall e. (HasCallStack, Member Logs e) => Severity -> Text -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity' :: forall e. (HasCallStack, Member Logs e) => Severity -> String -> Eff e () -- | Log a String as emergencySeverity. logEmergency :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a message with alertSeverity. logAlert :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a criticalSeverity message. logCritical :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a errorSeverity message. logError :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a warningSeverity message. logWarning :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a noticeSeverity message. logNotice :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a informationalSeverity message. logInfo :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a debugSeverity message. logDebug :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a String as emergencySeverity. logEmergency' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a message with alertSeverity. logAlert' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a criticalSeverity message. logCritical' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a errorSeverity message. logError' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a warningSeverity message. logWarning' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a noticeSeverity message. logNotice' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a informationalSeverity message. logInfo' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a debugSeverity message. logDebug' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Keep only those messages, for which a predicate holds. -- -- E.g. to keep only messages which begin with OMG: -- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Include LogMessages that match a LogPredicate. -- -- excludeLogMessages p allows log message to be logged if p -- m -- -- Although it is enough if the previous predicate holds. See -- excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate includeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Exclude LogMessages that match a LogPredicate. -- -- excludeLogMessages p discards logs if p m -- -- Also the previous predicate must also hold for a message to be logged. -- See excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate excludeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b -- | Change the current LogWriter. modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Modify the the LogMessages written in the given sub-expression. -- -- Note: This is equivalent to modifyLogWriter . -- mappingLogWriter censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a -- | Modify the the LogMessages written in the given sub-expression, -- as in censorLogs but with a effectful function. -- -- Note: This is equivalent to modifyLogWriter . -- mappingLogWriterM censorLogsM :: (LogsTo h e, Monad (LogWriterM h)) => (LogMessage -> LogWriterM h LogMessage) -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad (LogWriterM h)) => LogWriter h -> Eff e a -> Eff e a
-- | Each process is identified by a single process id, that stays constant
-- throughout the life cycle of a process. Also, message sending relies
-- on these values to address messages to processes.
newtype ProcessId
ProcessId :: Int -> ProcessId
[_fromProcessId] :: ProcessId -> Int
-- | A monitored process exited. This message is sent to a process by the
-- scheduler, when a process that was monitored died.
data ProcessDown
ProcessDown :: !MonitorReference -> !SomeExitReason -> !ProcessId -> ProcessDown
[downReference] :: ProcessDown -> !MonitorReference
[downReason] :: ProcessDown -> !SomeExitReason
[downProcess] :: ProcessDown -> !ProcessId
-- | A value that contains a unique reference of a process monitoring.
data MonitorReference
MonitorReference :: Int -> ProcessId -> MonitorReference
[monitorIndex] :: MonitorReference -> Int
[monitoredProcess] :: MonitorReference -> ProcessId
-- | An existential wrapper around Interrupt
data SomeExitReason
[SomeExitReason] :: Interrupt x -> SomeExitReason
-- | Exceptions containing Interrupts. See
-- handleInterrupts, exitOnInterrupt or
-- provideInterrupts
type Interrupts = Exc (Interrupt 'Recoverable)
-- | A constraint for an effect set that requires the presence of
-- SafeProcesses.
--
-- This constrains the effect list to look like this: [e1 ... eN,
-- Process [e(N+1) .. e(N+k)], e(N+1) .. e(N+k)]
--
-- It contrains e to support the (only) Process effect.
--
-- This is more relaxed that HasProcesses since it does not
-- require Interrupts.
type HasSafeProcesses e inner = (SetMember Process (Process inner) e)
-- | Cons Process onto a list of effects. This is called
-- SafeProcesses because the the actions cannot be interrupted
-- in.
type SafeProcesses r = Process r : r
-- | A constraint for an effect set that requires the presence of
-- Processes.
--
-- This constrains the effect list to look like this: [e1 ... eN,
-- Interrupts, Process [e(N+1) .. e(N+k)], e(N+1) ..
-- e(N+k)]
--
-- It contrains e beyond HasSafeProcesses to encompass
-- Interrupts.
type HasProcesses e inner = (HasSafeProcesses e inner, Member Interrupts e)
-- | This adds a layer of the Interrupts effect on top of
-- Processes
type Processes e = Interrupts : SafeProcesses e
-- | Interrupts which are Recoverable.
type RecoverableInterrupt = Interrupt 'Recoverable
-- | A sum-type with reasons for why a process operation, such as receiving
-- messages, is interrupted in the scheduling loop.
--
-- This includes errors, that can occur when scheduling messages.
data Interrupt (t :: ExitRecovery)
-- | A process has finished a unit of work and might exit or work on
-- something else. This is primarily used for interrupting infinite
-- server loops, allowing for additional cleanup work before exiting
-- (e.g. with ExitNormally)
[NormalExitRequested] :: Interrupt 'Recoverable
-- | A process that should be running was not running.
[OtherProcessNotRunning] :: ProcessId -> Interrupt 'Recoverable
-- | A Recoverable timeout has occurred.
[TimeoutInterrupt] :: String -> Interrupt 'Recoverable
-- | A linked process is down
[LinkedProcessCrashed] :: ProcessId -> Interrupt 'Recoverable
-- | An exit reason that has an error message and is Recoverable.
[ErrorInterrupt] :: String -> Interrupt 'Recoverable
-- | A process function returned or exited without any error.
[ExitNormally] :: Interrupt 'NoRecovery
-- | An error causes the process to exit immediately. For example an
-- unexpected runtime exception was thrown, i.e. an exception derived
-- from SomeException Or a Recoverable Interrupt was not
-- recovered.
[ExitUnhandledError] :: Text -> Interrupt 'NoRecovery
-- | A process shall exit immediately, without any cleanup was cancelled
-- (e.g. killed, in cancel)
[ExitProcessCancelled] :: Interrupt 'NoRecovery
-- | This value indicates whether a process exited in way consistent with
-- the planned behaviour or not.
data ExitSeverity
NormalExit :: ExitSeverity
Crash :: ExitSeverity
-- | This kind is used to indicate if a Interrupt can be treated
-- like a short interrupt which can be handled or ignored.
data ExitRecovery
Recoverable :: ExitRecovery
NoRecovery :: ExitRecovery
-- | A function that decided if the next message will be received by
-- ReceiveSelectedMessage. It conveniently is an instance of
-- Alternative so the message selector can be combined: > >
-- selectInt :: MessageSelector Int > selectInt = selectMessage >
-- > selectString :: MessageSelector String > selectString =
-- selectMessage > > selectIntOrString :: MessageSelector (Either
-- Int String) > selectIntOrString = > Left $
-- selectTimeout| Right $ selectString
data MessageSelector a
-- | Every Process action returns it's actual result wrapped in this
-- type. It will allow to signal errors as well as pass on normal results
-- such as incoming messages.
data ResumeProcess v
-- | The current operation of the process was interrupted with a
-- Interrupt. If isRecoverable holds for the given reason,
-- the process may choose to continue.
[Interrupted] :: Interrupt 'Recoverable -> ResumeProcess v
-- | The process may resume to do work, using the given result.
[ResumeWith] :: a -> ResumeProcess a
-- | Serialize a message into a StrictDynamic value to be
-- sent via sendAnyMessage.
--
-- This indirection allows, among other things, the composition of
-- Servers.
newtype Serializer message
MkSerializer :: (message -> StrictDynamic) -> Serializer message
[runSerializer] :: Serializer message -> message -> StrictDynamic
-- | Data flows between Processes via these messages.
--
-- This is just a newtype wrapper around Dynamic. The reason this
-- type exists is to force construction through the code in this module,
-- which always evaluates a message to normal form before
-- sending it to another process.
data StrictDynamic
-- | A multi-line text describing the current state of a process for
-- debugging purposes.
newtype ProcessDetails
MkProcessDetails :: Text -> ProcessDetails
[_fromProcessDetails] :: ProcessDetails -> Text
-- | A short title for a Process for logging purposes.
newtype ProcessTitle
MkProcessTitle :: Text -> ProcessTitle
[_fromProcessTitle] :: ProcessTitle -> Text
-- | The process effect is the basis for message passing concurrency. This
-- effect describes an interface for concurrent, communicating isolated
-- processes identified uniquely by a process-id.
--
-- Processes can raise exceptions that can be caught, exit gracefully or
-- with an error, or be killed by other processes, with the option of
-- ignoring the shutdown request.
--
-- Process Scheduling is implemented in different modules. All scheduler
-- implementations should follow some basic rules:
--
-- -- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () -- | Execute a and action and return the result; if the process is -- interrupted by an error or exception, or an explicit shutdown from -- another process, or through a crash of a linked process, i.e. whenever -- the exit reason satisfies isRecoverable, return the exit -- reason. executeAndResume :: forall q r v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r (Either (Interrupt 'Recoverable) v) -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrExit :: forall r q v. (HasSafeProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrThrow :: forall q r v. (HasProcesses r q, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Use executeAndResumeOrExit to execute YieldProcess. -- Refer to YieldProcess for more information. yieldProcess :: forall r q. (HasProcesses r q, HasCallStack) => Eff r () -- | Send a message to a process addressed by the ProcessId. See -- SendMessage. -- -- The message will be reduced to normal form (rnf) by/in the -- caller process. sendMessage :: forall r q o. (HasProcesses r q, HasCallStack, Typeable o, NFData o) => ProcessId -> o -> Eff r () -- | Send a Dynamic value to a process addressed by the -- ProcessId. See SendMessage. sendAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> StrictDynamic -> Eff r () -- | Exit a process addressed by the ProcessId. The process will -- exit, it might do some cleanup, but is ultimately unrecoverable. See -- SendShutdown. sendShutdown :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'NoRecovery -> Eff r () -- | Interrupts a process addressed by the ProcessId. The process -- might exit, or it may continue. | Like sendInterrupt, but also -- return True iff the process to exit exists. sendInterrupt :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Interrupt 'Recoverable -> Eff r () -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. If the new -- process is interrupted, the process will Shutdown with the -- Interrupt wrapped in interruptToExit. For specific use -- cases it might be better to use spawnRaw. spawn :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Like spawn but return (). spawn_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r () -- | Start a new process, and immediately link to it. spawnLink :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (Processes q) () -> Eff r ProcessId -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. The spawned -- process has only the raw SafeProcesses effects. For -- non-library code spawn might be better suited. spawnRaw :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r ProcessId -- | Like spawnRaw but return (). spawnRaw_ :: forall r q. (HasCallStack, HasProcesses r q) => ProcessTitle -> Eff (SafeProcesses q) () -> Eff r () -- | Return True if the process is alive. isProcessAlive :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r Bool -- | Return the ProcessTitle, ProcessDetails and -- ProcessState, for the given process, if the process is alive. getProcessState :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r (Maybe (ProcessTitle, ProcessDetails, ProcessState)) -- | Replace the ProcessDetails of the process. updateProcessDetails :: forall r q. (HasCallStack, HasProcesses r q) => ProcessDetails -> Eff r () -- | Block until a message was received. See ReceiveSelectedMessage -- for more documentation. receiveAnyMessage :: forall r q. (HasCallStack, HasProcesses r q) => Eff r StrictDynamic -- | Block until a message was received, that is not Nothing after -- applying a callback to it. See ReceiveSelectedMessage for more -- documentation. receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, HasProcesses r q) => MessageSelector a -> Eff r a -- | Receive and cast the message to some Typeable instance. See -- ReceiveSelectedMessage for more documentation. This will wait -- for a message of the return type using receiveSelectedMessage receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, HasProcesses r q) => Eff r a -- | Remove and return all messages currently enqueued in the process -- message queue. flushMessages :: forall r q. (HasCallStack, HasProcesses r q) => Eff r [StrictDynamic] -- | Enter a loop to receive messages and pass them to a callback, until -- the function returns Just a result. Only the messages of the -- given type will be received. If the process is interrupted by an -- exception of by a SendShutdown from another process, with an -- exit reason that satisfies isRecoverable, then the callback -- will be invoked with Left Interrupt, otherwise -- the process will be exited with the same reason using -- exitBecause. See also ReceiveSelectedMessage for more -- documentation. receiveSelectedLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => MessageSelector a -> (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but not selective. See also -- selectAnyMessage, receiveSelectedLoop. receiveAnyLoop :: forall r q endOfLoopResult. (HasSafeProcesses r q, HasCallStack) => (Either (Interrupt 'Recoverable) StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but refined to casting to a specific -- Typeable using selectMessage. receiveLoop :: forall r q a endOfLoopResult. (HasSafeProcesses r q, HasCallStack, NFData a, Typeable a) => (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Returns the ProcessId of the current process. self :: (HasCallStack, HasSafeProcesses r q) => Eff r ProcessId -- | Generate a unique Int for the current process. makeReference :: (HasCallStack, HasProcesses r q) => Eff r Int -- | Monitor another process. When the monitored process exits a -- ProcessDown is sent to the calling process. The return value is -- a unique identifier for that monitor. There can be multiple monitors -- on the same process, and a message for each will be sent. If the -- process is already dead, the ProcessDown message will be sent -- immediately, without exit reason monitor :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r MonitorReference -- | Remove a monitor created with monitor. demonitor :: forall r q. (HasCallStack, HasProcesses r q) => MonitorReference -> Eff r () -- | monitor another process before while performing an action and -- demonitor afterwards. withMonitor :: (HasCallStack, HasProcesses r q) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a -- | A MessageSelector for receiving either a monitor of the given -- process or another message. receiveWithMonitor :: (HasCallStack, HasProcesses r q, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a) -- | Make an Interrupt for a ProcessDown message. -- -- For example: doSomething >>= either (interrupt . -- becauseProcessIsDown) return becauseProcessIsDown :: ProcessDown -> Interrupt 'Recoverable -- | A MessageSelector for the ProcessDown message of a -- specific process. -- -- The parameter is the value obtained by monitor. selectProcessDown :: MonitorReference -> MessageSelector ProcessDown -- | A MessageSelector for the ProcessDown message. of a -- specific process. -- -- In contrast to selectProcessDown this function matches the -- ProcessId. selectProcessDownByProcessId :: ProcessId -> MessageSelector ProcessDown -- | Connect the calling process to another process, such that if one of -- the processes crashes (i.e. isCrash returns True), the -- other is shutdown with the Interrupt -- LinkedProcessCrashed. linkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Unlink the calling process from the other process. unlinkProcess :: forall r q. (HasCallStack, HasProcesses r q) => ProcessId -> Eff r () -- | Exit the process with a Interrupt. exitBecause :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Interrupt 'NoRecovery -> Eff r a -- | Exit the process. exitNormally :: forall r q a. (HasCallStack, HasSafeProcesses r q) => Eff r a -- | Exit the process with an error. exitWithError :: forall r q a. (HasCallStack, HasSafeProcesses r q) => String -> Eff r a -- | A ProcessId and a Serializer. EXPERIMENTAL -- -- See sendToReceiver. data Receiver a Receiver :: ProcessId -> (a -> out) -> Receiver a [_receiverPid] :: Receiver a -> ProcessId [_receiverSerializer] :: Receiver a -> a -> out fromProcessId :: Iso' ProcessId Int -- | Serialize and send a message to the process in a Receiver. -- -- EXPERIMENTAL sendToReceiver :: (NFData o, HasProcesses r q) => Receiver o -> o -> Eff r () receiverPid :: forall a_aHxu. Lens' (Receiver a_aHxu) ProcessId -- | A class for Pdu instances that embed other Pdu. -- -- This is a part of Embeds provide instances for your Pdus -- but in client code use the Embeds constraint. -- -- Instances of this class serve as proof to Embeds that a -- conversion into another Pdu actually exists. -- -- A Prism for the embedded Pdu is the center of this class -- -- Laws: embeddedPdu = prism' embedPdu fromPdu class (Typeable protocol, Typeable embeddedProtocol) => HasPduPrism protocol embeddedProtocol -- | A Prism for the embedded Pdus. embeddedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result) -- | Embed the Pdu value of an embedded protocol into the -- corresponding Pdu value. embedPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu embeddedProtocol result -> Pdu protocol result -- | Examine a Pdu value from the outer protocol, and return it, if -- it embeds a Pdu of embedded protocol, otherwise return -- Nothing/ fromPdu :: forall (result :: Synchronicity). HasPduPrism protocol embeddedProtocol => Pdu protocol result -> Maybe (Pdu embeddedProtocol result) -- | This type function takes an Pdu and analysis the reply type, -- i.e. the Synchronicity and evaluates to either t for -- an Pdu x (Synchronous t) or to '()' for an Pdu x -- Asynchronous. type family ProtocolReply (s :: Synchronicity) -- | The (promoted) constructors of this type specify (at the type level) -- the reply behavior of a specific constructor of an Pdu -- instance. data Synchronicity -- | Specify that handling a request is a blocking operation with a -- specific return type, e.g. ('Synchronous (Either RentalError -- RentalId)) Synchronous :: Type -> Synchronicity -- | Non-blocking, asynchronous, request handling Asynchronous :: Synchronicity -- | A Constraint that bundles the requirements for the Pdu -- values of a protocol. -- -- This ensures that Pdus can be strictly and deeply evaluated and -- shown such that for example logging is possible. type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r), HasPdu p) -- | A set of constraints for types that can evaluated via NFData, -- compared via Ord and presented dynamically via Typeable, -- and represented both as values via Show. type Tangible i = (NFData i, Typeable i, Show i) -- | A constraint that requires that the outer Pdu has a -- clause to embed values from the inner Pdu. -- -- Also, this constraint requires a HasPduPrism instance, as a -- proof for a possible conversion of an embedded Pdu value into -- to the enclosing Pdu. -- -- This generates better compiler error messages, when an embedding of a -- Pdu into another. -- -- This is provided by HasPdu instances. The instances are -- required to provide a list of embedded Pdu values in -- EmbeddedPduList. -- -- Note that every type embeds itself, so Embeds x x always -- holds. type Embeds outer inner = (HasPduPrism outer inner, CheckEmbeds outer inner, HasPdu outer) -- | This type class and the associated data family defines the protocol -- data units (PDU) of a protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- instance Typeable r => HasPdu BookShop r where
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
-- deriving Typeable
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
class Typeable protocol => HasPdu (protocol :: Type) where {
-- | A type level list Protocol phantom types included in the associated
-- Pdu instance.
--
-- This is just a helper for better compiler error messages. It relies on
-- Embeds to add the constraint HasPduPrism.
type family EmbeddedPduList protocol :: [Type];
-- | The protocol data unit type for the given protocol.
data family Pdu protocol (reply :: Synchronicity);
type EmbeddedPduList protocol = '[];
}
-- | A server process for protocol.
--
-- Protocols are represented by phantom types, which are used in
-- different places to index type families and type class instances.
--
-- A Process can send and receive any messages. An Endpoint
-- wraps around a ProcessId and carries a phantom type to indicate
-- the kinds of messages accepted by the process.
--
-- As a metaphor, communication between processes can be thought of
-- waiting for and sending protocol data units belonging to some
-- protocol.
newtype Endpoint protocol
Endpoint :: ProcessId -> Endpoint protocol
[_fromEndpoint] :: Endpoint protocol -> ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | Convert an Endpoint to an endpoint for an embedded protocol.
--
-- See Embeds, fromEmbeddedEndpoint.
toEmbeddedEndpoint :: forall inner outer. Embeds outer inner => Endpoint outer -> Endpoint inner
-- | Convert an Endpoint to an endpoint for a server, that embeds
-- the protocol.
--
-- See Embeds, toEmbeddedEndpoint.
fromEmbeddedEndpoint :: forall outer inner. HasPduPrism outer inner => Endpoint inner -> Endpoint outer
fromEndpoint :: forall protocol_aTMy protocol_aUUM. Iso (Endpoint protocol_aTMy) (Endpoint protocol_aUUM) ProcessId ProcessId
-- | Target of a Call reply.
--
-- This combines a RequestOrigin with a Serializer for a
-- Reply using Arg. There are to smart constructors for
-- this type: replyTarget and embeddedReplyTarget.
--
-- Because of Arg the Eq and Ord instances are
-- implemented via the RequestOrigin instances.
newtype ReplyTarget p r
MkReplyTarget :: Arg (RequestOrigin p r) (Serializer (Reply p r)) -> ReplyTarget p r
-- | Wraps the source ProcessId and a unique identifier for a
-- Call.
data RequestOrigin (proto :: Type) reply
RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply
[_requestOriginPid] :: RequestOrigin reply -> !ProcessId
[_requestOriginCallRef] :: RequestOrigin reply -> !Int
-- | The wrapper around replies to Calls.
data Reply protocol reply
[Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply
-- | A wrapper sum type for calls and casts for the Pdus of a
-- protocol
data Request protocol
[Call] :: forall protocol reply. (Tangible reply, TangiblePdu protocol ( 'Synchronous reply)) => RequestOrigin protocol reply -> Pdu protocol ( 'Synchronous reply) -> Request protocol
[Cast] :: forall protocol. (TangiblePdu protocol 'Asynchronous, NFData (Pdu protocol 'Asynchronous)) => Pdu protocol 'Asynchronous -> Request protocol
-- | Create a new, unique RequestOrigin value for the current
-- process.
makeRequestOrigin :: (Typeable r, NFData r, HasProcesses e q0) => Eff e (RequestOrigin p r)
-- | Turn an RequestOrigin to an origin for an embedded request (See
-- Embeds).
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedReplySerializer.
toEmbeddedOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin outer reply -> RequestOrigin inner reply
-- | Turn an embedded RequestOrigin to a RequestOrigin
-- for the bigger request.
--
-- This is the inverse of toEmbeddedOrigin.
--
-- This function is strict in all parameters.
embedRequestOrigin :: forall outer inner reply. Embeds outer inner => RequestOrigin inner reply -> RequestOrigin outer reply
-- | Turn a Serializer for a Pdu instance that contains
-- embedded Pdu values into a Reply Serializer for
-- the embedded Pdu.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also toEmbeddedOrigin.
embedReplySerializer :: forall outer inner reply. Embeds outer inner => Serializer (Reply outer reply) -> Serializer (Reply inner reply)
-- | Answer a Call by sending the reply value to the client process.
--
-- The ProcessId, the RequestOrigin and the Reply
-- Serializer are stored in the ReplyTarget.
sendReply :: (HasProcesses eff q, Tangible reply, Typeable protocol) => ReplyTarget protocol reply -> reply -> Eff eff ()
-- | Smart constructor for a ReplyTarget.
--
-- To build a ReplyTarget for an Embeds instance use
-- embeddedReplyTarget.
replyTarget :: Serializer (Reply p reply) -> RequestOrigin p reply -> ReplyTarget p reply
-- | A simple Lens for the RequestOrigin of a
-- ReplyTarget.
replyTargetOrigin :: Lens' (ReplyTarget p reply) (RequestOrigin p reply)
-- | A simple Lens for the Reply Serializer of a
-- ReplyTarget.
replyTargetSerializer :: Lens' (ReplyTarget p reply) (Serializer (Reply p reply))
-- | Smart constructor for an embedded ReplyTarget.
--
-- This combines replyTarget and toEmbeddedReplyTarget.
embeddedReplyTarget :: Embeds outer inner => Serializer (Reply outer reply) -> RequestOrigin outer reply -> ReplyTarget inner reply
-- | Convert a ReplyTarget to be usable for embedded replies.
--
-- This combines a toEmbeddedOrigin with
-- embedReplySerializer to produce a ReplyTarget that can
-- be passed to functions defined soley on an embedded protocol.
toEmbeddedReplyTarget :: Embeds outer inner => ReplyTarget outer reply -> ReplyTarget inner reply
-- | A value to be sent when timer started with startTimer has
-- elapsed.
data TimerElapsed
-- | The reference to a timer started by startTimer, required to
-- stop a timer via cancelTimer.
data TimerReference
-- | A number of micro seconds.
data Timeout
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Nothing. This is based on
-- receiveSelectedAfter.
receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Left TimerElapsed. This
-- is based on selectTimerElapsed and startTimer.
receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
-- | Like receiveWithMonitor combined with
-- receiveSelectedAfter.
receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, HasProcesses r q, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
-- | A MessageSelector matching TimerElapsed messages created
-- by startTimer.
selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed
-- | Send a message to a given process after waiting. The message is
-- created by applying the function parameter to the
-- TimerReference, such that the message can directly refer to the
-- timer.
sendAfter :: forall r q message. (Lifted IO q, HasCallStack, HasProcesses r q, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
-- | Start a new timer, after the time has elapsed, TimerElapsed is
-- sent to calling process. The message also contains the
-- TimerReference returned by this function. Use
-- cancelTimer to cancel the timer. Use selectTimerElapsed
-- to receive the message using receiveSelectedMessage. To receive
-- messages with guarded with a timeout see receiveAfter.
startTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => Timeout -> Eff r TimerReference
-- | Cancel a timer started with startTimer.
cancelTimer :: forall r q. (Lifted IO q, HasCallStack, HasProcesses r q) => TimerReference -> Eff r ()
-- | The reader effect for ProcessIds for Pdus, see
-- runEndpointReader
type EndpointReader o = Reader (Endpoint o)
-- | Instead of passing around a Endpoint value and passing to
-- functions like cast or call, a Endpoint can
-- provided by a Reader effect, if there is only a single
-- server for a given Pdu instance. This type alias is
-- convenience to express that an effect has Process and a reader
-- for a Endpoint.
type HasEndpointReader o r = (Typeable o, Member (EndpointReader o) r)
-- | Send a request Pdu that has no reply and return immediately.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Asynchronous. The operation never fails, if it is important
-- to know if the message was delivered, use call instead.
--
-- The message will be reduced to normal form (rnf) in the
-- caller process.
cast :: forall destination protocol r q. (HasCallStack, HasProcesses r q, HasPdu destination, HasPdu protocol, Tangible (Pdu destination 'Asynchronous), Embeds destination protocol) => Endpoint destination -> Pdu protocol 'Asynchronous -> Eff r ()
-- | Send a request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- Always prefer callWithTimeout over call
call :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Embeds destination protocol, HasCallStack) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Eff r result
-- | Send an request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- If the server that was called dies, this function interrupts the
-- process with ProcessDown. If the server takes longer to reply
-- than the given timeout, this function interrupts the process with
-- TimeoutInterrupt.
--
-- Always prefer this function over call
callWithTimeout :: forall result destination protocol r q. (HasProcesses r q, TangiblePdu destination ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack, Embeds destination protocol) => Endpoint destination -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result
-- | Run a reader effect that contains the one server handling a
-- specific Pdu instance.
runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a
-- | Get the Endpoint registered with runEndpointReader.
askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o)
-- | Like call but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use callSingleton.
callEndpointReader :: forall reply o r q. (HasEndpointReader o r, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), HasProcesses r q, Embeds o o) => Pdu o ( 'Synchronous reply) -> Eff r reply
-- | Like cast but take the Endpoint from the reader provided
-- by runEndpointReader.
--
-- When working with an embedded Pdu use castSingleton.
castEndpointReader :: forall o r q. (HasEndpointReader o r, HasProcesses r q, Tangible (Pdu o 'Asynchronous), HasCallStack, HasPdu o, Embeds o o) => Pdu o 'Asynchronous -> Eff r ()
-- | Like callEndpointReader, uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- callEndpointReader.
callSingleton :: forall outer inner reply q e. (HasCallStack, Member (EndpointReader outer) e, Embeds outer inner, Embeds outer outer, HasProcesses e q, TangiblePdu outer ( 'Synchronous reply), TangiblePdu inner ( 'Synchronous reply), Tangible reply) => Pdu inner ( 'Synchronous reply) -> Eff e reply
-- | Like castEndpointReader, but uses embedPdu to embed the
-- value.
--
-- This function makes use of AmbigousTypes and TypeApplications.
--
-- When not working with an embedded Pdu use
-- castEndpointReader.
castSingleton :: forall outer inner q e. (HasCallStack, Member (EndpointReader outer) e, Tangible (Pdu outer 'Asynchronous), HasProcesses e q, HasPdu outer, HasPdu inner, Embeds outer inner, Embeds outer outer) => Pdu inner 'Asynchronous -> Eff e ()
-- | Alias for the effect that contains the observers managed by
-- evalObserverRegistryState
type ObserverRegistryState event = State (ObserverRegistry event)
-- | A protocol for managing Observers, encompassing registration
-- and de-registration of Observers.
data ObserverRegistry (event :: Type)
MkObserverRegistry :: Map ProcessId (ObservationSink event) -> ObserverRegistry
[_observerRegistry] :: ObserverRegistry -> Map ProcessId (ObservationSink event)
-- | Convenience type alias.
type CanObserve eventSink event = (Tangible event, Embeds eventSink (Observer event), HasPdu eventSink)
-- | Convenience type alias.
type IsObservable eventSource event = (Tangible event, Embeds eventSource (ObserverRegistry event), HasPdu eventSource)
-- | The Information necessary to wrap an Observed event to a
-- process specific message, e.g. the embedded Observer Pdu
-- instance, and the MonitorReference of the destination process.
data ObservationSink event
-- | A protocol to communicate Observed events from a sources
-- to many sinks.
--
-- A sink is any process that serves a protocol with a Pdu
-- instance that embeds the Observer Pdu via an HasPduPrism
-- instance.
--
-- This type has dual use, for one it serves as type-index for
-- Pdu, i.e. HasPdu respectively, and secondly it contains
-- an ObservationSink and a MonitorReference.
--
-- The ObservationSink is used to serialize and send the
-- Observed events, while the ProcessId serves as key for
-- internal maps.
newtype Observer event
MkObserver :: Arg ProcessId (ObservationSink event) -> Observer event
-- | And an Observer to the set of recipients for all observations
-- reported by observerRegistryNotify. Note that the
-- observerRegistry are keyed by the observing process, i.e. a previous
-- entry for the process contained in the Observer is overwritten.
-- If you want multiple entries for a single process, just combine
-- several filter functions.
registerObserver :: forall event eventSink eventSource r q. (HasCallStack, HasProcesses r q, IsObservable eventSource event, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message
forgetObserver :: forall event eventSink eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), Tangible (Pdu eventSink 'Asynchronous), IsObservable eventSource event, CanObserve eventSink event) => Endpoint eventSource -> Endpoint eventSink -> Eff r ()
-- | Send the ForgetObserver message, use a raw ProcessId as
-- parameter.
forgetObserverUnsafe :: forall event eventSource r q. (HasProcesses r q, HasCallStack, Tangible (Pdu eventSource 'Asynchronous), IsObservable eventSource event) => Endpoint eventSource -> ProcessId -> Eff r ()
-- | Provide the implementation for the ObserverRegistry Protocol,
-- this handled RegisterObserver and ForgetObserver
-- messages. It also adds the ObserverRegistryState constraint to
-- the effect list.
observerRegistryHandlePdu :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => Pdu (ObserverRegistry event) 'Asynchronous -> Eff r ()
-- | Remove the entry in the ObserverRegistry for the
-- ProcessId and return True if there was an entry,
-- False otherwise.
observerRegistryRemoveProcess :: forall event q r. (HasCallStack, Typeable event, HasProcesses r q, Member (ObserverRegistryState event) r, Member Logs r) => ProcessId -> Eff r Bool
-- | Keep track of registered Observers.
--
-- Handle the ObserverRegistryState effect, i.e. run
-- evalState on an emptyObserverRegistry.
evalObserverRegistryState :: HasCallStack => Eff (ObserverRegistryState event : r) a -> Eff r a
-- | The empty ObserverRegistryState
emptyObserverRegistry :: ObserverRegistry event
-- | Report an observation to all observers. The process needs to
-- evalObserverRegistryState and to
-- observerRegistryHandlePdu.
observerRegistryNotify :: forall event r q. (HasProcesses r q, Member (ObserverRegistryState event) r, Tangible event, HasCallStack) => event -> Eff r ()
-- | Alias for the Writer that contains the captured
-- LogMessages from CaptureLogs.
type CaptureLogWriter = Writer LogMessage
-- | A LogWriter monad that provides pure logging by capturing via
-- the Writer effect.
type CaptureLogs a = LogWriterM CaptureLogWriter a
-- | A LogWriter monad that provides pure logging by capturing via
-- the Writer effect.
--
-- See exampleLogCapture
captureLogWriter :: LogWriter CaptureLogWriter
-- | Run a Writer for LogMessages.
--
-- Such a Writer is needed to handle CaptureLogWriter
runCaptureLogWriter :: Eff (CaptureLogWriter : e) a -> Eff e (a, [LogMessage])
-- | The concrete list of Effects for logging with an IO based
-- LogWriter, and a LogWriterReader.
type LoggingAndIo = '[Logs, LogWriterReader (Lift IO), Lift IO]
-- | A LogWriter that uses an IO action to write the message.
--
-- This is just an alias for MkLogWriter but with IO as
-- parameter. This reduces the need to apply something to the extra type
-- argument @IO.
--
-- Example use cases for this function are the consoleLogWriter
-- and the ioHandleLogWriter.
mkLogWriterIO :: HasCallStack => (LogMessage -> IO ()) -> LogWriter (Lift IO)
-- | A LogWriter that renders LogMessages to strings via
-- renderLogMessageConsoleLog and prints them to an Handle
-- using hPutStrLn.
ioHandleLogWriter :: HasCallStack => Handle -> LogWriter (Lift IO)
-- | Enable logging to IO using the defaultIoLogWriter.
--
-- Example:
--
-- -- exampleWithIoLogging :: IO () -- exampleWithIoLogging = -- runLift -- $ withIoLogging debugTraceLogWriter -- "my-app" -- local7 -- (lmSeverityIsAtLeast informationalSeverity) -- $ logInfo "Oh, hi there" --withIoLogging :: Lifted IO e => LogWriter (Lift IO) -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Decorate an IO based LogWriter to fill out these fields in -- LogMessages: -- --
-- exampleWithFileLogging :: IO () -- exampleWithFileLogging = -- runLift -- $ withFileLogging "/var/log/my-app.log" "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withFileLogging :: (Lifted IO e, MonadBaseControl IO (Eff e)) => FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a file. -- -- If the file or its directory does not exist, it will be created. -- Example: -- --
-- exampleWithFileLogWriter :: IO () -- exampleWithFileLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withFileLogWriter "test.log" -- $ logInfo "Oh, hi there" --withFileLogWriter :: (LogIo e, MonadBaseControl IO (Eff e)) => FilePath -> Eff e b -> Eff e b -- | Enable logging via traceM using the debugTraceLogWriter, -- with some LogMessage fields preset as in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogging :: IO () -- exampleWithTraceLogging = -- runLift -- $ withTraceLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" --withTraceLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging via traceM using the debugTraceLogWriter. -- The logging monad type can be any type with a Monad -- instance. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogWriter :: IO () -- exampleWithTraceLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withTraceLogWriter -- $ logInfo "Oh, hi there" --withTraceLogWriter :: forall h e a. (Monad (LogWriterM h), LogsTo h e) => Eff e a -> Eff e a -- | Write LogMessages via traceM. debugTraceLogWriter :: forall h. Monad (LogWriterM h) => LogMessageRenderer Text -> LogWriter h -- | Enable logging to standard output using the -- consoleLogWriter, with some LogMessage fields preset as -- in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogging :: IO () -- exampleWithConsoleLogging = -- runLift -- $ withConsoleLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withConsoleLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to standard output using the -- consoleLogWriter. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogWriter :: IO () -- exampleWithConsoleLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withConsoleLogWriter -- $ logInfo "Oh, hi there" --withConsoleLogWriter :: LogIo e => Eff e a -> Eff e a -- | Write LogMessages to standard output, formatted with -- printLogMessage. -- -- It uses stdoutLogWriter with renderLogMessageConsoleLog. consoleLogWriter :: LogWriter (Lift IO) -- | A LogWriter that uses a LogMessageRenderer to render, -- and putStrLn to print it. stdoutLogWriter :: LogMessageRenderer Text -> LogWriter (Lift IO) -- | This is a wrapper around withAsyncLogWriter and -- withIoLogging. -- -- Example: -- --
-- exampleWithAsyncLogging :: IO () -- exampleWithAsyncLogging = -- runLift -- $ withAsyncLogWriter consoleLogWriter (1000::Int) "my-app" local0 allLogMessages -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogging :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter (Lift IO) -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Move the current LogWriter into its own thread. -- -- A bounded queue is used to forward logs to the process. -- -- If an exception is received, the logging process will be killed. -- -- Log messages are deeply evaluated before being sent to the logger -- process, to prevent that lazy evaluation leads to heavy work being -- done in the logger process instead of the caller process. -- -- Example: -- --
-- exampleAsyncLogWriter :: IO () -- exampleAsyncLogWriter = -- runLift -- $ withLogging consoleLogWriter -- $ withAsyncLogWriter (1000::Int) -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), Integral len) => len -> Eff e a -> Eff e a -- | Enable logging to a remote host via UDP, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleUdpRFC3164Logging withUDPLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => (LogMessage -> Text) -> String -> String -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a (remote-) host via UDP. -- -- See exampleUdpRFC3164Logging withUDPLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => (LogMessage -> Text) -> String -> String -> Eff e b -> Eff e b -- | Enable logging to a unix domain socket, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleDevLogSyslogLogging withUnixSocketLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => LogMessageRenderer Text -> FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader (Lift IO) : e)) a -> Eff e a -- | Enable logging to a (remote-) host via UnixSocket. -- -- See exampleDevLogSyslogLogging withUnixSocketLogWriter :: (LogIo e, MonadBaseControl IO (Eff e), HasCallStack) => LogMessageRenderer Text -> FilePath -> Eff e b -> Eff e b -- | A version of forever that hopefully tricks GHC into -- not creating a space leak. The intuition is, that we -- want to do something that is cheap, and hence should be -- recomputed instead of shared. foreverCheap :: Monad m => m a -> m () -- | A version of replicateM_ that hopefully tricks GHC into -- not creating a space leak. The intuition is, that we -- want to do something that is cheap, and hence should be -- recomputed instead of shared. replicateCheapM_ :: Monad m => Int -> m a -> m () -- | Run the Effects using a single threaded, coroutine based, pure -- scheduler from -- Control.Eff.Concurrent.Process.SingleThreadedScheduler. schedule :: Eff Effects a -> Either (Interrupt 'NoRecovery) a -- | The effect list for Process effects in the single threaded pure -- scheduler. -- -- See PureEffects type Effects = PureEffects -- | The effect list for Process effects in the single threaded pure -- scheduler. This is like SafeProcesses, no Interrupts are -- present. -- -- See PureSafeEffects type SafeEffects = PureSafeEffects -- | The effect list for the underlying scheduler. type BaseEffects = PureBaseEffects -- | Constraint for the existence of the underlying scheduler effects. type HasBaseEffects e = HasPureBaseEffects e