Skip to content

Commit 2438dfd

Browse files
committed
feat: initial commit
1 parent a627a0e commit 2438dfd

13 files changed

Lines changed: 1031 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.stack-work/
2+
dist-newstyle/
3+
*.log

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# fused-effects-logger
2+
A logger effects for the
3+
[`fused-effects`](https://github.com/fused-effects/fused-effects) library, based
4+
on the [`monad-logger`](https://github.com/snoyberg/monad-logger) API.

fused-effects-logger.cabal

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
cabal-version: 1.12
2+
3+
-- This file has been generated from package.yaml by hpack version 0.37.0.
4+
--
5+
-- see: https://github.com/sol/hpack
6+
7+
name: fused-effects-logger
8+
version: 0.0.0.0
9+
synopsis: Logger effect for the `fused-effects` library
10+
description: A logger effect for the `fused-effects` library based on the `monad-logger` api.
11+
category: Effect
12+
author: drlkf
13+
maintainer: drlkf@drlkf.net
14+
copyright: 2025 drlkf
15+
license: GPL-3
16+
license-file: LICENSE
17+
build-type: Simple
18+
extra-source-files:
19+
README.md
20+
21+
library
22+
exposed-modules:
23+
Control.Carrier.Logger.IO
24+
Control.Carrier.Logger.Writer
25+
Control.Effect.Logger
26+
other-modules:
27+
Paths_fused_effects_logger
28+
hs-source-dirs:
29+
src
30+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
31+
build-depends:
32+
base >=4.7 && <5
33+
, bytestring >=0.12 && <1
34+
, fused-effects >=1.1 && <2
35+
, monad-logger >=0.3 && <1
36+
default-language: Haskell2010
37+
38+
test-suite fused-effects-logger-test
39+
type: exitcode-stdio-1.0
40+
main-is: Spec.hs
41+
other-modules:
42+
Control.Carrier.Logger.IOSpec
43+
Control.Carrier.Logger.WriterSpec
44+
Paths_fused_effects_logger
45+
hs-source-dirs:
46+
test
47+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
48+
build-depends:
49+
base >=4.7 && <5
50+
, bytestring >=0.12 && <1
51+
, directory
52+
, fused-effects >=1.1 && <2
53+
, fused-effects-logger
54+
, ghc-prim
55+
, hspec
56+
, monad-logger >=0.3 && <1
57+
default-language: Haskell2010

package.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: fused-effects-logger
2+
version: 0.0.0.0
3+
license: GPL-3
4+
author: drlkf
5+
maintainer: drlkf@drlkf.net
6+
copyright: 2025 drlkf
7+
category: Effect
8+
9+
extra-source-files:
10+
- README.md
11+
12+
synopsis: Logger effect for the `fused-effects` library
13+
description: >-
14+
A logger effect for the `fused-effects` library based on the `monad-logger`
15+
api.
16+
17+
dependencies:
18+
- base >= 4.7 && < 5
19+
- bytestring >= 0.12 && < 1
20+
- fused-effects >= 1.1 && < 2
21+
- monad-logger >= 0.3 && < 1
22+
23+
ghc-options:
24+
- -Wall
25+
- -Wcompat
26+
- -Widentities
27+
- -Wincomplete-record-updates
28+
- -Wincomplete-uni-patterns
29+
- -Wmissing-export-lists
30+
- -Wmissing-home-modules
31+
- -Wpartial-fields
32+
- -Wredundant-constraints
33+
34+
library:
35+
source-dirs: src
36+
37+
tests:
38+
fused-effects-logger-test:
39+
main: Spec.hs
40+
source-dirs: test
41+
ghc-options:
42+
- -threaded
43+
- -rtsopts
44+
- -with-rtsopts=-N
45+
dependencies:
46+
- fused-effects-logger
47+
- directory
48+
- ghc-prim
49+
- hspec

src/Control/Carrier/Logger/IO.hs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+
{-# LANGUAGE MultiParamTypeClasses #-}
5+
{-# LANGUAGE RankNTypes #-}
6+
{-# LANGUAGE TypeApplications #-}
7+
{-# LANGUAGE TypeOperators #-}
8+
{-# LANGUAGE UndecidableInstances #-}
9+
10+
module Control.Carrier.Logger.IO (
11+
HandleSelector,
12+
singleHandle,
13+
runLoggerIO,
14+
) where
15+
16+
import Control.Algebra (Algebra (..), (:+:) (..))
17+
import Control.Carrier.Reader (ReaderC, runReader)
18+
import Control.Effect.Logger (Logger (..))
19+
import Control.Effect.Reader (ask)
20+
import Control.Monad.IO.Class (MonadIO (..))
21+
import Control.Monad.Logger (
22+
Loc,
23+
LogLevel,
24+
LogSource,
25+
LogStr,
26+
ToLogStr (..),
27+
defaultLogStr,
28+
fromLogStr,
29+
)
30+
import qualified Data.ByteString.Char8 as B (hPutStr)
31+
import System.IO (Handle)
32+
33+
-- | Algebra for a simple IO logger. The inner function allows for selecting a
34+
-- 'Handle' according to something like 'LogLevel'.
35+
newtype LoggerIOC f m a = LoggerIOC
36+
{ runLoggerIOC :: ReaderC f m a
37+
}
38+
deriving (Applicative, Functor, Monad, MonadIO)
39+
40+
type HandleSelector = Loc -> LogSource -> LogLevel -> LogStr -> Handle
41+
42+
singleHandle :: Handle -> HandleSelector
43+
singleHandle h _ _ _ _ = h
44+
45+
instance
46+
forall sig m
47+
. ( Algebra sig m
48+
, MonadIO m
49+
)
50+
=> Algebra (Logger :+: sig) (LoggerIOC HandleSelector m)
51+
where
52+
alg hdl sig ctx = case sig of
53+
L (LoggerLog loc src lvl msg) -> LoggerIOC $ do
54+
f <- ask
55+
ctx
56+
<$ liftIO
57+
( B.hPutStr
58+
(f loc src lvl (toLogStr msg))
59+
(fromLogStr (defaultLogStr loc src lvl (toLogStr msg)))
60+
)
61+
R other -> LoggerIOC (alg (runLoggerIOC . hdl) (R other) ctx)
62+
63+
-- | Run a logger by writing to a 'Handle'.
64+
runLoggerIO
65+
:: HandleSelector
66+
-> LoggerIOC HandleSelector m a
67+
-> m a
68+
runLoggerIO f = runReader f . runLoggerIOC
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+
{-# LANGUAGE MultiParamTypeClasses #-}
5+
{-# LANGUAGE RankNTypes #-}
6+
{-# LANGUAGE ScopedTypeVariables #-}
7+
{-# LANGUAGE TypeOperators #-}
8+
{-# LANGUAGE UndecidableInstances #-}
9+
10+
module Control.Carrier.Logger.Writer (
11+
LoggerWriterC (..),
12+
runLoggerW,
13+
) where
14+
15+
import Control.Algebra (Algebra (..), (:+:) (..))
16+
import Control.Carrier.Writer.Strict (WriterC, runWriter, tell)
17+
import Control.Effect.Logger (Logger (..))
18+
import Control.Monad.IO.Class (MonadIO (..))
19+
import Control.Monad.Logger (
20+
LogLine,
21+
ToLogStr (..),
22+
)
23+
24+
-- | Reinterpreter from logger to writer. The underlying 'Writer' is always
25+
-- 'Control.Carrier.Writer.Strict'.
26+
newtype LoggerWriterC w m a = LoggerWriterC
27+
{ runLoggerWriterC :: WriterC (w LogLine) m a
28+
}
29+
deriving (Applicative, Functor, Monad, MonadIO)
30+
31+
instance
32+
forall sig w m
33+
. ( Algebra sig m
34+
, Applicative w
35+
, Monoid (w LogLine)
36+
)
37+
=> Algebra (Logger :+: sig) (LoggerWriterC w m)
38+
where
39+
alg hdl sig ctx = case sig of
40+
L (LoggerLog loc src lvl msg) ->
41+
ctx <$ LoggerWriterC (tell (pure (loc, src, lvl, toLogStr msg) :: w LogLine))
42+
R other ->
43+
LoggerWriterC (alg (runLoggerWriterC . hdl) (R other) ctx)
44+
45+
runLoggerW
46+
:: Monoid (w LogLine)
47+
=> LoggerWriterC w m a
48+
-> m (w LogLine, a)
49+
runLoggerW = runWriter . runLoggerWriterC

src/Control/Effect/Logger.hs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE KindSignatures #-}
4+
{-# LANGUAGE UndecidableInstances #-}
5+
{-# OPTIONS_GHC -Wno-orphans #-}
6+
7+
module Control.Effect.Logger (
8+
Logger (..),
9+
) where
10+
11+
import Control.Effect.Labelled (Has, send)
12+
import Control.Monad.Logger (
13+
Loc,
14+
LogLevel,
15+
LogSource,
16+
MonadLogger (..),
17+
ToLogStr (..),
18+
)
19+
import Data.Kind (Type)
20+
21+
--
22+
-- Effect definition
23+
--
24+
25+
-- | A simple logger effect that takes all information a 'MonadLogger' monad
26+
-- would take. In order to be able to use the same interface as 'MonadLogger',
27+
-- that unfortunately means it needs to implement the 'MonadLogger' instance as
28+
-- an orphan.
29+
data Logger (m :: Type -> Type) k where
30+
LoggerLog
31+
:: ToLogStr msg
32+
=> Loc
33+
-> LogSource
34+
-> LogLevel
35+
-> msg
36+
-> Logger m ()
37+
38+
-- ORPHAN :(
39+
instance (Has Logger sig m, Monad m) => MonadLogger m where
40+
monadLoggerLog loc src lvl msg = send (LoggerLog loc src lvl msg)

stack.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
resolver:
3+
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/11.yaml
4+
5+
packages:
6+
- .

stack.yaml.lock

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This file was autogenerated by Stack.
2+
# You should not edit this file by hand.
3+
# For more information, please see the documentation at:
4+
# https://docs.haskellstack.org/en/stable/topics/lock_files
5+
6+
packages: []
7+
snapshots:
8+
- completed:
9+
sha256: 468e1afa06cd069e57554f10e84fdf1ac5e8893e3eefc503ef837e2449f7e60c
10+
size: 726310
11+
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/11.yaml
12+
original:
13+
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/11.yaml

0 commit comments

Comments
 (0)