co-log 0.5.0.0 → 0.6.0.0
raw patch · 16 files changed
+496/−264 lines, 16 filesdep +dependent-mapdep +dependent-sumdep +run-stdep −typerep-mapdep ~ansi-terminaldep ~basedep ~bytestringnew-component:exe:tutorial-loggertnew-component:exe:tutorial-loggert-simplenew-uploader
Dependencies added: dependent-map, dependent-sum, run-st, unliftio-core
Dependencies removed: typerep-map
Dependency ranges changed: ansi-terminal, base, bytestring, co-log-core, doctest, exceptions, hedgehog, mtl, text
Files
- CHANGELOG.md +49/−24
- README.lhs +13/−20
- README.md +13/−20
- co-log.cabal +49/−25
- src/Colog.hs +1/−2
- src/Colog/Actions.hs +1/−2
- src/Colog/Contra.hs +1/−2
- src/Colog/Message.hs +11/−23
- src/Colog/Monad.hs +4/−3
- src/Colog/Pure.hs +1/−2
- src/Colog/Rotation.hs +1/−2
- tutorials/2-custom/Custom.lhs +0/−136
- tutorials/2-loggert/loggert.lhs +96/−0
- tutorials/3-loggert-with-message/loggert.lhs +117/−0
- tutorials/Main.hs +3/−3
- tutorials/custom/Custom.lhs +136/−0
CHANGELOG.md view
@@ -3,33 +3,58 @@ `co-log` uses [PVP Versioning][1]. The changelog is available [on GitHub][2]. +## 0.6.0.0 - Sep 18, 2023++### What's Changed++* Support GHC-9.6 - replace `typerep-map` with `dependent-map`. by @alaendle in [#264](https://github.com/co-log/co-log/pull/264)+* Support GHC 9.4. by @alaendle in [#252](https://github.com/co-log/co-log/pull/252)+* Add MonadUnliftIO instance by @newhoggy in [#240](https://github.com/co-log/co-log/pull/240)+* Update CI tested GHC versions & workaround for GHC < 9.4.5 (run-st, primitive-unlifted) by @alaendle in [#257](https://github.com/co-log/co-log/pull/257)+* Derive `MonadFail` for `LoggerT` by @alaendle in [#260](https://github.com/co-log/co-log/pull/260)+* docs: use relative path to benefit locally reading by @xieyuschen in [#253](https://github.com/co-log/co-log/pull/253)+* docs: refine readme by @xieyuschen in [#254](https://github.com/co-log/co-log/pull/254)+* tutorials: add demo for LoggerT and SimpleMsg, #84 by @xieyuschen in [#256](https://github.com/co-log/co-log/pull/256)+* docs: add a link to tutorial pages and aggregate all tutorial pages by @xieyuschen in [#259](https://github.com/co-log/co-log/pull/259)+* tutorials: add a tutorial for loggert and message by @xieyuschen in [#261](https://github.com/co-log/co-log/pull/261)+* Create tags and upload package candidates on version bumps. by @alaendle in [#265](https://github.com/co-log/co-log/pull/265)+* Added @alaendle as code owner. by @alaendle in [#258](https://github.com/co-log/co-log/pull/258)+* GA(deps): Bump actions/checkout from 3 to 4 by @dependabot in [#263](https://github.com/co-log/co-log/pull/263)++### New Contributors++* @xieyuschen made their first contribution in [#253](https://github.com/co-log/co-log/pull/253)+* @newhoggy made their first contribution in [#240](https://github.com/co-log/co-log/pull/240)++**Full Changelog**: https://github.com/co-log/co-log/compare/v0.5.0.0...v0.6.0.0+ ## 0.5.0.0 - Nov 2, 2022 -* [#230](https://github.com/kowainik/co-log/issues/230):+* [#230](https://github.com/co-log/co-log/issues/230): Support GHC-9.2. * Allow `mtl-2.3`. * Allow `vector-0.13`. * Allow `hedgehog-1.2`.-* [#187](https://github.com/kowainik/co-log/issues/187):+* [#187](https://github.com/co-log/co-log/issues/187): Remove `CoLog.Concurrent` module and executable.-* [#243](https://github.com/kowainik/co-log/pull/243):+* [#243](https://github.com/co-log/co-log/pull/243): Improve printing in multiple threads. * Drop support for GHC-8.2, GHC-8.4, GHC-8.6, GHC-8.8 ## 0.4.0.2 — <M> <d>, 2021 -* [#223](https://github.com/kowainik/co-log/pulls/223):+* [#223](https://github.com/co-log/co-log/pulls/223): Support GHC-9.0.1. Require typerep-map ^>= 0.4 ## 0.4.0.1 — Apr 18, 2020 -* [#186](https://github.com/kowainik/co-log/issues/186):+* [#186](https://github.com/co-log/co-log/issues/186): Support GHC-8.10.1. ## 0.4.0.0 — Jan 19, 2020 -* [#120](https://github.com/kowainik/co-log/issues/120):+* [#120](https://github.com/co-log/co-log/issues/120): Improve time formatting. Old: `29-12-2019 22:00:00.000`@@ -37,39 +62,39 @@ New: `29 Dec 2019 22:00:00.000 +00:00` (by [@vrom911](https://github.com/vrom911))-* [#144](https://github.com/kowainik/co-log/issues/144):+* [#144](https://github.com/co-log/co-log/issues/144): Add Windows CI check. (by [@vrom911](https://github.com/vrom911))-* [#148](https://github.com/kowainik/co-log/issues/148):+* [#148](https://github.com/co-log/co-log/issues/148): Support GHC-8.8.2. (by [@chshersh](https://github.com/chshersh))-* [#119](https://github.com/kowainik/co-log/issues/119):+* [#119](https://github.com/co-log/co-log/issues/119): Add new message type that allows printing messages without `Severity`. (by [@sphaso](https://github.com/sphaso))-* [#150](https://github.com/kowainik/co-log/issues/150):+* [#150](https://github.com/co-log/co-log/issues/150): Introduce `formatWith` — beginner-friendly alias for formatting combinator. (by [@chshersh](https://github.com/chshersh)) * Use `chronos-1.1` as `1.0.9` is not Windows-compatible. (by [@vrom911](https://github.com/vrom911))-* [#156](https://github.com/kowainik/co-log/issues/156):+* [#156](https://github.com/co-log/co-log/issues/156): Improve documentation for the `Colog.Concurrent` module. (by [@chshersh](https://github.com/chshersh))-* [#146](https://github.com/kowainik/co-log/issues/146):+* [#146](https://github.com/co-log/co-log/issues/146): Allow `ansi-terminal-0.10`. (by [@mpilgrem](https://github.com/mpilgrem))-* [#124](https://github.com/kowainik/co-log/issues/124):+* [#124](https://github.com/co-log/co-log/issues/124): Implement executable playground for concurrent logging. (by [@chshersh](https://github.com/chshersh)) ## 0.3.0.0 — May 5, 2019 -* [#77](https://github.com/kowainik/co-log/issues/77):+* [#77](https://github.com/co-log/co-log/issues/77): **Important:** Use `chronos` time formatter. This is a breaking change because default field map in `RichMessage` now contains different type representing time. If you use your custom formatter for time, you should change it. Othwerwise no observable differences in the library API usage will be noticed.-* [#103](https://github.com/kowainik/co-log/issues/103):+* [#103](https://github.com/co-log/co-log/issues/103): **Breaking change:** make `Message` data type polymorhic over the type of severity. **Migration guide:** this change is done in backwards-compatible way. If you@@ -81,30 +106,30 @@ messageText -> msgText ``` * Export more formatting functions to make implementation of custom formatters easier.-* [#96](https://github.com/kowainik/co-log/issues/96):+* [#96](https://github.com/co-log/co-log/issues/96): Add `simpleMessageAction` and `richMessageAction` to work with `Message`s. * Use `co-log-core` of version `0.2.0.0`. ## 0.2.0 — Nov 15, 2018 -* [#45](https://github.com/kowainik/co-log/issues/45):+* [#45](https://github.com/co-log/co-log/issues/45): Introduce approach for concurrent log writing.-* [#46](https://github.com/kowainik/co-log/issues/46):+* [#46](https://github.com/co-log/co-log/issues/46): Moves `logStringStdout`, `logStringStderr`, `logStringHandle`, `withLogStringFile` from `Colog.Actions` to `Colog.Core.IO`-* [#77](https://github.com/kowainik/co-log/issues/77):+* [#77](https://github.com/co-log/co-log/issues/77): Remove `relude` from dependencies. Add HLint check to Travis CI.-* [#64](https://github.com/kowainik/co-log/issues/64):+* [#64](https://github.com/co-log/co-log/issues/64): Introduce basic benchmarks.-* [#20](https://github.com/kowainik/co-log/issues/20):+* [#20](https://github.com/co-log/co-log/issues/20): Add experimental support for logger rotation (see `Colog.Rotation` module).-* [#39](https://github.com/kowainik/co-log/issues/39):+* [#39](https://github.com/co-log/co-log/issues/39): Support GHC-8.2.2 and GHC-8.6.2. ## 0.1.0 -* [#37](https://github.com/kowainik/co-log/issues/37):+* [#37](https://github.com/co-log/co-log/issues/37): Add bounds to all dependencies. Move `Prelude` to the `other-modules` section. @@ -113,4 +138,4 @@ * Initially created. [1]: https://pvp.haskell.org-[2]: https://github.com/kowainik/co-log/releases+[2]: https://github.com/co-log/co-log/releases
README.lhs view
@@ -1,9 +1,9 @@ # co-log -+<img align="left" width="180" height="180" src="https://user-images.githubusercontent.com/8126674/80955687-92f21a80-8df7-11ea-90d3-422dafdc8391.png"> -[](https://github.com/kowainik/co-log/actions)-[](https://github.com/kowainik/co-log/blob/main/LICENSE)+[](https://github.com/co-log/co-log/actions)+[](https://github.com/co-log/co-log/blob/main/LICENSE) `co-log` is a composable and configurable logging framework. It combines all the benefits of Haskell idioms to provide a reasonable@@ -14,11 +14,13 @@ pragmatic approach to logging and fundamental Haskell abstractions allows us to create a highly composable and configurable logging framework. +---+ If you're interested in how different Haskell typeclasses are used to implement core functions of `co-log`, you can read the following blog post which goes into detail about the internal implementation specifics: -* [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log)+- [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log) ## Co-Log Family @@ -28,12 +30,12 @@ Here is the list of currently available repositories and libraries that you can check out: -| | | |-| :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- |-| [`co-log-core`](https://github.com/co-log/co-log-core) | lightweight package with basic data types and general idea which depends only on `base` | [![Hackage][hk-img-core]][hk-core] |-| [`co-log`](https://github.com/co-log/co-log) | taggless final implementation of logging library based on `co-log-core` | [![Hackage][hk-img]][hk] |-| [`co-log-polysemy`](https://github.com/co-log/co-log-polysemy) | implementation of logging library based on `co-log-core` and the [`polysemy`](http://hackage.haskell.org/package/polysemy) extensible effects library. | [![Hackage][hk-img-ps]][hk-ps] |-| [`co-log-benchmarks`](https://github.com/co-log/co-log-benchmarks) | benchmarks of the `co-log` library | -+| | | |+| :----------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- |+| [`co-log-core`](https://github.com/co-log/co-log-core) | lightweight package with basic data types and general idea which depends only on `base` | [![Hackage][hk-img-core]][hk-core] |+| [`co-log`](https://github.com/co-log/co-log) | taggless final implementation of logging library based on `co-log-core` | [![Hackage][hk-img]][hk] |+| [`co-log-polysemy`](https://github.com/co-log/co-log-polysemy) | implementation of logging library based on `co-log-core` and the [`polysemy`](http://hackage.haskell.org/package/polysemy) extensible effects library. | [![Hackage][hk-img-ps]][hk-ps] |+| [`co-log-benchmarks`](https://github.com/co-log/co-log-benchmarks) | benchmarks of the `co-log` library | - | ## `co-log` library @@ -137,16 +139,7 @@ To provide a more user-friendly introduction to the library, we've created the tutorial series which introduces the main concepts behind `co-log`-smoothly:--* [Intro: Using `LogAction`](https://github.com/co-log/co-log/blob/main/tutorials/1-intro/Intro.md)-* [Using custom monad that stores `LogAction` inside its environment](https://github.com/co-log/co-log/blob/main/tutorials/2-custom/Custom.md)--`co-log` also cares about concurrent logging. For this purpose we have the `concurrent-playground`-executable where we experiment with different multithreading scenarios to test the library's behavior.-You can find it here:--* [tutorials/Concurrent.hs](tutorials/Concurrent.hs)+smoothly, please [check more details here](./tutorials/README.md). [hk-img]: https://img.shields.io/hackage/v/co-log.svg?logo=haskell [hk-img-ps]: https://img.shields.io/hackage/v/co-log-polysemy.svg?logo=haskell
README.md view
@@ -1,9 +1,9 @@ # co-log -+<img align="left" width="180" height="180" src="https://user-images.githubusercontent.com/8126674/80955687-92f21a80-8df7-11ea-90d3-422dafdc8391.png"> -[](https://github.com/kowainik/co-log/actions)-[](https://github.com/kowainik/co-log/blob/main/LICENSE)+[](https://github.com/co-log/co-log/actions)+[](https://github.com/co-log/co-log/blob/main/LICENSE) `co-log` is a composable and configurable logging framework. It combines all the benefits of Haskell idioms to provide a reasonable@@ -14,11 +14,13 @@ pragmatic approach to logging and fundamental Haskell abstractions allows us to create a highly composable and configurable logging framework. +---+ If you're interested in how different Haskell typeclasses are used to implement core functions of `co-log`, you can read the following blog post which goes into detail about the internal implementation specifics: -* [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log)+- [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log) ## Co-Log Family @@ -28,12 +30,12 @@ Here is the list of currently available repositories and libraries that you can check out: -| | | |-| :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- |-| [`co-log-core`](https://github.com/co-log/co-log-core) | lightweight package with basic data types and general idea which depends only on `base` | [![Hackage][hk-img-core]][hk-core] |-| [`co-log`](https://github.com/co-log/co-log) | taggless final implementation of logging library based on `co-log-core` | [![Hackage][hk-img]][hk] |-| [`co-log-polysemy`](https://github.com/co-log/co-log-polysemy) | implementation of logging library based on `co-log-core` and the [`polysemy`](http://hackage.haskell.org/package/polysemy) extensible effects library. | [![Hackage][hk-img-ps]][hk-ps] |-| [`co-log-benchmarks`](https://github.com/co-log/co-log-benchmarks) | benchmarks of the `co-log` library | -+| | | |+| :----------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- |+| [`co-log-core`](https://github.com/co-log/co-log-core) | lightweight package with basic data types and general idea which depends only on `base` | [![Hackage][hk-img-core]][hk-core] |+| [`co-log`](https://github.com/co-log/co-log) | taggless final implementation of logging library based on `co-log-core` | [![Hackage][hk-img]][hk] |+| [`co-log-polysemy`](https://github.com/co-log/co-log-polysemy) | implementation of logging library based on `co-log-core` and the [`polysemy`](http://hackage.haskell.org/package/polysemy) extensible effects library. | [![Hackage][hk-img-ps]][hk-ps] |+| [`co-log-benchmarks`](https://github.com/co-log/co-log-benchmarks) | benchmarks of the `co-log` library | - | ## `co-log` library @@ -137,16 +139,7 @@ To provide a more user-friendly introduction to the library, we've created the tutorial series which introduces the main concepts behind `co-log`-smoothly:--* [Intro: Using `LogAction`](https://github.com/co-log/co-log/blob/main/tutorials/1-intro/Intro.md)-* [Using custom monad that stores `LogAction` inside its environment](https://github.com/co-log/co-log/blob/main/tutorials/2-custom/Custom.md)--`co-log` also cares about concurrent logging. For this purpose we have the `concurrent-playground`-executable where we experiment with different multithreading scenarios to test the library's behavior.-You can find it here:--* [tutorials/Concurrent.hs](tutorials/Concurrent.hs)+smoothly, please [check more details here](./tutorials/README.md). [hk-img]: https://img.shields.io/hackage/v/co-log.svg?logo=haskell [hk-img-ps]: https://img.shields.io/hackage/v/co-log-polysemy.svg?logo=haskell
co-log.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: co-log-version: 0.5.0.0+version: 0.6.0.0 synopsis: Composable Contravariant Comonadic Logging Library description: The default implementation of logging based on [co-log-core](http://hackage.haskell.org/package/co-log-core).@@ -9,13 +9,13 @@ . * [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log) -homepage: https://github.com/kowainik/co-log-bug-reports: https://github.com/kowainik/co-log/issues+homepage: https://github.com/co-log/co-log+bug-reports: https://github.com/co-log/co-log/issues license: MPL-2.0 license-file: LICENSE author: Dmitrii Kovanikov maintainer: Kowainik <xrom.xkov@gmail.com>-copyright: 2018-2022 Kowainik+copyright: 2018-2022 Kowainik, 2023 Co-Log category: Logging, Contravariant, Comonad build-type: Simple stability: provisional@@ -23,14 +23,16 @@ README.md tested-with: GHC == 8.10.7 GHC == 9.0.2- GHC == 9.2.4+ GHC == 9.2.8+ GHC == 9.4.7+ GHC == 9.6.2 source-repository head type: git- location: https://github.com/kowainik/co-log.git+ location: https://github.com/co-log/co-log.git common common-options- build-depends: base >= 4.14 && < 4.17+ build-depends: base >= 4.14 && < 4.19 ghc-options: -Wall -Wcompat@@ -72,10 +74,17 @@ if os(windows) buildable: False build-depends: co-log-core+ , text build-tool-depends: markdown-unlit:markdown-unlit ghc-options: -pgmL markdown-unlit +common tutorial-depends+ import: tutorial-options+ build-depends: co-log+ , mtl++ library import: common-options hs-source-dirs: src@@ -87,20 +96,24 @@ Colog.Pure Colog.Rotation - build-depends: ansi-terminal >= 0.10 && < 0.12- , bytestring >= 0.10.8 && < 0.12+ build-depends: ansi-terminal >= 1.0 && < 1.1+ , bytestring >= 0.10.8 && < 0.13 , co-log-core ^>= 0.3 , containers >= 0.5.7 && < 0.7 , contravariant ^>= 1.5 , directory ^>= 1.3.0- , exceptions >= 0.8.3+ , exceptions >= 0.8.3 && < 0.11 , filepath ^>= 1.4.1 , mtl >= 2.2.2 && < 2.4- , text >= 1.2.3 && < 2.1+ , text >= 1.2.3 && < 2.2 , chronos ^>= 1.1 && < 1.2 , transformers >= 0.5 && < 0.7- , typerep-map ^>= 0.5+ , dependent-sum >= 0.7 && < 0.8+ , dependent-map >= 0.4 && < 0.5+ , unliftio-core ^>= 0.2 , vector >= 0.12.0.3 && < 0.14+ if impl(ghc < 9.4.5)+ build-depends: run-st <= 0.1.3.0 executable play-colog import: common-options@@ -109,7 +122,7 @@ build-depends: co-log , mtl- , typerep-map+ , dependent-map ghc-options: -threaded -rtsopts@@ -131,31 +144,42 @@ build-depends: co-log , text -executable tutorial-intro- import: tutorial-options- main-is: tutorials/1-intro/Intro.lhs--executable tutorial-custom- import: tutorial-options- main-is: tutorials/2-custom/Custom.lhs- build-depends: co-log- , mtl- test-suite test-co-log import: common-options build-depends: co-log , co-log-core- , hedgehog >= 1.0 && < 1.3+ , hedgehog >= 1.0 && < 1.5 hs-source-dirs: test main-is: Property.hs type: exitcode-stdio-1.0 test-suite co-log-doctest import: common-options+ -- Disable `doctest` on windows since it couldn't handle qualified imports reliable (which leads to errors like "Not in scope: `C.timeToOffsetDatetime'").+ if os(windows)+ buildable: False type: exitcode-stdio-1.0 hs-source-dirs: test main-is: Doctest.hs - build-depends: doctest >= 0.16.0 && < 0.21+ build-depends: doctest >= 0.16.0 && < 0.23 , Glob ^>= 0.10.0 ghc-options: -threaded+++executable tutorial-intro+ import: tutorial-options+ main-is: tutorials/1-intro/Intro.lhs++executable tutorial-loggert-simple+ import: tutorial-depends+ main-is: tutorials/2-loggert/loggert.lhs+ +executable tutorial-loggert+ import: tutorial-depends+ main-is: tutorials/3-loggert-with-message/loggert.lhs++executable tutorial-custom+ import: tutorial-depends+ main-is: tutorials/custom/Custom.lhs+
src/Colog.hs view
@@ -1,7 +1,6 @@ {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> This package contains @mtl@ implementation of composable, contravariant and comonadic logging based on @co-log-core@.
src/Colog/Actions.hs view
@@ -1,7 +1,6 @@ {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> Logging actions for various text types. -}
src/Colog/Contra.hs view
@@ -3,9 +3,8 @@ {-# LANGUAGE CPP #-} {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> This module contains 'LogAction' orphan instances of @contravariant@ classes. -}
src/Colog/Message.hs view
@@ -5,13 +5,11 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE TypeFamilies #-} {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> This module contains logging messages data types along with the formatting and logging actions for them.@@ -65,21 +63,21 @@ , upgradeMessageAction ) where -import Prelude hiding (log)+import Prelude hiding (lookup, log) import Control.Concurrent (ThreadId, myThreadId) import Control.Exception (Exception, displayException) import Control.Monad.IO.Class (MonadIO (..))+import Data.Dependent.Map (DMap, fromList, lookup)+import Data.Dependent.Sum (DSum ((:=>))) import Data.Kind (Type) import Data.Text (Text) import Data.Text.Lazy (toStrict)-import Data.TypeRepMap (TypeRepMap)-import GHC.Exts (IsList (..))-import GHC.OverloadedLabels (IsLabel (..)) import GHC.Stack (CallStack, SrcLoc (..), callStack, getCallStack, withFrozenCallStack)-import GHC.TypeLits (KnownSymbol, Symbol)+import GHC.TypeLits (Symbol) import System.Console.ANSI (Color (..), ColorIntensity (Vivid), ConsoleLayer (Foreground), SGR (..), setSGRCode)+import Type.Reflection (TypeRep, typeRep) import Colog.Core (LogAction, Severity (..), cmap) import Colog.Monad (WithLog, logMsg)@@ -89,7 +87,6 @@ import qualified Data.Text as T import qualified Data.Text.Lazy.Builder as TB import qualified Data.Text.Lazy.Builder.Int as TB-import qualified Data.TypeRepMap as TM import qualified Data.Vector as Vector ----------------------------------------------------------------------------@@ -297,15 +294,6 @@ unMessageField (MessageField f) = f {-# INLINE unMessageField #-} -instance (KnownSymbol fieldName, a ~ m (FieldType fieldName))- => IsLabel fieldName (a -> TM.WrapTypeable (MessageField m)) where-#if MIN_VERSION_base(4,11,0)- fromLabel field = TM.WrapTypeable $ MessageField @fieldName field-#else- fromLabel field = TM.WrapTypeable $ MessageField @_ @fieldName field-#endif- {-# INLINE fromLabel #-}- -- | Helper function to deal with 'MessageField' when looking it up in the 'FieldMap'. extractField :: Applicative m@@ -322,7 +310,7 @@ {- | Depedent map from type level strings to the corresponding types. See 'FieldType' for mapping between names and types. -}-type FieldMap (m :: Type -> Type) = TypeRepMap (MessageField m)+type FieldMap m = DMap TypeRep (MessageField m) {- | Default message map that contains actions to extract 'ThreadId' and 'C.Time'. Basically, the following mapping:@@ -334,8 +322,8 @@ -} defaultFieldMap :: MonadIO m => FieldMap m defaultFieldMap = fromList- [ #threadId (liftIO myThreadId)- , #posixTime (liftIO C.now)+ [ typeRep @"threadId" :=> MessageField (liftIO myThreadId)+ , typeRep @"posixTime" :=> MessageField (liftIO C.now) ] {- | Contains additional data to 'Message' to display more verbose information.@@ -413,8 +401,8 @@ -> (Maybe ThreadId -> Maybe C.Time -> msg -> Text) -> m Text fmtRichMessageCustomDefault RichMsg{..} formatter = do- maybeThreadId <- extractField $ TM.lookup @"threadId" richMsgMap- maybePosixTime <- extractField $ TM.lookup @"posixTime" richMsgMap+ maybeThreadId <- extractField $ lookup (typeRep @"threadId") richMsgMap+ maybePosixTime <- extractField $ lookup (typeRep @"posixTime") richMsgMap pure $ formatter maybeThreadId maybePosixTime richMsgMsg {- | Shows time in the following format:
src/Colog/Monad.hs view
@@ -1,9 +1,8 @@ {-# LANGUAGE InstanceSigs #-} {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> Core of the @mtl@ implementation. -}@@ -22,6 +21,7 @@ import Prelude hiding (log) import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.IO.Unlift (MonadUnliftIO (..)) import Control.Monad.Reader (MonadReader (..), ReaderT (..), asks) import Control.Monad.Trans.Class (MonadTrans (..)) import Data.Foldable (traverse_)@@ -34,8 +34,9 @@ -} newtype LoggerT msg m a = LoggerT { runLoggerT :: ReaderT (LogAction (LoggerT msg m) msg) m a- } deriving newtype ( Functor, Applicative, Monad, MonadIO+ } deriving newtype ( Functor, Applicative, Monad, MonadIO, MonadFail , MonadReader (LogAction (LoggerT msg m) msg)+ , MonadUnliftIO ) instance MonadTrans (LoggerT msg) where
src/Colog/Pure.hs view
@@ -1,7 +1,6 @@ {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> Pure implementation of logging action. -}
src/Colog/Rotation.hs view
@@ -1,7 +1,6 @@ {- |-Copyright: (c) 2018-2022 Kowainik+Copyright: (c) 2018-2022 Kowainik, 2023 Co-Log SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com> Stability: experimental __NOTE:__ This functionality is not to be considered stable
− tutorials/2-custom/Custom.lhs
@@ -1,136 +0,0 @@-# Using a custom monad that stores `LogAction` inside its environment--This tutorial covers the more advanced topic of using the `co-log` library with-a custom application monad.--You can run this tutorial by executing the following command:--```shell-cabal new-run tutorial-custom-```--## Preamble: imports and language extensions--Since this is a literate Haskell file, we need to specify all our language-extensions and imports up front.--```haskell-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}--import Prelude hiding (log)--import Colog (pattern D, HasLog (..), pattern I, LogAction, Message, WithLog, log,- richMessageAction)-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Reader (MonadReader, ReaderT (..))-```--## Application environment--If you have a complex Haskell application, then you are likely to also have-non-trivial settings that configure your application environment. The-environment may store various parameters relevant to your application's-behavior. Interestingly, we can store a `LogAction` inside the same-environment to use it for our logging functions.--The environment for your application may look like this:--```haskell-data Env m = Env- { envServerPort :: !Int- , envLogAction :: !(LogAction m Message)- }-```--Several notes about this data type:--1. It stores different parameters, like the server port.-2. It stores a `LogAction` that can log values of the `Message` type-from `co-log` in the `m` monad.-3. `Env` is parameterized by type variable `m` which is going to be the-application monad.--The next step is to define an instance of the `HasLog` typeclass for the `Env`-data type. This instance will specify how to get and update the `LogAction`-stored inside the environment.--```haskell-instance HasLog (Env m) Message m where- getLogAction :: Env m -> LogAction m Message- getLogAction = envLogAction- {-# INLINE getLogAction #-}-- setLogAction :: LogAction m Message -> Env m -> Env m- setLogAction newLogAction env = env { envLogAction = newLogAction }- {-# INLINE setLogAction #-}-```--That's it! `co-log` requires very little boilerplate.--## Application monad--Now let's define our application monad:--```haskell-newtype App a = App- { unApp :: ReaderT (Env App) IO a- } deriving newtype (Functor, Applicative, Monad, MonadIO, MonadReader (Env App))-```--This monad stores `Env` parameterized by the monad itself in its context.-Nothing special is required here to tell the monad how to use the logger.--## Example--`co-log` relies on the tagless final technique for writing functions. So you-define your monadic actions with the `WithLog` constraint that allows you to-perform logging:--```haskell-example :: WithLog env Message m => m ()-example = do- log D "First message..."- log I "Second message..."-```--The `WithLog` constraint has three type parameters: the application environment,-the type of the message and the monad. Function `log` takes two parameters:-the logger severity and the log message's text.--## Running example--Now we are ready to execute this action.--First, let's create an example environment:--```haskell-simpleEnv :: Env App-simpleEnv = Env- { envServerPort = 8081- , envLogAction = richMessageAction- }-```--Then we need to define a function that performs actions of type `App`:--```haskell-runApp :: Env App -> App a -> IO a-runApp env app = runReaderT (unApp app) env-```--Putting it all together, we can specialize the `WithLog` constraint to our-`App` monad and run our example.--```haskell-main :: IO ()-main = runApp simpleEnv example-```--And the output will look like this:--
+ tutorials/2-loggert/loggert.lhs view
@@ -0,0 +1,96 @@+# Simple Message and LoggerT++This tutorial will show you how to use LoggerT and Simple message to log with more information in a more flexiable way.++You can run this tutorial by executing the following command:++```shell+cabal new-run tutorial-loggert-simple+```++## Preamble: imports and language extensions++Since this is a literate Haskell file, we need to specify all our language+extensions and imports up front.++```haskell+{-# OPTIONS_GHC -Wno-unused-top-binds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Prelude hiding (log)+import Data.Text (Text,append)+import Colog ( LogAction, SimpleMsg , usingLoggerT,+ WithLog, cmap, logText,fmtSimpleMessage,formatWith,+ logTextStderr,logTextStdout+ )+```++## LoggerT+The `LoggerT` monad transformer wraps a ReaderT that keeps `LogAction` in its context. It denotes a +computation of logging. So you define your monadic actions with the `WithLog` constraint that allows you to perform logging:+```haskell+example1 :: WithLog env SimpleMsg m => m ()+example1 = do+ logText "this is a demo log for simple message!"++example2 :: WithLog env SimpleMsg m => m ()+example2 = do+ logText "you see the demo log for simple message again!\n"+```+The `WithLog` constraint has three type parameters: the application environment,+the type of the message and the monad. The actions constraint by `WithLog` could be used as `LoggerT`.+++## Simple Message+The simple message is data type without `severity`. It contains a callstack information and a text message.+```idris+data SimpleMsg = SimpleMsg+ { simpleMsgStack :: !CallStack+ , simpleMsgText :: !Text+ }+```+When logging, simple messages require a format for transforming from simple messages to text. We can either use `formatWith` or its alias `cmap`+to combine it with the `LogAction`.++```haskell+logStdoutAction :: LogAction IO SimpleMsg+logStdoutAction = cmap fmtSimpleMessage logTextStdout++logStdErrAction :: LogAction IO SimpleMsg+logStdErrAction = formatWith fmtSimpleMessage logTextStderr+```+What's more, it's available to define a own formatter.+```haskell+selfDefinedFmtSimpleMessage :: SimpleMsg -> Text+selfDefinedFmtSimpleMessage = append "+ self defined behavior: " . fmtSimpleMessage++logByOwnFormatterAction :: LogAction IO SimpleMsg+logByOwnFormatterAction = formatWith selfDefinedFmtSimpleMessage logTextStderr+```++## Running example++Now we are ready to execute those actions defined above.+```haskell+main :: IO ()+main = do+ usingLoggerT logStdoutAction example1+ usingLoggerT logStdoutAction example2+ usingLoggerT logStdErrAction example1+ usingLoggerT logStdErrAction example2+ usingLoggerT logByOwnFormatterAction example1+ usingLoggerT logByOwnFormatterAction example2+```++Run command `cabal new-run tutorial-loggert-simple`.++And the output will look like this:++
+ tutorials/3-loggert-with-message/loggert.lhs view
@@ -0,0 +1,117 @@+# Message and LoggerT++The previous tutorial shows how to use `LoggerT` with simple message.+This tutorial will show you how to use LoggerT together with messages with more details(e.g. severity).++You can run this tutorial by executing the following command:++```shell+cabal new-run tutorial-loggert+```++## Preamble: imports and language extensions++```haskell+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -Wno-unused-top-binds #-}++module Main (main) where++import Colog (+ LogAction,+ Message,+ Msg (..),+ WithLog,+ cmap,+ fmtMessage,+ formatWith,+ logError,+ logInfo,+ logTextStderr,+ logTextStdout,+ msgSeverity,+ msgText,+ richMessageAction,+ showSeverity,+ usingLoggerT,+ )++import Data.Text (Text)+import Prelude hiding (log)+```++## LoggerT++The `LoggerT` monad transformer wraps a ReaderT that keeps `LogAction` in its context. It denotes a+computation of logging. So you define your monadic actions with the `WithLog` constraint that allows you to perform logging.+The `Message` allows you to log with severity.++```haskell+example1 :: WithLog env Message m => m ()+example1 = do+ logInfo "this is a demo log for message!"++example2 :: WithLog env Message m => m ()+example2 = do+ logError "Mayday! Mayday! Here is an example of error log\n"+```++The `WithLog` constraint has three type parameters:++- `env` – application environment+- `msg` – type of the message+- `m` – monad++The actions constraint by `WithLog` could be used as `LoggerT`.++## Message++The message is parametrized by the `Severity` type through `Msg`, which is a general logging message data type.++```idris+type Message = Msg Severity+data Msg sev = Msg+ { msgSeverity :: !sev+ , msgStack :: !CallStack+ , msgText :: Text+ }+```++Hence, besides printing the callstack, as the `LoggerT` with simple message tutorial shows, this example supports printing severity and thread id as well.++```haskell+logStdoutAction :: LogAction IO Message+logStdoutAction = cmap fmtMessage logTextStdout++fmtMessageWithoutSourceLoc :: Message -> Text+fmtMessageWithoutSourceLoc Msg{..} =+ showSeverity msgSeverity+ <> msgText++logStdErrActionWithoutStackAction :: LogAction IO Message+logStdErrActionWithoutStackAction = formatWith fmtMessageWithoutSourceLoc logTextStderr+```++## Running example++Now we are ready to execute those actions defined above.++```haskell+main :: IO ()+main = do+ usingLoggerT logStdoutAction example1+ usingLoggerT logStdoutAction example2+ usingLoggerT logStdErrActionWithoutStackAction example1+ usingLoggerT logStdErrActionWithoutStackAction example2+ usingLoggerT richMessageAction example1+ usingLoggerT richMessageAction example2+```++Run command `cabal new-run tutorial-loggert`, and the output will look like this:++
tutorials/Main.hs view
@@ -28,8 +28,8 @@ logWarning, pattern D, runPureLog, upgradeMessageAction, usingLoggerT, withLog, withLogTextFile, (*<), (<&), (>$), (>$<), (>*), (>*<), (>|<)) -import qualified Data.TypeRepMap as TM-+import Data.Dependent.Map (delete)+import Type.Reflection (typeRep) example :: WithLog env Message m => m () example = do@@ -188,7 +188,7 @@ let fullMessageAction = upgradeMessageAction defaultFieldMap richMessageAction let semiMessageAction = upgradeMessageAction- (TM.delete @"threadId" defaultFieldMap)+ (delete (typeRep @"threadId") defaultFieldMap) richMessageAction runApp simpleMessageAction
+ tutorials/custom/Custom.lhs view
@@ -0,0 +1,136 @@+# Using a custom monad that stores `LogAction` inside its environment++This tutorial covers the more advanced topic of using the `co-log` library with+a custom application monad.++You can run this tutorial by executing the following command:++```shell+cabal new-run tutorial-custom+```++## Preamble: imports and language extensions++Since this is a literate Haskell file, we need to specify all our language+extensions and imports up front.++```haskell+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}++import Prelude hiding (log)++import Colog (pattern D, HasLog (..), pattern I, LogAction, Message, WithLog, log,+ richMessageAction)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Reader (MonadReader, ReaderT (..))+```++## Application environment++If you have a complex Haskell application, then you are likely to also have+non-trivial settings that configure your application environment. The+environment may store various parameters relevant to your application's+behavior. Interestingly, we can store a `LogAction` inside the same+environment to use it for our logging functions.++The environment for your application may look like this:++```haskell+data Env m = Env+ { envServerPort :: !Int+ , envLogAction :: !(LogAction m Message)+ }+```++Several notes about this data type:++1. It stores different parameters, like the server port.+2. It stores a `LogAction` that can log values of the `Message` type+from `co-log` in the `m` monad.+3. `Env` is parameterized by type variable `m` which is going to be the+application monad.++The next step is to define an instance of the `HasLog` typeclass for the `Env`+data type. This instance will specify how to get and update the `LogAction`+stored inside the environment.++```haskell+instance HasLog (Env m) Message m where+ getLogAction :: Env m -> LogAction m Message+ getLogAction = envLogAction+ {-# INLINE getLogAction #-}++ setLogAction :: LogAction m Message -> Env m -> Env m+ setLogAction newLogAction env = env { envLogAction = newLogAction }+ {-# INLINE setLogAction #-}+```++That's it! `co-log` requires very little boilerplate.++## Application monad++Now let's define our application monad:++```haskell+newtype App a = App+ { unApp :: ReaderT (Env App) IO a+ } deriving newtype (Functor, Applicative, Monad, MonadIO, MonadReader (Env App))+```++This monad stores `Env` parameterized by the monad itself in its context.+Nothing special is required here to tell the monad how to use the logger.++## Example++`co-log` relies on the tagless final technique for writing functions. So you+define your monadic actions with the `WithLog` constraint that allows you to+perform logging:++```haskell+example :: WithLog env Message m => m ()+example = do+ log D "First message..."+ log I "Second message..."+```++The `WithLog` constraint has three type parameters: the application environment,+the type of the message and the monad. Function `log` takes two parameters:+the logger severity and the log message's text.++## Running example++Now we are ready to execute this action.++First, let's create an example environment:++```haskell+simpleEnv :: Env App+simpleEnv = Env+ { envServerPort = 8081+ , envLogAction = richMessageAction+ }+```++Then we need to define a function that performs actions of type `App`:++```haskell+runApp :: Env App -> App a -> IO a+runApp env app = runReaderT (unApp app) env+```++Putting it all together, we can specialize the `WithLog` constraint to our+`App` monad and run our example.++```haskell+main :: IO ()+main = runApp simpleEnv example+```++And the output will look like this:++