on 4ff93dc help sign in
24 files changed+217−329
since splitsnapshots
unifiedsplit
.gitignore−1 .travis.yml+9−8 katip-datadog/changelog.md+1−6 katip-datadog/katip-datadog.cabal+1−1 katip-datadog/src/Katip/Scribes/Datadog/TCP.hs+1−1 katip-elasticsearch/bench/Main.hs+3−3 katip-elasticsearch/changelog.md−10 katip-elasticsearch/docker-compose.yml−10 katip-elasticsearch/examples/example.hs+1−1 katip-elasticsearch/katip-elasticsearch.cabal+4−1 katip-elasticsearch/src/Katip/Scribes/ElasticSearch.hs−5 katip-elasticsearch/src/Katip/Scribes/ElasticSearch/Internal.hs+7−18 katip-elasticsearch/test/Main.hs+7−23 katip-logzio/changelog.md+1−8 katip-logzio/katip-logzio.cabal+1−2 katip-logzio/src/Katip/Scribes/LogzIO/HTTPS.hs+148−116 katip-logzio/test/Katip/Tests/Scribes/LogzIO/HTTPS.hs+1−10 katip/README.md+1−1 katip/changelog.md−21 katip/katip.cabal+2−2 katip/src/Katip.hs+1−3 katip/src/Katip/Core.hs+19−45 katip/src/Katip/Monadic.hs+6−28 stack.yaml+3−5
.gitignore−1
@@ -7,4 +7,3 @@ TAGS
77*.hi
88*.dyn_o
99*.dyn_hi
10−stack.yaml.lock
.travis.yml+9−8
@@ -9,19 +9,21 @@ addons:
99 apt:
1010 packages:
1111 - libgmp-dev
12+ - oracle-java8-installer
1213
1314# The different configurations we want to test. You could also do things like
1415# change flags or use --stack-yaml to point to a different file.
1516matrix:
1617 include:
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
18+ - env: ARGS="--resolver=lts-10" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
19+ - env: ARGS="--resolver=lts-11" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
20+ - env: ARGS="--resolver=lts-12" ESVERSION=1.5.2 ESURL=https://download.elastic.co/elasticsearch/elasticsearch ESTESTARGS="--es-version 1"
21+ - 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
22+ - 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+ # nightlies may fail from time to time
2224 allow_failures:
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"
25+ - 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
26+ - 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
2527
2628before_install:
2729# Download and unpack the stack executable
@@ -34,7 +36,6 @@ install:
3436 - tar xzf elasticsearch-$ESVERSION.tar.gz
3537 # set up a repo for snapshot testing. Required in ES >= 1.6
3638 - echo "path.repo = [\"/tmp\"]" >> ./elasticsearch-$ESVERSION/elasticsearch.yml
37− - java -version
3839 - ./elasticsearch-$ESVERSION/bin/elasticsearch &
3940 # Bloodhound seems to take a while to build and can sometimes stall out the build when travis detects no output.
4041
katip-datadog/changelog.md+1−6
@@ -1,7 +1,2 @@
1−0.2.0.0
1+Unreleased
22==========
3−* Remove import of deprecated Network module
4−
5−0.1.0.0
6−==========
7−* Initial release
katip-datadog/katip-datadog.cabal+1−1
@@ -1,5 +1,5 @@
11name: katip-datadog
2−version: 0.2.0.0
2+version: 0.0.1.0
33synopsis: Datadog scribe for the Katip logging framework
44description: See README.md for more details.
55license: BSD3
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
3637import 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.Bloodhound.Types
18+import Database.V1.Bloodhound.Types
1919import Numeric
2020-------------------------------------------------------------------------------
2121import Katip.Scribes.ElasticSearch
22−import Katip.Scribes.ElasticSearch.Internal (ESV5)
22+import Katip.Scribes.ElasticSearch.Internal (ESV1)
2323-------------------------------------------------------------------------------
2424
2525main :: IO ()
@@ -34,7 +34,7 @@ main = do
3434mkDocIdBenchmark :: Benchmark
3535mkDocIdBenchmark = bgroup "mkDocId"
3636 [
37− bench "mkDocId (randomIO)" $ nfIO (mkDocId (Proxy :: Proxy ESV5))
37+ bench "mkDocId (randomIO)" $ nfIO (mkDocId (Proxy :: Proxy ESV1))
3838 , bench "mkDocId' (shared )" $ nfIO mkDocId'
3939 ]
4040
katip-elasticsearch/changelog.md−10
@@ -1,13 +1,3 @@
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−
1110.6.0.0
122=======
133* Update to katip-0.8.0.0 `PermitFunc` convention. To update, for
katip-elasticsearch/docker-compose.ymldeleted−10
@@ -1,10 +0,0 @@
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.Bloodhound
9+import Database.V5.Bloodhound
1010import Network.HTTP.Client
1111-------------------------------------------------------------------------------
1212import Katip
katip-elasticsearch/katip-elasticsearch.cabal+4−1
@@ -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.7.0.0
4+version: 0.6.0.0
55license: BSD3
66license-file: LICENSE
77author: Ozgun Ataman, Michael Xavier
@@ -108,4 +108,7 @@ test-suite test
108108 , bytestring
109109 , tagged
110110
111+ if flag(lib-Werror)
112+ ghc-options: -Wall -Werror
113+
111114 ghc-options: -threaded -rtsopts
katip-elasticsearch/src/Katip/Scribes/ElasticSearch.hs−5
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
21-- | Includes a scribe that can be used to log structured, JSON log
32-- messages to ElasticSearch. These logs can be explored easily using
43-- <https://www.elastic.co/products/kibana kibana> or your tool of
@@ -68,16 +67,12 @@ module Katip.Scribes.ElasticSearch
6867 , essIndexSettings
6968 , essIndexSharding
7069 , defaultEsScribeCfg
71−#if !MIN_VERSION_bloodhound(0,17,0)
7270 , defaultEsScribeCfgV1
73−#endif
7471 , defaultEsScribeCfgV5
7572 -- ** Version-Proxied APIS
7673 -- $versionproxies
7774 , defaultEsScribeCfg'
78−#if !MIN_VERSION_bloodhound(0,17,0)
7975 , ESV1
80−#endif
8176 , ESV5
8277 -- * Utilities
8378 , mkDocId
katip-elasticsearch/src/Katip/Scribes/ElasticSearch/Internal.hs+7−18
@@ -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 as Monoid
31+import Data.Monoid ((<>))
3232import Data.Text (Text)
3333import qualified Data.Text as T
3434import qualified Data.Text.Encoding as T
@@ -37,12 +37,8 @@ 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
4340import qualified Database.V1.Bloodhound as V1
4441import qualified Database.V5.Bloodhound as V5
45−#endif
4642import Network.HTTP.Client
4743import Network.HTTP.Types.Status
4844import Text.Printf (printf)
@@ -99,7 +95,7 @@ data EsScribeCfg v = EsScribeCfg {
9995-- * DailyIndexSharding
10096defaultEsScribeCfg' :: ESVersion v => proxy v -> EsScribeCfg v
10197defaultEsScribeCfg' prx = EsScribeCfg {
102− essRetryPolicy = exponentialBackoff 25000 Monoid.<> limitRetries 5
98+ essRetryPolicy = exponentialBackoff 25000 <> limitRetries 5
10399 , essQueueSize = EsQueueSize 1000
104100 , essPoolSize = EsPoolSize 2
105101 , essAnnotateTypes = False
@@ -108,22 +104,19 @@ defaultEsScribeCfg' prx = EsScribeCfg {
108104 }
109105
110106
111−
112−
113107-------------------------------------------------------------------------------
114−-- | Alias of 'defaultEsScribeCfgV5' to minimize API
108+-- | Alias of 'defaultEsScribeCfgV1' to minimize API
115109-- breakage. Previous versions of katip-elasticsearch only supported
116−-- ES version 1 and defaulted to it.
117−defaultEsScribeCfg :: EsScribeCfg ESV5
118−defaultEsScribeCfg = defaultEsScribeCfgV5
110+-- ES version 1.
111+defaultEsScribeCfg :: EsScribeCfg ESV1
112+defaultEsScribeCfg = defaultEsScribeCfgV1
119113
120114
121115-------------------------------------------------------------------------------
122−#if !MIN_VERSION_bloodhound(0,17,0)
123116-- | EsScribeCfg that will use ElasticSearch V1
124117defaultEsScribeCfgV1 :: EsScribeCfg ESV1
125118defaultEsScribeCfgV1 = defaultEsScribeCfg' (Typeable.Proxy :: Typeable.Proxy ESV1)
126−#endif
119+
127120
128121-------------------------------------------------------------------------------
129122-- | EsScribeCfg that will use ElasticSearch V5
@@ -491,10 +484,7 @@ class ESVersion v where
491484
492485
493486
494−#if !MIN_VERSION_bloodhound(0,17,0)
495487data ESV1 = ESV1
496−{-# DEPRECATED ESV1 "ESV1 is deprecated and removed in bloodhound >= 0.17.0" #-}
497−
498488
499489instance ESVersion ESV1 where
500490 type BHEnv ESV1 = V1.BHEnv
@@ -534,7 +524,6 @@ instance ESVersion ESV1 where
534524 [ "type" .= String "string"
535525 , "index" .= String "analyzed"
536526 ]
537−#endif
538527
539528
540529data ESV5 = ESV5
katip-elasticsearch/test/Main.hs+7−23
@@ -34,12 +34,8 @@ 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
4037import qualified Database.V1.Bloodhound as V1
4138import qualified Database.V5.Bloodhound as V5
42−#endif
4339import Network.HTTP.Client
4440import Network.HTTP.Types.Status
4541import Test.QuickCheck.Instances ()
@@ -58,10 +54,8 @@ main :: IO ()
5854main = defaultMainWithIngredients ings $ askOption $ \vers -> testGroup "katip-elasticsearch"
5955 [
6056 case vers of
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)
57+ TestV1 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV1)
58+ TestV5 -> esTests (Typeable.Proxy :: Typeable.Proxy ESV5)
6559 , typeAnnotatedTests
6660 , roundToSundayTests
6761 ]
@@ -70,26 +64,18 @@ main = defaultMainWithIngredients ings $ askOption $ \vers -> testGroup "katip-e
7064
7165
7266-------------------------------------------------------------------------------
73−data TestWithESVersion = TestV5
74−#if !MIN_VERSION_bloodhound(0,17,0)
75− | TestV1
76−#endif
77− deriving (Typeable)
67+data TestWithESVersion = TestV1
68+ | TestV5
69+ deriving (Typeable)
7870
7971
8072instance IsOption TestWithESVersion where
81− defaultValue = TestV5
82−#if !MIN_VERSION_bloodhound(0,17,0)
73+ defaultValue = TestV1
8374 parseValue "1" = Just TestV1
84−#endif
8575 parseValue "5" = Just TestV5
8676 parseValue _ = Nothing
8777 optionName = Tagged "es-version"
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
78+ optionHelp = Tagged "Version of ES to test against, either 1 or 5, defaulting to 1."
9379
9480
9581class ESVersion v => TestESVersion v where
@@ -115,7 +101,6 @@ class ESVersion v => TestESVersion v where
115101 searchByIndex :: proxy v -> IndexName v -> Search v -> BH v IO (Response ByteString)
116102
117103
118−#if !MIN_VERSION_bloodhound(0,17,0)
119104instance TestESVersion ESV1 where
120105 type Server ESV1 = V1.Server
121106 toServer _ = V1.Server
@@ -137,7 +122,6 @@ instance TestESVersion ESV1 where
137122 refreshIndex _ = V1.refreshIndex
138123 withBH _ = V1.withBH
139124 searchByIndex _ = V1.searchByIndex
140−#endif
141125
142126
143127instance TestESVersion ESV5 where
katip-logzio/changelog.md+1−8
@@ -1,9 +1,2 @@
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
1+Unreleased
82==========
9−* Initial release
katip-logzio/katip-logzio.cabal+1−2
@@ -1,5 +1,5 @@
11name: katip-logzio
2−version: 0.1.1.0
2+version: 0.0.1.0
33synopsis: Logz.IO scribe for the Katip logging framework
44description: See README.md for more details.
55license: BSD3
@@ -49,7 +49,6 @@ library
4949 , text
5050 , bytestring
5151 , scientific
52− , stm-chans >= 2.0.0
5352 hs-source-dirs: src
5453 default-language: Haskell2010
5554 hs-source-dirs: src
katip-logzio/src/Katip/Scribes/LogzIO/HTTPS.hs+148−116
@@ -1,5 +1,4 @@
11{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE GADTs #-}
32{-# LANGUAGE GeneralizedNewtypeDeriving #-}
43{-# LANGUAGE OverloadedStrings #-}
54{-# LANGUAGE RankNTypes #-}
@@ -39,34 +38,33 @@ module Katip.Scribes.LogzIO.HTTPS
3938
4039-------------------------------------------------------------------------------
4140import Control.Applicative
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
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
5451import Data.Int
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
52+import qualified Data.Scientific as Scientific
53+import Data.Semigroup as Semigroup
54+import Data.String (IsString)
55+import qualified Data.Text as T
56+import qualified Data.Text.Encoding as TE
57+import qualified Data.Text.Lazy as TL
58+import qualified Data.Text.Lazy.Builder as TB
59+import qualified Data.Time as Time
60+import qualified Katip as K
61+import Katip.Core (LocJs (..))
62+import qualified Network.HTTP.Client as HTTP
63+import qualified Network.HTTP.Client.TLS as HTTPS
64+import qualified Network.HTTP.Types as HTypes
65+import qualified System.Posix.Types as POSIX
66+import qualified URI.ByteString as URIBS
67+-------------------------------------------------------------------------------
7068-------------------------------------------------------------------------------
7169
7270
@@ -209,115 +207,132 @@ mkLogzIOScribe
209207 -> K.Verbosity
210208 -> IO K.Scribe
211209mkLogzIOScribe config permitItem verbosity = do
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
210+ -- Accumulating buffer for each item
211+ bufferState <- STM.newTVarIO (mempty :: BulkBuffer)
212+ -- Single-slot TMVar when something is ready to write. Katip buffers
213+ -- for us upstream so we can simplify shutdown and flush guarantees
214+ -- by synchronously writing when we need to.
215+ readyMVar <- STM.newEmptyTMVarIO :: IO (STM.TMVar BulkBuffer)
216+
217+ -- We create a TVar that is set to ShutDown when its time to stop
218+ killSwitch <- STM.newTVarIO Continue
219+
220+ -- Create a mutable ref to whether the timer has expired. This lets
221+ -- us replace the timer when its time to start timing again. We
222+ -- reset the timer __after__ a write goes out, not as soon as it expires
223+ timerRef <- STM.newTVarIO =<< STM.registerDelay itemBufferTimeoutMicros
223224
224225 -- Set up a connection manager for requests
225226 mgr <- case scheme of
226227 HTTPS -> HTTPS.newTlsManager
227228 HTTP -> HTTP.newManager HTTP.defaultManagerSettings
228229
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
230+ -- In STM: resolve an action with the buffers
231+ let processLogAction :: LogAction BulkBuffer -> STM.STM ()
232+ processLogAction logAction = case logAction of
233+ -- No write needed right now
234+ Buffered !newBuffer -> STM.writeTVar bufferState newBuffer
235+ -- Time to flush and put excess in the next buffer
236+ FlushNow !toFlush !newBuffer -> do
237+ STM.writeTVar bufferState newBuffer
238+ STM.putTMVar readyMVar toFlush
239+
240+ -- Recompute the new buffer state from a new log item and take action
241+ let push :: (K.LogItem a) => K.Item a -> STM.STM ()
242+ push !logItem = do
243+ !curBuffer <- STM.readTVar bufferState
244+ processLogAction (bufferItem itemBufferSize verbosity logItem curBuffer)
245+
246+
247+ -- A transaction that retries until its time to shutdown
248+ let waitShutdown :: STM.STM ()
249+ waitShutdown = do
250+ killStatus <- STM.readTVar killSwitch
251+ STM.check (killStatus == ShutDown)
252+
253+ -- Retry transaction until timer has expired. When it does, take action on the buffer.
254+ let waitTimer :: STM.STM ()
255+ waitTimer = do
256+ -- get the timer we'll be using
257+ timer <- STM.readTVar timerRef
258+ -- do not proceed until its ready
259+ timerExpired <- STM.readTVar timer
260+ STM.check timerExpired
261+ -- do not wake again until this message is out the door
262+ STM.writeTVar timer False
263+ -- we waited long enough, grab the current buffer
264+ !curBuffer <- STM.readTVar bufferState
265+ -- and tell it to flush right now
266+ processLogAction (forceFlush curBuffer)
267+
268+ -- run the timer in a loop until its time to shut down
269+ let timedFlushLoop :: IO ()
270+ timedFlushLoop = do
271+ res <- STM.atomically $
272+ raceAlt
273+ waitShutdown
274+ waitTimer
267275 case res of
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
276+ Left () -> pure () -- exit loop
277+ Right () -> timedFlushLoop -- wait for another timer or shutdown
278+
279+ timedFlusher <- Async.async timedFlushLoop
280+
281+ -- flush the buffer until its time to shutdown and we're out of items to log
282+ let flushLoop :: IO ()
283+ flushLoop = do
284+ -- 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
285+ readyBufferOrDie <- STM.atomically $
286+ raceAlt
287+ (STM.takeTMVar readyMVar)
288+ waitShutdown
289+ case readyBufferOrDie of
290+ Right () -> pure () -- we caught shutdown before any new data arrived
291+ -- There's some logs to write
292+ Left readyBuffer -> do
293+ -- flush in IO
294+ res <- flushBuffer config mgr readyBuffer
295+ case res of
296+ Left ex -> onErrorSafe ex
297+ Right () -> pure ()
298+ -- reset the timeout before the next flush on each write
299+ !newTimer <- STM.registerDelay itemBufferTimeoutMicros
300+ STM.atomically $ do
301+ STM.writeTVar timerRef newTimer
302+ -- start over
303+ flushLoop
304+ flusher <- Async.async flushLoop
305+
306+ -- Blocking call which sends a poison pill to the workers and waits
307+ -- for them to exit, swallowing exceptions. This follows the
308+ -- semantics that when katip calls the finalizer, no more log
309+ -- entries will be sent.
310+ let shutdown :: IO ()
311+ shutdown = do
312+ -- tell workers this is the last loop
313+ STM.atomically (STM.writeTVar killSwitch ShutDown)
314+ -- wait for workers to finish
315+ _ <- Async.waitCatch timedFlusher
316+ _ <- Async.waitCatch flusher
317+ -- stop blocking
294318 pure ()
295319
320+
296321 pure $ K.Scribe
297− { K.liPush = STM.atomically . push . AnyLogItem
298− , K.scribeFinalizer = close
322+ { K.liPush = STM.atomically . push
323+ , K.scribeFinalizer = shutdown
299324 , K.scribePermitItem = permitItem
300325 }
301326 where
302327 itemBufferSize = logzIOScribeConfiguration_bufferItems config
303328 itemBufferTimeoutMicros = ndtToMicros (logzIOScribeConfiguration_bufferTimeout config)
304329 scheme = logzIOScribeConfiguration_scheme config
330+ -- should this be async?
305331 onErrorSafe ex = do
306332 _ <- EX.tryAny (logzIOScribeConfiguration_onError config ex)
307333 pure ()
308334
309335
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−
321336-------------------------------------------------------------------------------
322337-- Match the native resolution of NominalDiffTime, which is excessive
323338-- for our needs
@@ -335,6 +350,23 @@ ndtToMicros t = round (((fromIntegral (ndtPicos t)) :: Double) / picosInMicro)
335350 picosInMicro = 10 ^ (3 :: Int)
336351
337352
353+-------------------------------------------------------------------------------
354+-- | An internal mode flag used to shut down worker
355+-- threads. Internally, we assume htere is no going back from
356+-- ShutDown.
357+data KillSwitch =
358+ Continue
359+ | ShutDown
360+ deriving (Eq)
361+
362+
363+-------------------------------------------------------------------------------
364+-- | When applied to STM, it will try the left side first and if that
365+-- retries, the right, and if that retries, start from the beginning.
366+raceAlt :: (Alternative m) => m a -> m b -> m (Either a b)
367+raceAlt a b = (Left <$> a) <|> (Right <$> b)
368+
369+
338370-------------------------------------------------------------------------------
339371data LoggingError =
340372 URIError HTTP.HttpException
katip-logzio/test/Katip/Tests/Scribes/LogzIO/HTTPS.hs+1−10
@@ -108,15 +108,6 @@ 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"]
120111 ]
121112 where
122113 second = 1000000
@@ -240,7 +231,7 @@ bufferItemTests = testGroup "bufferItem"
240231 let logAction = bufferItem' maxBound maxBound maxItems verbosity item bulkBuffer
241232 case logAction of
242233 FlushNow _ _ -> pure ()
243− Buffered _ -> fail "Expected a FlushNow but got a Buffered"
234+ Buffered _ -> fail "Expected a FlushNow but got a Buffered"
244235 ]
245236 where
246237 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 Integration:* Katip was designed to be easily integrated
19+* *Easy to 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−21
@@ -1,24 +1,3 @@
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−
2210.8.0.0
232=======
243* **Breaking change**: switch from severity based log level filtering to
katip/katip.cabal+2−2
@@ -1,5 +1,5 @@
11name: katip
2−version: 0.8.5.0
2+version: 0.8.0.0
33synopsis: A structured logging framework.
44description:
55 Katip is a structured logging framework. See README.md for more details.
@@ -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.9
90+ build-depends: Win32 >=2.3 && <2.6
9191 exposed-modules: Katip.Compat
9292 else
9393 build-depends: unix >= 2.5 && <2.8
katip/src/Katip.hs+1−3
@@ -44,7 +44,7 @@
4444--
4545-- newtype App m a = App {
4646-- unApp :: ReaderT Config m a
47−-- } deriving (Functor, Applicative, Monad, MonadIO, MonadReader Config) -- these are necessary
47+-- } deriving (Functor, Applicative, Monad) -- more instances as needed
4848--
4949--
5050-- -- These instances get even easier with lenses!
@@ -159,9 +159,7 @@ module Katip
159159 , logF
160160 , logMsg
161161 , logT
162− , logLoc
163162 , logItem
164− , logKatipItem
165163 , logException
166164 -- ** 'KatipContext': Logging With Context
167165 -- $katipcontextlogging
katip/src/Katip/Core.hs+19−45
@@ -31,9 +31,6 @@ 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
3734import Control.Monad.IO.Class
3835import Control.Monad.IO.Unlift
3936import Control.Monad.Trans.Class
@@ -44,8 +41,7 @@ import Control.Monad.Trans.Either
4441import Control.Monad.Trans.Except
4542import Control.Monad.Trans.Maybe
4643import Control.Monad.Trans.Reader
47−import Control.Monad.Trans.Resource (MonadResource, ResourceT,
48− transResourceT)
44+import Control.Monad.Trans.Resource (ResourceT, transResourceT)
4945import Control.Monad.Trans.RWS.Lazy (RWST, mapRWST)
5046import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
5147import Control.Monad.Trans.State.Lazy (StateT, mapStateT)
@@ -665,7 +661,7 @@ makeLenses ''LogEnv
665661
666662
667663-------------------------------------------------------------------------------
668−-- | Create a reasonable default InitLogEnv. Uses an 'AutoUpdate' which
664+-- | Create a reasonable default InitLogEnv. Uses an 'AutoUdate' which
669665-- updates the timer every 1ms. If you need even more timestamp
670666-- precision at the cost of performance, consider setting
671667-- '_logEnvTimer' with 'getCurrentTime'.
@@ -880,8 +876,7 @@ instance (Katip m) => Katip (ResourceT m) where
880876-- opposed to implementing 'Katip' for your monad.
881877newtype KatipT m a = KatipT { unKatipT :: ReaderT LogEnv m a }
882878 deriving ( Functor, Applicative, Monad, MonadIO
883− , MonadMask, MonadCatch, MonadThrow, MonadResource, MonadTrans
884− , MonadBase b)
879+ , MonadMask, MonadCatch, MonadThrow, MonadTrans, MonadBase b)
885880
886881
887882instance MonadIO m => Katip (KatipT m) where
@@ -903,20 +898,9 @@ instance (MonadBaseControl b m) => MonadBaseControl b (KatipT m) where
903898 restoreM = defaultRestoreM
904899
905900instance 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
910901 askUnliftIO = KatipT $
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
902+ withUnliftIO $ \u ->
903+ pure (UnliftIO (unliftIO u . unKatipT))
920904
921905-------------------------------------------------------------------------------
922906-- | Execute 'KatipT' on a log env.
@@ -948,29 +932,19 @@ logItem
948932 -> m ()
949933logItem a ns loc sev msg = do
950934 LogEnv{..} <- getLogEnv
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 $
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
974948 FT.forM_ (M.elems _logEnvScribes) $ \ ScribeHandle {..} -> do
975949 whenM (scribePermitItem shScribe item) $
976950 void $ atomically (tryWriteTBQueue shChan (NewItem item))
@@ -1019,7 +993,7 @@ logException
1019993logException a ns sev action = action `catchAny` \e -> f e >> throwM e
1020994 where
1021995 f e = logF a ns sev (msg e)
1022− msg e = ls (T.pack "An exception has occurred: ") <> showLS e
996+ msg e = ls (T.pack "An exception has occured: ") <> showLS e
1023997
1024998
1025999-------------------------------------------------------------------------------
katip/src/Katip/Monadic.hs+6−28
@@ -44,9 +44,6 @@ 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
5047import Control.Monad.IO.Class
5148import Control.Monad.IO.Unlift
5249import Control.Monad.Reader
@@ -58,8 +55,7 @@ import Control.Monad.Trans.Either (EitherT, mapEitherT)
5855import Control.Monad.Trans.Except (ExceptT, mapExceptT)
5956import Control.Monad.Trans.Identity (IdentityT, mapIdentityT)
6057import Control.Monad.Trans.Maybe (MaybeT, mapMaybeT)
61−import Control.Monad.Trans.Resource (MonadResource,
62− ResourceT, transResourceT)
58+import Control.Monad.Trans.Resource (ResourceT, transResourceT)
6359import Control.Monad.Trans.RWS (RWST, mapRWST)
6460import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST, mapRWST)
6561import qualified Control.Monad.Trans.State.Strict as Strict (StateT, mapStateT)
@@ -316,7 +312,7 @@ logExceptionM
316312logExceptionM action sev = action `catchAny` \e -> f e >> throwM e
317313 where
318314 f e = logFM sev (msg e)
319− msg e = ls ("An exception has occurred: " :: Text) Semi.<> showLS e
315+ msg e = ls ("An exception has occured: " :: Text) Semi.<> showLS e
320316
321317
322318-------------------------------------------------------------------------------
@@ -350,7 +346,6 @@ newtype KatipContextT m a = KatipContextT {
350346 , MonadWriter w
351347 , MonadError e
352348 , MonadPlus
353− , MonadResource
354349 , Alternative
355350 , MonadFix
356351 , MonadTrans
@@ -397,21 +392,10 @@ instance (MonadIO m) => KatipContext (KatipContextT m) where
397392 localKatipNamespace f (KatipContextT m) = KatipContextT $ local (\s -> s { ltsNamespace = f (ltsNamespace s)}) m
398393
399394instance 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
404395 askUnliftIO = KatipContextT $
405− withUnliftIO $ \u ->
406− pure (UnliftIO (unliftIO u . unKatipContextT))
407−#endif
408−
396+ withUnliftIO $ \u ->
397+ pure (UnliftIO (unliftIO u . unKatipContextT))
409398
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
415399
416400-------------------------------------------------------------------------------
417401runKatipContextT :: (LogItem c) => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
@@ -490,15 +474,9 @@ instance MonadBaseControl b m => MonadBaseControl b (NoLoggingT m) where
490474 restoreM = NoLoggingT . restoreM
491475
492476instance 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
497477 askUnliftIO = NoLoggingT $
498− withUnliftIO $ \u ->
499− pure (UnliftIO (unliftIO u . runNoLoggingT))
500−#endif
501−
478+ withUnliftIO $ \u ->
479+ pure (UnliftIO (unliftIO u . runNoLoggingT))
502480
503481instance MonadIO m => Katip (NoLoggingT m) where
504482 getLogEnv = liftIO (initLogEnv "NoLoggingT" "no-logging")
stack.yaml+3−5
@@ -1,14 +1,12 @@
1−resolver: lts-16.18
1+resolver: lts-12.26
22packages:
33 - katip
44 - katip-elasticsearch
55 - katip-datadog
66 - katip-logzio
77extra-deps:
8− # ghc 8.8 support
9− - github: wireapp/bloodhound
10− commit: b409f52b518f20a4c20651b5893c31b7b85cb9b1
11−allow-newer: true
8+ - bloodhound-0.16.0.0
9+ - unliftio-core-0.1.2.0
1210flags:
1311 katip:
1412 lib-Werror: true