on master help sign in
26 files changed+462−267
since splitsnapshots
unifiedsplit
.gitignore+1 .travis.yml+8−11 katip-datadog/README.md+3−5 katip-datadog/changelog.md+6−1 katip-datadog/katip-datadog.cabal+2−1 katip-datadog/src/Katip/Scribes/Datadog/TCP.hs+1−1 katip-elasticsearch/bench/Main.hs+3−3 katip-elasticsearch/changelog.md+21 katip-elasticsearch/docker-compose.yml+10 katip-elasticsearch/examples/example.hs+1−1 katip-elasticsearch/katip-elasticsearch.cabal+15−18 katip-elasticsearch/src/Katip/Scribes/ElasticSearch.hs+5 katip-elasticsearch/src/Katip/Scribes/ElasticSearch/Internal.hs+18−7 katip-elasticsearch/test/Main.hs+23−7 katip-logzio/README.md−4 katip-logzio/changelog.md+8−1 katip-logzio/katip-logzio.cabal+6−3 katip-logzio/src/Katip/Scribes/LogzIO/HTTPS.hs+172−152 katip-logzio/test/Katip/Tests/Scribes/LogzIO/HTTPS.hs+18 katip/README.md+1−1 katip/changelog.md+37 katip/katip.cabal+22−22 katip/src/Katip.hs+3−1 katip/src/Katip/Core.hs+45−19 katip/src/Katip/Monadic.hs+28−6 stack.yaml+5−3
.gitignore+1
@@ -7,3 +7,4 @@ TAGS
77*.hi
88*.dyn_o
99*.dyn_hi
10+stack.yaml.lock
.travis.yml+8−11
@@ -9,23 +9,19 @@ addons:
99 apt:
1010 packages:
1111 - libgmp-dev
12− - oracle-java8-installer
1312
1413# The different configurations we want to test. You could also do things like
1514# change flags or use --stack-yaml to point to a different file.
1615matrix:
1716 include:
18− - env: ARGS="--resolver=lts-8" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
19− - env: ARGS="--resolver=lts-9" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
20− - env: ARGS="--resolver=lts-10" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
21− - env: ARGS="--resolver=lts-11" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
22− - env: ARGS="--resolver=lts-12" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
23− - env: ARGS="--resolver=nightly" ESVERSION=5.5.0 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m" JAVA_HOME=/usr/lib/jvm/java-8-oracle
24− - env: ARGS="--resolver=nightly" ESVERSION=6.2.2 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m" JAVA_HOME=/usr/lib/jvm/java-8-oracle
25− # nightlies may fail from time to time
17+ - env: ARGS="--resolver=lts-16" ESVERSION=5.5.0 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
18+ - env: ARGS="--resolver=lts-16" ESVERSION=6.2.2 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
19+ - env: ARGS="--resolver=nightly" ESVERSION=5.5.0 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
20+ - env: ARGS="--resolver=nightly" ESVERSION=6.2.2 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
21+ # nightlies may fail usually due to lagging dependencies
2622 allow_failures:
27− - env: ARGS="--resolver=nightly" ESVERSION=5.5.0 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m" JAVA_HOME=/usr/lib/jvm/java-8-oracle
28− - env: ARGS="--resolver=nightly" ESVERSION=6.2.2 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m" JAVA_HOME=/usr/lib/jvm/java-8-oracle
23+ - env: ARGS="--resolver=nightly" ESVERSION=5.5.0 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
24+ - env: ARGS="--resolver=nightly" ESVERSION=6.2.2 ESURL=https://artifacts.elastic.co/downloads/elasticsearch ESTESTARGS="--es-version 5" ES_JAVA_OPTS="-Xms500m -Xmx750m"
2925
3026before_install:
3127# Download and unpack the stack executable
@@ -38,6 +34,7 @@ install:
3834 - tar xzf elasticsearch-$ESVERSION.tar.gz
3935 # set up a repo for snapshot testing. Required in ES >= 1.6
4036 - echo "path.repo = [\"/tmp\"]" >> ./elasticsearch-$ESVERSION/elasticsearch.yml
37+ - java -version
4138 - ./elasticsearch-$ESVERSION/bin/elasticsearch &
4239 # Bloodhound seems to take a while to build and can sometimes stall out the build when travis detects no output.
4340
katip-datadog/README.md+3−5
@@ -1,8 +1,6 @@
11# Katip Datadog [![Build Status](https://travis-ci.org/Soostone/katip.svg?branch=master)](https://travis-ci.org/Soostone/katip)
22
33katip-datadog is a scribe for the Katip logging framework that sends
4−structured logs to the Datadog logging service.
5−
6−## Warning
7−
8−This is an unreleased library and is not yet production-ready.
4+structured logs to the Datadog logging service. It supports both
5+directly sending to the ingestion API and through a locally installed
6+datadog agent.
katip-datadog/changelog.md+6−1
@@ -1,2 +1,7 @@
1−Unreleased
1+0.2.0.0
22==========
3+* Remove import of deprecated Network module
4+
5+0.1.0.0
6+==========
7+* Initial release
katip-datadog/katip-datadog.cabal+2−1
@@ -1,5 +1,6 @@
11name: katip-datadog
2−version: 0.0.1.0
2+version: 0.2.0.0
3+synopsis: Datadog scribe for the Katip logging framework
34description: See README.md for more details.
45license: BSD3
56license-file: LICENSE
katip-datadog/src/Katip/Scribes/Datadog/TCP.hs+1−1
@@ -33,8 +33,8 @@ import qualified Data.Text.Lazy.Builder as B
3333import Data.Time (NominalDiffTime)
3434import Katip
3535import Katip.Core (LocJs (..))
36−import qualified Network as Net
3736import qualified Network.Connection as C
37+import qualified Network.Socket as Net
3838import qualified System.Posix.Types as POSIX
3939-------------------------------------------------------------------------------
4040
katip-elasticsearch/bench/Main.hs+3−3
@@ -15,11 +15,11 @@ import qualified Data.HashMap.Strict as HM
1515import Data.Proxy (Proxy (..))
1616import System.Random
1717import qualified Data.Text as T
18−import Database.V1.Bloodhound.Types
18+import Database.Bloodhound.Types
1919import Numeric
2020-------------------------------------------------------------------------------
2121import Katip.Scribes.ElasticSearch
22−import Katip.Scribes.ElasticSearch.Internal (ESV1)
22+import Katip.Scribes.ElasticSearch.Internal (ESV5)
2323-------------------------------------------------------------------------------
2424
2525main :: IO ()
@@ -34,7 +34,7 @@ main = do
3434mkDocIdBenchmark :: Benchmark
3535mkDocIdBenchmark = bgroup "mkDocId"
3636 [
37− bench "mkDocId (randomIO)" $ nfIO (mkDocId (Proxy :: Proxy ESV1))
37+ bench "mkDocId (randomIO)" $ nfIO (mkDocId (Proxy :: Proxy ESV5))
3838 , bench "mkDocId' (shared )" $ nfIO mkDocId'
3939 ]
4040
katip-elasticsearch/changelog.md+21
@@ -1,3 +1,24 @@
1+0.7.0.0
2+=======
3+* Make compatible with unreleased bloodhound 0.17
4+* Deprecate use of ES version 1 which has been removed from bloodhound
5+ 0.17. All users should move over to ESV5 which should work for
6+ versions 5 and up.
7+* Default configuration to ESV5
8+* Add deprecation warnings for ESV1. Support for ESV1 will be removed
9+ in the future.
10+
11+0.6.0.0
12+=======
13+* Update to katip-0.8.0.0 `PermitFunc` convention. To update, for
14+ example, if you were passing `InfoS` to `mkEsScribe` to filter
15+ severities, instead you should pass `(permitItem InfoS)`.
16+* Update examples to add necessary type signature for the default
17+ scribe config.
18+* Bugfix: the default error retry policy was much more rapid than
19+ documented.
20+* Internally switch to safe-exceptions from encolosed-exceptions.
21+
1220.5.1.1
223=======
324* Loosen katip dep
katip-elasticsearch/docker-compose.ymlnew file+10
@@ -0,0 +1,10 @@
1+version: "3.7"
2+services:
3+ # https://hub.docker.com/_/elasticsearch
4+ elasticsearch:
5+ image: elasticsearch:5-alpine
6+ ports:
7+ - target: 9200
8+ published: 9200
9+ protocol: tcp
10+ mode: host
katip-elasticsearch/examples/example.hs+1−1
@@ -6,7 +6,7 @@ module Main
66
77-------------------------------------------------------------------------------
88import Control.Exception
9−import Database.V5.Bloodhound
9+import Database.Bloodhound
1010import Network.HTTP.Client
1111-------------------------------------------------------------------------------
1212import Katip
katip-elasticsearch/katip-elasticsearch.cabal+15−18
@@ -1,7 +1,7 @@
11name: katip-elasticsearch
22synopsis: ElasticSearch scribe for the Katip logging framework.
33description: See README.md for more details.
4−version: 0.6.0.0
4+version: 0.7.0.0
55license: BSD3
66license-file: LICENSE
77author: Ozgun Ataman, Michael Xavier
@@ -35,23 +35,23 @@ library
3535 Katip.Scribes.ElasticSearch.Internal
3636 build-depends:
3737 base >=4.6 && <5
38− , katip >= 0.2.0.0 && < 0.9
39− , bloodhound >= 0.13.0.0 && < 0.17
40− , uuid >= 1.3.12 && < 1.4
38+ , katip >= 0.8.0.0
39+ , bloodhound >= 0.13.0.0
40+ , uuid >= 1.3.12
4141 , aeson >=0.6
42− , stm >= 2.4.3 && < 2.6
43− , stm-chans >= 3.0.0.2 && < 3.1
44− , async >= 2.0.1.0 && < 3.0
42+ , stm >= 2.4.3
43+ , stm-chans >= 3.0.0.2
44+ , async >= 2.0.1.0
4545 , safe-exceptions >= 0.1.0.0
46− , http-client >= 0.3 && < 0.6
47− , text >= 0.11 && < 1.3
48− , retry >= 0.7 && < 0.8
46+ , http-client >= 0.3
47+ , text >= 0.11
48+ , retry >= 0.7
4949 , exceptions
50− , scientific >= 0.3.0.0 && < 0.4
51− , unordered-containers >= 0.1.0.0 && < 0.3
52− , transformers >= 0.2 && < 0.6
53− , http-types >= 0.8 && < 0.13
54− , time >= 1 && < 1.9
50+ , scientific >= 0.3.0.0
51+ , unordered-containers >= 0.1.0.0
52+ , transformers >= 0.2
53+ , http-types >= 0.8
54+ , time >= 1
5555 , bytestring
5656 , semigroups
5757 hs-source-dirs: src
@@ -108,7 +108,4 @@ test-suite test
108108 , bytestring
109109 , tagged
110110
111− if flag(lib-Werror)
112− ghc-options: -Wall -Werror
113−
114111 ghc-options: -threaded -rtsopts
katip-elasticsearch/src/Katip/Scribes/ElasticSearch.hs+5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12-- | Includes a scribe that can be used to log structured, JSON log
23-- messages to ElasticSearch. These logs can be explored easily using
34-- <https://www.elastic.co/products/kibana kibana> or your tool of
@@ -67,12 +68,16 @@ module Katip.Scribes.ElasticSearch
6768 , essIndexSettings
6869 , essIndexSharding
6970 , defaultEsScribeCfg
71+#if !MIN_VERSION_bloodhound(0,17,0)
7072 , defaultEsScribeCfgV1
73+#endif
7174 , defaultEsScribeCfgV5
7275 -- ** Version-Proxied APIS
7376 -- $versionproxies
7477 , defaultEsScribeCfg'
78+#if !MIN_VERSION_bloodhound(0,17,0)
7579 , ESV1
80+#endif
7681 , ESV5
7782 -- * Utilities
7883 , mkDocId
katip-elasticsearch/src/Katip/Scribes/ElasticSearch/Internal.hs+18−7
@@ -28,7 +28,7 @@ import Control.Retry (RetryPolicy,
2828import Data.Aeson
2929import Data.ByteString.Lazy (ByteString)
3030import Data.List.NonEmpty (NonEmpty (..))
31−import Data.Monoid ((<>))
31+import Data.Monoid as Monoid
3232import Data.Text (Text)
3333import qualified Data.Text as T
3434import qualified Data.Text.Encoding as T
@@ -37,8 +37,12 @@ import Data.Time.Calendar.WeekDate
3737import Data.Typeable as Typeable
3838import Data.UUID
3939import qualified Data.UUID.V4 as UUID4
40+#if MIN_VERSION_bloodhound(0,17,0)
41+import qualified Database.Bloodhound as V5
42+#else
4043import qualified Database.V1.Bloodhound as V1
4144import qualified Database.V5.Bloodhound as V5
45+#endif
4246import Network.HTTP.Client
4347import Network.HTTP.Types.Status
4448import Text.Printf (printf)
@@ -95,7 +99,7 @@ data EsScribeCfg v = EsScribeCfg {
9599-- * DailyIndexSharding
96100defaultEsScribeCfg' :: ESVersion v => proxy v -> EsScribeCfg v
97101defaultEsScribeCfg' prx = EsScribeCfg {
98− essRetryPolicy = exponentialBackoff 25000 <> limitRetries 5
102+ essRetryPolicy = exponentialBackoff 25000 Monoid.<> limitRetries 5
99103 , essQueueSize = EsQueueSize 1000
100104 , essPoolSize = EsPoolSize 2
101105 , essAnnotateTypes = False
@@ -104,19 +108,22 @@ defaultEsScribeCfg' prx = EsScribeCfg {
104108 }
105109
106110
111+
112+
107113-------------------------------------------------------------------------------
108−-- | Alias of 'defaultEsScribeCfgV1' to minimize API
114+-- | Alias of 'defaultEsScribeCfgV5' to minimize API
109115-- breakage. Previous versions of katip-elasticsearch only supported
110−-- ES version 1.
111−defaultEsScribeCfg :: EsScribeCfg ESV1
112−defaultEsScribeCfg = defaultEsScribeCfgV1
116+-- ES version 1 and defaulted to it.
117+defaultEsScribeCfg :: EsScribeCfg ESV5
118+defaultEsScribeCfg = defaultEsScribeCfgV5
113119
114120
115121-------------------------------------------------------------------------------
122+#if !MIN_VERSION_bloodhound(0,17,0)
116123-- | EsScribeCfg that will use ElasticSearch V1
117124defaultEsScribeCfgV1 :: EsScribeCfg ESV1
118125defaultEsScribeCfgV1 = defaultEsScribeCfg' (Typeable.Proxy :: Typeable.Proxy ESV1)
119−
126+#endif
120127
121128-------------------------------------------------------------------------------
122129-- | EsScribeCfg that will use ElasticSearch V5
@@ -484,7 +491,10 @@ class ESVersion v where
484491
485492
486493
494+#if !MIN_VERSION_bloodhound(0,17,0)
487495data ESV1 = ESV1
496+{-# DEPRECATED ESV1 "ESV1 is deprecated and removed in bloodhound >= 0.17.0" #-}
497+
488498
489499instance ESVersion ESV1 where
490500 type BHEnv ESV1 = V1.BHEnv
@@ -524,6 +534,7 @@ instance ESVersion ESV1 where
524534 [ "type" .= String "string"
525535 , "index" .= String "analyzed"
526536 ]
537+#endif
527538
528539
529540data ESV5 = ESV5
katip-elasticsearch/test/Main.hs+23−7
@@ -34,8 +34,12 @@ import Data.Time
3434import Data.Time.Calendar.WeekDate
3535import Data.Typeable as Typeable
3636import qualified Data.Vector as V
37+#if MIN_VERSION_bloodhound(0,17,0)
38+import qualified Database.Bloodhound as V5
39+#else
3740import qualified Database.V1.Bloodhound as V1
3841import qualified Database.V5.Bloodhound as V5
42+#endif
3943import Network.HTTP.Client
4044import Network.HTTP.Types.Status
4145import Test.QuickCheck.Instances ()
@@ -54,8 +58,10 @@ main :: IO ()
5458main = defaultMainWithIngredients ings $ askOption $ \vers -> testGroup "katip-elasticsearch"
5559 [
5660 case vers of
57− TestV1 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV1)
58− TestV5 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV5)
61+#if !MIN_VERSION_bloodhound(0,17,0)
62+ TestV1 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV1)
63+#endif
64+ TestV5 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV5)
5965 , typeAnnotatedTests
6066 , roundToSundayTests
6167 ]
@@ -64,18 +70,26 @@ main = defaultMainWithIngredients ings $ askOption $ \vers -> testGroup "katip-e
6470
6571
6672-------------------------------------------------------------------------------
67−data TestWithESVersion = TestV1
68− | TestV5
69− deriving (Typeable)
73+data TestWithESVersion = TestV5
74+#if !MIN_VERSION_bloodhound(0,17,0)
75+ | TestV1
76+#endif
77+ deriving (Typeable)
7078
7179
7280instance IsOption TestWithESVersion where
73− defaultValue = TestV1
81+ defaultValue = TestV5
82+#if !MIN_VERSION_bloodhound(0,17,0)
7483 parseValue "1" = Just TestV1
84+#endif
7585 parseValue "5" = Just TestV5
7686 parseValue _ = Nothing
7787 optionName = Tagged "es-version"
78− optionHelp = Tagged "Version of ES to test against, either 1 or 5, defaulting to 1."
88+#if MIN_VERSION_bloodhound(0,17,0)
89+ optionHelp = Tagged "Version of ES to test against, either 1 or 5, defaulting to 5."
90+#else
91+ optionHelp = Tagged "Version of ES to test against, only v5 is supported, but should work for higher versions."
92+#endif
7993
8094
8195class ESVersion v => TestESVersion v where
@@ -101,6 +115,7 @@ class ESVersion v => TestESVersion v where
101115 searchByIndex :: proxy v -> IndexName v -> Search v -> BH v IO (Response ByteString)
102116
103117
118+#if !MIN_VERSION_bloodhound(0,17,0)
104119instance TestESVersion ESV1 where
105120 type Server ESV1 = V1.Server
106121 toServer _ = V1.Server
@@ -122,6 +137,7 @@ instance TestESVersion ESV1 where
122137 refreshIndex _ = V1.refreshIndex
123138 withBH _ = V1.withBH
124139 searchByIndex _ = V1.searchByIndex
140+#endif
125141
126142
127143instance TestESVersion ESV5 where
katip-logzio/README.md−4
@@ -2,7 +2,3 @@
22
33katip-logzio is a scribe for the Katip logging framework that sends
44structured logs to the logz.io centralized logging platform.
5−
6−## Warning
7−
8−This is an unreleased library and is not yet production-ready.
katip-logzio/changelog.md+8−1
@@ -1,2 +1,9 @@
1−Unreleased
1+0.1.1.0
2+=======
3+* Fixed bug where on scribe close, any items left in the buffer that
4+ hadn't timed out or been flushed already would be dropped rather
5+ than flushed. All users are encouraged to upgrade.
6+
7+0.1.0.0
28==========
9+* Initial release
katip-logzio/katip-logzio.cabal+6−3
@@ -1,5 +1,6 @@
11name: katip-logzio
2−version: 0.0.1.0
2+version: 0.1.1.0
3+synopsis: Logz.IO scribe for the Katip logging framework
34description: See README.md for more details.
45license: BSD3
56license-file: LICENSE
@@ -47,10 +48,12 @@ library
4748 , http-types
4849 , text
4950 , bytestring
51+ , scientific
52+ , stm-chans >= 2.0.0
5053 hs-source-dirs: src
5154 default-language: Haskell2010
5255 hs-source-dirs: src
53− ghc-options: -Wall -j -Wall -Wnoncanonical-monad-instances
56+ ghc-options: -Wall -Wall -Wnoncanonical-monad-instances
5457 if flag(lib-Werror)
5558 ghc-options: -Werror
5659
@@ -86,6 +89,6 @@ test-suite test
8689 , uri-bytestring
8790 , warp
8891 , http-types
89− ghc-options: -j -Wall -threaded -rtsopts -with-rtsopts=-N -Wnoncanonical-monad-instances
92+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -Wnoncanonical-monad-instances
9093 if flag(lib-Werror)
9194 ghc-options: -Werror
katip-logzio/src/Katip/Scribes/LogzIO/HTTPS.hs+172−152
@@ -1,4 +1,5 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE GADTs #-}
23{-# LANGUAGE GeneralizedNewtypeDeriving #-}
34{-# LANGUAGE OverloadedStrings #-}
45{-# LANGUAGE RankNTypes #-}
@@ -38,31 +39,34 @@ module Katip.Scribes.LogzIO.HTTPS
3839
3940-------------------------------------------------------------------------------
4041import Control.Applicative
41−import qualified Control.Concurrent.Async as Async
42−import qualified Control.Concurrent.STM as STM
43−import qualified Control.Error as E
44−import qualified Control.Exception.Safe as EX
45−import qualified Control.Retry as Retry
46−import qualified Data.Aeson as A
47−import qualified Data.ByteString.Builder as BB
48−import qualified Data.ByteString.Lazy as LBS
49−import qualified Data.ByteString.Lazy.Char8 as LBS8
50−import qualified Data.HashMap.Strict as HM
42+import qualified Control.Concurrent.Async as Async
43+import qualified Control.Concurrent.STM as STM
44+import qualified Control.Concurrent.STM.TBMQueue as STM
45+import qualified Control.Error as E
46+import qualified Control.Exception.Safe as EX
47+import Control.Monad
48+import qualified Control.Retry as Retry
49+import qualified Data.Aeson as A
50+import qualified Data.ByteString.Builder as BB
51+import qualified Data.ByteString.Lazy as LBS
52+import qualified Data.ByteString.Lazy.Char8 as LBS8
53+import qualified Data.HashMap.Strict as HM
5154import Data.Int
52−import Data.String (IsString)
53−import qualified Data.Text as T
54−import qualified Data.Text.Encoding as TE
55−import qualified Data.Text.Lazy as TL
56−import qualified Data.Text.Lazy.Builder as TB
57−import qualified Data.Time as Time
58−import qualified Katip as K
59−import Katip.Core (LocJs (..))
60−import qualified Network.HTTP.Client as HTTP
61−import qualified Network.HTTP.Client.TLS as HTTPS
62−import qualified Network.HTTP.Types as HTypes
63−import qualified System.Posix.Types as POSIX
64−import qualified URI.ByteString as URIBS
65−-------------------------------------------------------------------------------
55+import qualified Data.Scientific as Scientific
56+import Data.Semigroup as Semigroup
57+import Data.String (IsString)
58+import qualified Data.Text as T
59+import qualified Data.Text.Encoding as TE
60+import qualified Data.Text.Lazy as TL
61+import qualified Data.Text.Lazy.Builder as TB
62+import qualified Data.Time as Time
63+import qualified Katip as K
64+import Katip.Core (LocJs (..))
65+import qualified Network.HTTP.Client as HTTP
66+import qualified Network.HTTP.Client.TLS as HTTPS
67+import qualified Network.HTTP.Types as HTypes
68+import qualified System.Posix.Types as POSIX
69+import qualified URI.ByteString as URIBS
6670-------------------------------------------------------------------------------
6771
6872
@@ -196,7 +200,7 @@ httpPort = URIBS.Port 8070
196200-- | A reasonable retry policy: exponential backoff with 25ms base
197201-- delay up to 5 retries, for a total cumulative delay of 775ms.
198202defaultRetryPolicy :: (Monad m) => Retry.RetryPolicyM m
199−defaultRetryPolicy = Retry.exponentialBackoff 25000 <> Retry.limitRetries 5
203+defaultRetryPolicy = Retry.exponentialBackoff 25000 `mappend` Retry.limitRetries 5
200204
201205-------------------------------------------------------------------------------
202206mkLogzIOScribe
@@ -205,132 +209,115 @@ mkLogzIOScribe
205209 -> K.Verbosity
206210 -> IO K.Scribe
207211mkLogzIOScribe config permitItem verbosity = do
208− -- Accumulating buffer for each item
209− bufferState <- STM.newTVarIO (mempty :: BulkBuffer)
210− -- Single-slot TMVar when something is ready to write. Katip buffers
211− -- for us upstream so we can simplify shutdown and flush guarantees
212− -- by synchronously writing when we need to.
213− readyMVar <- STM.newEmptyTMVarIO :: IO (STM.TMVar BulkBuffer)
214−
215− -- We create a TVar that is set to ShutDown when its time to stop
216− killSwitch <- STM.newTVarIO Continue
217−
218− -- Create a mutable ref to whether the timer has expired. This lets
219− -- us replace the timer when its time to start timing again. We
220− -- reset the timer __after__ a write goes out, not as soon as it expires
221− timerRef <- STM.newTVarIO =<< STM.registerDelay itemBufferTimeoutMicros
212+ -- This size is actually somewhat arbitrary. We're just making sure
213+ -- it isn't infinite so we don't consume the whole backlog right
214+ -- away and take up lots of memory.. Katip above us does bounded
215+ -- buffering and load-shedding when there's too much of a
216+ -- backlog. Our writes are blocking to apply backpressure up to
217+ -- katip. This value just holds onto values temporarily while we
218+ -- concatenate them into a buffer.
219+ ingestionQueue <- STM.newTBMQueueIO (itemBufferSize * 10)
220+
221+ let newTimer = STM.registerDelay itemBufferTimeoutMicros
222+ timerRef <- STM.newTVarIO =<< newTimer
222223
223224 -- Set up a connection manager for requests
224225 mgr <- case scheme of
225226 HTTPS -> HTTPS.newTlsManager
226227 HTTP -> HTTP.newManager HTTP.defaultManagerSettings
227228
228− -- In STM: resolve an action with the buffers
229− let processLogAction :: LogAction BulkBuffer -> STM.STM ()
230− processLogAction logAction = case logAction of
231− -- No write needed right now
232− Buffered !newBuffer -> STM.writeTVar bufferState newBuffer
233− -- Time to flush and put excess in the next buffer
234− FlushNow !toFlush !newBuffer -> do
235− STM.writeTVar bufferState newBuffer
236− STM.putTMVar readyMVar toFlush
237−
238− -- Recompute the new buffer state from a new log item and take action
239− let push :: (K.LogItem a) => K.Item a -> STM.STM ()
240− push !logItem = do
241− !curBuffer <- STM.readTVar bufferState
242− processLogAction (bufferItem itemBufferSize verbosity logItem curBuffer)
243−
244−
245− -- A transaction that retries until its time to shutdown
246− let waitShutdown :: STM.STM ()
247− waitShutdown = do
248− killStatus <- STM.readTVar killSwitch
249− STM.check (killStatus == ShutDown)
250−
251− -- Retry transaction until timer has expired. When it does, take action on the buffer.
252− let waitTimer :: STM.STM ()
253− waitTimer = do
254− -- get the timer we'll be using
255− timer <- STM.readTVar timerRef
256− -- do not proceed until its ready
257− timerExpired <- STM.readTVar timer
258− STM.check timerExpired
259− -- do not wake again until this message is out the door
260− STM.writeTVar timer False
261− -- we waited long enough, grab the current buffer
262− !curBuffer <- STM.readTVar bufferState
263− -- and tell it to flush right now
264− processLogAction (forceFlush curBuffer)
265−
266− -- run the timer in a loop until its time to shut down
267− let timedFlushLoop :: IO ()
268− timedFlushLoop = do
269− res <- STM.atomically $
270− raceAlt
271− waitShutdown
272− waitTimer
229+ -- An STM transaction that will return true when writes are stopped
230+ -- and backlog is emptied.
231+ let workExhausted :: STM.STM Bool
232+ workExhausted = (&&)
233+ <$> STM.isClosedTBMQueue ingestionQueue
234+ <*> STM.isEmptyTBMQueue ingestionQueue
235+ -- Block until there's no more work
236+ let waitWorkExhausted :: STM.STM ()
237+ waitWorkExhausted = STM.check =<< workExhausted
238+ let pop :: STM.STM (Tick AnyLogItem)
239+ pop = maybe WorkExhausted NewItem <$> STM.readTBMQueue ingestionQueue
240+
241+ let timeExpired :: STM.STM (Tick a)
242+ timeExpired = do
243+ isExpired <- STM.readTVar =<< STM.readTVar timerRef
244+ STM.check isExpired
245+ pure TimeExpired
246+
247+ -- Circular transaction that checks for completion of work, time
248+ -- expiration, or new events.
249+ let nextTick :: STM.STM (Tick AnyLogItem)
250+ nextTick =
251+ timeExpired <|>
252+ pop <|>
253+ (WorkExhausted <$ waitWorkExhausted)
254+
255+ -- Blocking push. This applies backpressure upstream to katip, which does its own buffering
256+ let push :: AnyLogItem -> STM.STM ()
257+ push = void . STM.writeTBMQueue ingestionQueue
258+
259+ let sealQueue = STM.atomically (STM.closeTBMQueue ingestionQueue)
260+
261+ -- Replace the timer with a new one
262+ let resetTimer = STM.atomically . STM.writeTVar timerRef =<< newTimer
263+
264+ -- Send the buffer and then reset the timer
265+ let flush curBuffer = do
266+ res <- flushBuffer config mgr curBuffer
273267 case res of
274− Left () -> pure () -- exit loop
275− Right () -> timedFlushLoop -- wait for another timer or shutdown
276−
277− timedFlusher <- Async.async timedFlushLoop
278−
279− -- flush the buffer until its time to shutdown and we're out of items to log
280− let flushLoop :: IO ()
281− flushLoop = do
282− -- hold until something comes in to flush or we're told to stop. If we're told to stop but get a log first, we'll catch it on the next loop
283− readyBufferOrDie <- STM.atomically $
284− raceAlt
285− (STM.takeTMVar readyMVar)
286− waitShutdown
287− case readyBufferOrDie of
288− Right () -> pure () -- we caught shutdown before any new data arrived
289− -- There's some logs to write
290− Left readyBuffer -> do
291− -- flush in IO
292− res <- flushBuffer config mgr readyBuffer
293− case res of
294− Left ex -> onErrorSafe ex
295− Right () -> pure ()
296− -- reset the timeout before the next flush on each write
297− !newTimer <- STM.registerDelay itemBufferTimeoutMicros
298− STM.atomically $ do
299− STM.writeTVar timerRef newTimer
300− -- start over
301− flushLoop
302− flusher <- Async.async flushLoop
303−
304− -- Blocking call which sends a poison pill to the workers and waits
305− -- for them to exit, swallowing exceptions. This follows the
306− -- semantics that when katip calls the finalizer, no more log
307− -- entries will be sent.
308− let shutdown :: IO ()
309− shutdown = do
310− -- tell workers this is the last loop
311− STM.atomically (STM.writeTVar killSwitch ShutDown)
312− -- wait for workers to finish
313− _ <- Async.waitCatch timedFlusher
314− _ <- Async.waitCatch flusher
315− -- stop blocking
268+ Left e -> onErrorSafe e
269+ Right () -> pure ()
270+ resetTimer
271+
272+ let flushLoop :: BulkBuffer -> IO ()
273+ flushLoop curBuffer = do
274+ tick <- STM.atomically nextTick
275+ case tick of
276+ WorkExhausted -> do
277+ flush curBuffer -- flush what you've got
278+ pure () -- stop looping
279+ TimeExpired -> do
280+ flush curBuffer
281+ flushLoop mempty
282+ NewItem (AnyLogItem item) -> do
283+ case bufferItem (logzIOScribeConfiguration_bufferItems config) verbosity item curBuffer of
284+ Buffered newBuffer -> flushLoop newBuffer
285+ FlushNow flushThis newBuffer -> do
286+ flush flushThis
287+ flushLoop newBuffer
288+
289+ flushThread <- Async.async (flushLoop mempty)
290+
291+ let close = do
292+ sealQueue
293+ _ <- Async.waitCatch flushThread
316294 pure ()
317295
318−
319296 pure $ K.Scribe
320− { K.liPush = STM.atomically . push
321− , K.scribeFinalizer = shutdown
297+ { K.liPush = STM.atomically . push . AnyLogItem
298+ , K.scribeFinalizer = close
322299 , K.scribePermitItem = permitItem
323300 }
324301 where
325302 itemBufferSize = logzIOScribeConfiguration_bufferItems config
326303 itemBufferTimeoutMicros = ndtToMicros (logzIOScribeConfiguration_bufferTimeout config)
327304 scheme = logzIOScribeConfiguration_scheme config
328− -- should this be async?
329305 onErrorSafe ex = do
330306 _ <- EX.tryAny (logzIOScribeConfiguration_onError config ex)
331307 pure ()
332308
333309
310+data AnyLogItem where
311+ AnyLogItem :: K.LogItem a => K.Item a -> AnyLogItem
312+
313+
314+-------------------------------------------------------------------------------
315+data Tick a =
316+ TimeExpired
317+ | NewItem !a
318+ | WorkExhausted
319+
320+
334321-------------------------------------------------------------------------------
335322-- Match the native resolution of NominalDiffTime, which is excessive
336323-- for our needs
@@ -348,23 +335,6 @@ ndtToMicros t = round (((fromIntegral (ndtPicos t)) :: Double) / picosInMicro)
348335 picosInMicro = 10 ^ (3 :: Int)
349336
350337
351−-------------------------------------------------------------------------------
352−-- | An internal mode flag used to shut down worker
353−-- threads. Internally, we assume htere is no going back from
354−-- ShutDown.
355−data KillSwitch =
356− Continue
357− | ShutDown
358− deriving (Eq)
359−
360−
361−-------------------------------------------------------------------------------
362−-- | When applied to STM, it will try the left side first and if that
363−-- retries, the right, and if that retries, start from the beginning.
364−raceAlt :: (Alternative m) => m a -> m b -> m (Either a b)
365−raceAlt a b = (Left <$> a) <|> (Right <$> b)
366−
367−
368338-------------------------------------------------------------------------------
369339data LoggingError =
370340 URIError HTTP.HttpException
@@ -441,7 +411,7 @@ flushBuffer config mgr bulkBuffer
441411-------------------------------------------------------------------------------
442412newtype Bytes = Bytes
443413 { bytes :: Int64
444− } deriving (Show, Eq, Num, Ord)
414+ } deriving (Show, Eq, Num, Ord, Bounded)
445415
446416
447417-- | How big of a body can we send? The limit is defined
@@ -472,7 +442,7 @@ fullItemObject verbosity item = HM.fromList
472442 , "thread" A..= K.getThreadIdText (K._itemThread item)
473443 , "host" A..= K._itemHost item
474444 , "pid" A..= pidInt
475− , "data" A..= K.payloadObject verbosity (K._itemPayload item)
445+ , "data" A..= annotateKeys (K.payloadObject verbosity (K._itemPayload item))
476446 -- Slight deviation, logz.io uses "message" instead of "msg"
477447 , "message" A..= TB.toLazyText (K.unLogStr (K._itemMessage item))
478448 -- Another slight deviation, logz.io uses "@timestamp" instead of
@@ -482,7 +452,7 @@ fullItemObject verbosity item = HM.fromList
482452 -- past. They seem to support 3 decimal places of
483453 -- precision. Formatting like this requires time 1.8.0.2, which is
484454 -- reflected in the cabal file.
485− , "@timestamp" A..= A.String (T.pack (Time.formatTime Time.defaultTimeLocale "%Y-%m-%dT%H:%M:%03QZ" (K._itemTime item)))
455+ , "@timestamp" A..= A.String (T.pack (Time.formatTime Time.defaultTimeLocale "%Y-%m-%dT%H:%M:%S%03QZ" (K._itemTime item)))
486456 , "ns" A..= K._itemNamespace item
487457 , "loc" A..= (LocJs <$> K._itemLoc item)
488458 ]
@@ -543,7 +513,7 @@ data BulkBuffer = BulkBuffer
543513 }
544514
545515
546−instance Semigroup BulkBuffer where
516+instance Semigroup.Semigroup BulkBuffer where
547517 (BulkBuffer bytesUsedA bufferA itemCountA) <>
548518 (BulkBuffer bytesUsedB bufferB itemCountB) = BulkBuffer
549519 (bytesUsedA + bytesUsedB)
@@ -597,7 +567,7 @@ bufferItem' customMaxPayload customMaxItem maxItems verb item bulkBuffer =
597567 let (encodedLine, spaceNeeded) = renderLineTruncated' customMaxItem verb item
598568 newBytesUsed = bulkBuffer_bytesUsed bulkBuffer + spaceNeeded
599569 newItemCount = bulkBuffer_itemCount bulkBuffer + 1
600− in if newItemCount > maxItems || newBytesUsed > customMaxPayload
570+ in if newItemCount >= maxItems || newBytesUsed >= customMaxPayload
601571 then FlushNow
602572 bulkBuffer
603573 BulkBuffer
@@ -617,3 +587,53 @@ bufferItem' customMaxPayload customMaxItem maxItems verb item bulkBuffer =
617587-- will always return 'FlushNow' with an empty new buffer.
618588forceFlush :: (Monoid buf) => buf -> LogAction buf
619589forceFlush buf = FlushNow buf mempty
590+
591+
592+-------------------------------------------------------------------------------
593+-- Annotation borrowed from katip-elasticsearch. There are fixed
594+-- fields in katip logs which should stay the same type forever and
595+-- thus won't need annotation. However, any code in userland may
596+-- choose to add akey to their log's metadata with a type that's
597+-- incompatible with the mapping. If the first value that's picked up
598+-- restrictive (e.g. a long), subsequent values will be rejected. By
599+-- differentiating types by their name, this is guaranteed not to
600+-- happen.
601+
602+annotateValue :: A.Value -> A.Value
603+annotateValue (A.Object o) = A.Object (annotateKeys o)
604+annotateValue (A.Array a) = A.Array (annotateValue <$> a)
605+annotateValue x = x
606+
607+
608+annotateKeys :: A.Object -> A.Object
609+annotateKeys = HM.fromList . map go . HM.toList
610+ where
611+ go (k, A.Object o) = (k, A.Object (annotateKeys o))
612+ go (k, A.Array a) = (k, A.Array (annotateValue <$> a))
613+ go (k, s@(A.String _)) = (k <> stringAnn, s)
614+ go (k, n@(A.Number sci)) = if Scientific.isFloating sci
615+ then (k <> doubleAnn, n)
616+ else (k <> longAnn, n)
617+ go (k, b@(A.Bool _)) = (k <> booleanAnn, b)
618+ go (k, A.Null) = (k <> nullAnn, A.Null)
619+
620+
621+-------------------------------------------------------------------------------
622+-- Annotation Constants
623+-------------------------------------------------------------------------------
624+
625+
626+stringAnn :: T.Text
627+stringAnn = "::s"
628+
629+doubleAnn :: T.Text
630+doubleAnn = "::d"
631+
632+longAnn :: T.Text
633+longAnn = "::l"
634+
635+booleanAnn :: T.Text
636+booleanAnn = "::b"
637+
638+nullAnn :: T.Text
639+nullAnn = "::n"
katip-logzio/test/Katip/Tests/Scribes/LogzIO/HTTPS.hs+18
@@ -108,6 +108,15 @@ scribeTests = withLock $ \mkSem -> testGroup "scribe"
108108 case loggingError of
109109 BadToken -> pure ()
110110 _ -> assertFailure ("Expected BadToken error but got " <> show loggingError)
111+ , testCase "flushes all queued logs on close" $ do
112+ sem <- mkSem
113+ withServer sem $ \receivedMessages -> do
114+ withScribe (\cfg -> cfg { logzIOScribeConfiguration_bufferItems = 100, logzIOScribeConfiguration_bufferTimeout = 100}) $ \scribe -> do
115+ (liPush scribe) (genericLog "message 1")
116+ (liPush scribe) (genericLog "message 2")
117+ messages <- atomically (flushTQueue receivedMessages)
118+ let allLogs = receivedLog_message <$> mconcat (requestLog_logs <$> messages)
119+ allLogs @?= ["message 1", "message 2"]
111120 ]
112121 where
113122 second = 1000000
@@ -223,6 +232,15 @@ bufferItemTests = testGroup "bufferItem"
223232 case logAction of
224233 FlushNow _ newBuffer -> bulkBuffer_itemCount newBuffer === 1
225234 _ -> pure ()
235+ , testProperty "flushes when the buffer is exactly at the limit" $ property $ do
236+ maxItems <- forAll (Gen.int (Range.linear 1 20))
237+ item <- forAllWith showSimplePayloadItem genSimplePayloadItem
238+ bulkBuffer <- forAllWith inspectBulkBuffer ((\b -> b { bulkBuffer_itemCount = maxItems - 1 }) <$> genBulkBuffer)
239+ verbosity <- forAll genVerbosity
240+ let logAction = bufferItem' maxBound maxBound maxItems verbosity item bulkBuffer
241+ case logAction of
242+ FlushNow _ _ -> pure ()
243+ Buffered _ -> fail "Expected a FlushNow but got a Buffered"
226244 ]
227245 where
228246 assertFlushNow (FlushNow _ _) = pure ()
katip/README.md+1−1
@@ -16,7 +16,7 @@ Kâtip (pronounced kah-tip) is the Turkish word for scribe.
1616 add context that will be automatically merged in with existing log
1717 context.
1818
19−* *Easy to Integration:* Katip was designed to be easily integrated
19+* *Easy Integration:* Katip was designed to be easily integrated
2020 into existing monads. By using typeclasses for logging facilities,
2121 individual subsystems and even libraries can easily add their own
2222 namespacing and context without having any knowledge of their
katip/changelog.md+37
@@ -1,3 +1,40 @@
1+0.8.5.0
2+=======
3+* Add MonadResource instances [#121](https://github.com/Soostone/katip/pull/121)
4+
5+0.8.4.0
6+=======
7+* Add support for unliftio-core 0.2 while maintaining backwards-compatible support for 0.1
8+
9+0.8.3.0
10+=======
11+
12+* Add `logKatipItem` function and reimplement `logItem` to use it. [vlatkoB](https://github.com/vlatkoB)
13+
14+0.8.2.0
15+=======
16+* Add `MonadFail` instances for `base` >= 4.9.0.0 [Koray Al](https://github.com/korayal)
17+
18+0.8.1.0
19+=======
20+* Export `logLoc`. Credit to [Brian McKenna](https://github.com/puffnfresh)
21+
22+0.8.0.0
23+=======
24+* **Breaking change**: switch from severity based log level filtering to
25+ user-definable `PermitFunc`. To upgrade, any time you initialize one
26+ of the standard scribes, rather than providing a severity like
27+ `InfoS`, instead pass in `(permitItem InfoS)`. Credit to
28+ [vlatkoB](https://github.com/vlatkoB).
29+* Update some misformatted and outdated docs.
30+* Set lower bound of base to 4.9.0.0, the version shipped with GHC
31+ 8.0.2. Support for GHC versions older than that is removed.
32+* Update default formatter of Handle scribe to format pid as `[PID
33+ 1234]` instead of `[1234]` and `[ThreadId 1234]` instead of
34+ `[1234]`.
35+* Add missing `Bounded` instance for `Verbosity`. This allows you to
36+ easily enumerate all verbosities via `[minBound..maxBound]`.
37+
1380.7.0.0
239=======
340* Exclusively use HasCallstack for location reporting in errors. Credit to [Domen Kožar](https://github.com/domenkozar)
katip/katip.cabal+22−22
@@ -1,5 +1,5 @@
11name: katip
2−version: 0.8.0.0
2+version: 0.8.5.0
33synopsis: A structured logging framework.
44description:
55 Katip is a structured logging framework. See README.md for more details.
@@ -56,29 +56,29 @@ library
5656 build-depends: base >=4.9.0.0 && <5
5757 , aeson >=0.6
5858 , async < 3.0.0.0
59− , auto-update >= 0.1 && < 0.2
60− , bytestring >= 0.9 && < 0.11
61− , containers >=0.4 && <0.7
62− , either >= 4 && < 5.1
59+ , auto-update >= 0.1
60+ , bytestring >= 0.9
61+ , containers >=0.4
62+ , either >= 4
6363 , safe-exceptions >= 0.1.0.0
64− , hostname >=1.0 && <1.1
65− , old-locale >= 1.0 && < 1.1
66− , string-conv >= 0.1 && < 0.2
67− , template-haskell >= 2.8 && < 2.15
68− , text >= 0.11 && <1.3
69− , time >= 1 && < 1.9
70− , transformers >= 0.3 && < 0.6
64+ , hostname >=1.0
65+ , old-locale >= 1.0
66+ , string-conv >= 0.1
67+ , template-haskell >= 2.8
68+ , text >= 0.11
69+ , time >= 1
70+ , transformers >= 0.3
7171 , transformers-compat
72− , unordered-containers >= 0.2 && < 0.3
73− , monad-control >= 1.0 && < 1.1
74− , mtl >= 2.0 && < 2.3
75− , transformers-base >= 0.3 && < 0.6
76− , resourcet >= 1.1 && < 1.3
72+ , unordered-containers >= 0.2
73+ , monad-control >= 1.0
74+ , mtl >= 2.0
75+ , transformers-base >= 0.3
76+ , resourcet >= 1.1
7777 , scientific >= 0.3.3.0
78− , microlens >= 0.2.0.0 && < 0.5
79− , microlens-th >= 0.1.0.0 && < 0.5
78+ , microlens >= 0.2.0.0
79+ , microlens-th >= 0.1.0.0
8080 , semigroups
81− , unliftio-core >= 0.1 && < 0.2
81+ , unliftio-core >= 0.1
8282 , stm >= 2.4
8383
8484 hs-source-dirs: src
@@ -87,7 +87,7 @@ library
8787 if flag(lib-Werror)
8888 ghc-options: -Werror
8989 if os(windows)
90− build-depends: Win32 >=2.3 && <2.6
90+ build-depends: Win32 >=2.3 && <2.9
9191 exposed-modules: Katip.Compat
9292 else
9393 build-depends: unix >= 2.5 && <2.8
@@ -114,7 +114,7 @@ test-suite test
114114 , template-haskell
115115 , text
116116 , time
117− , time-locale-compat >= 0.1.0.1 && < 0.2
117+ , time-locale-compat >= 0.1.0.1
118118 , directory
119119 , regex-tdfa
120120 , unordered-containers
katip/src/Katip.hs+3−1
@@ -44,7 +44,7 @@
4444--
4545-- newtype App m a = App {
4646-- unApp :: ReaderT Config m a
47−-- } deriving (Functor, Applicative, Monad) -- more instances as needed
47+-- } deriving (Functor, Applicative, Monad, MonadIO, MonadReader Config) -- these are necessary
4848--
4949--
5050-- -- These instances get even easier with lenses!
@@ -159,7 +159,9 @@ module Katip
159159 , logF
160160 , logMsg
161161 , logT
162+ , logLoc
162163 , logItem
164+ , logKatipItem
163165 , logException
164166 -- ** 'KatipContext': Logging With Context
165167 -- $katipcontextlogging
katip/src/Katip/Core.hs+45−19
@@ -31,6 +31,9 @@ import qualified Control.Concurrent.STM.TBQueue as BQ
3131import Control.Exception.Safe
3232import Control.Monad (unless, void, when)
3333import Control.Monad.Base
34+#if MIN_VERSION_base(4, 9, 0)
35+import qualified Control.Monad.Fail as MF
36+#endif
3437import Control.Monad.IO.Class
3538import Control.Monad.IO.Unlift
3639import Control.Monad.Trans.Class
@@ -41,7 +44,8 @@ import Control.Monad.Trans.Either
4144import Control.Monad.Trans.Except
4245import Control.Monad.Trans.Maybe
4346import Control.Monad.Trans.Reader
44−import Control.Monad.Trans.Resource (ResourceT, transResourceT)
47+import Control.Monad.Trans.Resource (MonadResource, ResourceT,
48+ transResourceT)
4549import Control.Monad.Trans.RWS.Lazy (RWST, mapRWST)
4650import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
4751import Control.Monad.Trans.State.Lazy (StateT, mapStateT)
@@ -661,7 +665,7 @@ makeLenses ''LogEnv
661665
662666
663667-------------------------------------------------------------------------------
664−-- | Create a reasonable default InitLogEnv. Uses an 'AutoUdate' which
668+-- | Create a reasonable default InitLogEnv. Uses an 'AutoUpdate' which
665669-- updates the timer every 1ms. If you need even more timestamp
666670-- precision at the cost of performance, consider setting
667671-- '_logEnvTimer' with 'getCurrentTime'.
@@ -876,7 +880,8 @@ instance (Katip m) => Katip (ResourceT m) where
876880-- opposed to implementing 'Katip' for your monad.
877881newtype KatipT m a = KatipT { unKatipT :: ReaderT LogEnv m a }
878882 deriving ( Functor, Applicative, Monad, MonadIO
879− , MonadMask, MonadCatch, MonadThrow, MonadTrans, MonadBase b)
883+ , MonadMask, MonadCatch, MonadThrow, MonadResource, MonadTrans
884+ , MonadBase b)
880885
881886
882887instance MonadIO m => Katip (KatipT m) where
@@ -898,9 +903,20 @@ instance (MonadBaseControl b m) => MonadBaseControl b (KatipT m) where
898903 restoreM = defaultRestoreM
899904
900905instance MonadUnliftIO m => MonadUnliftIO (KatipT m) where
906+#if MIN_VERSION_unliftio_core(0, 2, 0)
907+ withRunInIO inner = KatipT $ ReaderT $ \le -> withRunInIO $ \run ->
908+ inner (run . runKatipT le)
909+#else
901910 askUnliftIO = KatipT $
902− withUnliftIO $ \u ->
903− pure (UnliftIO (unliftIO u . unKatipT))
911+ withUnliftIO $ \u ->
912+ pure (UnliftIO (unliftIO u . unKatipT))
913+#endif
914+
915+#if MIN_VERSION_base(4, 9, 0)
916+instance MF.MonadFail m => MF.MonadFail (KatipT m) where
917+ fail msg = lift (MF.fail msg)
918+ {-# INLINE fail #-}
919+#endif
904920
905921-------------------------------------------------------------------------------
906922-- | Execute 'KatipT' on a log env.
@@ -932,19 +948,29 @@ logItem
932948 -> m ()
933949logItem a ns loc sev msg = do
934950 LogEnv{..} <- getLogEnv
935− liftIO $ do
936− item <- Item
937− <$> pure _logEnvApp
938− <*> pure _logEnvEnv
939− <*> pure sev
940− <*> (mkThreadIdText <$> myThreadId)
941− <*> pure _logEnvHost
942− <*> pure _logEnvPid
943− <*> pure a
944− <*> pure msg
945− <*> _logEnvTimer
946− <*> pure (_logEnvApp <> ns)
947− <*> pure loc
951+ logKatipItem =<< liftIO
952+ (Item <$> pure _logEnvApp
953+ <*> pure _logEnvEnv
954+ <*> pure sev
955+ <*> (mkThreadIdText <$> myThreadId)
956+ <*> pure _logEnvHost
957+ <*> pure _logEnvPid
958+ <*> pure a
959+ <*> pure msg
960+ <*> _logEnvTimer
961+ <*> pure (_logEnvApp <> ns)
962+ <*> pure loc)
963+
964+-- | Log already constructed 'Item'. This is the lowest level function that other log*
965+-- functions use.
966+-- It can be useful when implementing centralised logging services.
967+logKatipItem
968+ :: (A.Applicative m, LogItem a, Katip m)
969+ => Item a
970+ -> m ()
971+logKatipItem item = do
972+ LogEnv{..} <- getLogEnv
973+ liftIO $
948974 FT.forM_ (M.elems _logEnvScribes) $ \ ScribeHandle {..} -> do
949975 whenM (scribePermitItem shScribe item) $
950976 void $ atomically (tryWriteTBQueue shChan (NewItem item))
@@ -993,7 +1019,7 @@ logException
9931019logException a ns sev action = action `catchAny` \e -> f e >> throwM e
9941020 where
9951021 f e = logF a ns sev (msg e)
996− msg e = ls (T.pack "An exception has occured: ") <> showLS e
1022+ msg e = ls (T.pack "An exception has occurred: ") <> showLS e
9971023
9981024
9991025-------------------------------------------------------------------------------
katip/src/Katip/Monadic.hs+28−6
@@ -44,6 +44,9 @@ import Control.Applicative
4444import Control.Exception.Safe
4545import Control.Monad.Base
4646import Control.Monad.Error.Class
47+#if MIN_VERSION_base(4, 9, 0)
48+import qualified Control.Monad.Fail as MF
49+#endif
4750import Control.Monad.IO.Class
4851import Control.Monad.IO.Unlift
4952import Control.Monad.Reader
@@ -55,7 +58,8 @@ import Control.Monad.Trans.Either (EitherT, mapEitherT)
5558import Control.Monad.Trans.Except (ExceptT, mapExceptT)
5659import Control.Monad.Trans.Identity (IdentityT, mapIdentityT)
5760import Control.Monad.Trans.Maybe (MaybeT, mapMaybeT)
58−import Control.Monad.Trans.Resource (ResourceT, transResourceT)
61+import Control.Monad.Trans.Resource (MonadResource,
62+ ResourceT, transResourceT)
5963import Control.Monad.Trans.RWS (RWST, mapRWST)
6064import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
6165import qualified Control.Monad.Trans.State.Strict as Strict (StateT, mapStateT)
@@ -312,7 +316,7 @@ logExceptionM
312316logExceptionM action sev = action `catchAny` \e -> f e >> throwM e
313317 where
314318 f e = logFM sev (msg e)
315− msg e = ls ("An exception has occured: " :: Text) Semi.<> showLS e
319+ msg e = ls ("An exception has occurred: " :: Text) Semi.<> showLS e
316320
317321
318322-------------------------------------------------------------------------------
@@ -346,6 +350,7 @@ newtype KatipContextT m a = KatipContextT {
346350 , MonadWriter w
347351 , MonadError e
348352 , MonadPlus
353+ , MonadResource
349354 , Alternative
350355 , MonadFix
351356 , MonadTrans
@@ -392,10 +397,21 @@ instance (MonadIO m) => KatipContext (KatipContextT m) where
392397 localKatipNamespace f (KatipContextT m) = KatipContextT $ local (\s -> s { ltsNamespace = f (ltsNamespace s)}) m
393398
394399instance MonadUnliftIO m => MonadUnliftIO (KatipContextT m) where
400+#if MIN_VERSION_unliftio_core(0, 2, 0)
401+ withRunInIO inner = KatipContextT $ ReaderT $ \lts -> withRunInIO $ \run ->
402+ inner (run . runKatipContextT (ltsLogEnv lts) (ltsContext lts) (ltsNamespace lts))
403+#else
395404 askUnliftIO = KatipContextT $
396− withUnliftIO $ \u ->
397− pure (UnliftIO (unliftIO u . unKatipContextT))
405+ withUnliftIO $ \u ->
406+ pure (UnliftIO (unliftIO u . unKatipContextT))
407+#endif
408+
398409
410+#if MIN_VERSION_base(4, 9, 0)
411+instance MF.MonadFail m => MF.MonadFail (KatipContextT m) where
412+ fail msg = lift (MF.fail msg)
413+ {-# INLINE fail #-}
414+#endif
399415
400416-------------------------------------------------------------------------------
401417runKatipContextT :: (LogItem c) => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
@@ -474,9 +490,15 @@ instance MonadBaseControl b m => MonadBaseControl b (NoLoggingT m) where
474490 restoreM = NoLoggingT . restoreM
475491
476492instance MonadUnliftIO m => MonadUnliftIO (NoLoggingT m) where
493+#if MIN_VERSION_unliftio_core(0, 2, 0)
494+ withRunInIO inner = NoLoggingT $ withRunInIO $ \run ->
495+ inner (run . runNoLoggingT)
496+#else
477497 askUnliftIO = NoLoggingT $
478− withUnliftIO $ \u ->
479− pure (UnliftIO (unliftIO u . runNoLoggingT))
498+ withUnliftIO $ \u ->
499+ pure (UnliftIO (unliftIO u . runNoLoggingT))
500+#endif
501+
480502
481503instance MonadIO m => Katip (NoLoggingT m) where
482504 getLogEnv = liftIO (initLogEnv "NoLoggingT" "no-logging")
stack.yaml+5−3
@@ -1,12 +1,14 @@
1−resolver: lts-12.26
1+resolver: lts-16.18
22packages:
33 - katip
44 - katip-elasticsearch
55 - katip-datadog
66 - katip-logzio
77extra-deps:
8− - bloodhound-0.16.0.0
9− - unliftio-core-0.1.2.0
8+ # ghc 8.8 support
9+ - github: wireapp/bloodhound
10+ commit: b409f52b518f20a4c20651b5893c31b7b85cb9b1
11+allow-newer: true
1012flags:
1113 katip:
1214 lib-Werror: true