on master help sign in
Merge remote-tracking branch 'upstream/master' into issue-10-use-implicit-parameter-callstacks
commitb1e516a4028f4d8d751497bd32f989b1fdaf3f18 authorAlfredo Di Napoli <alfredo.dinapoli@gmail.com> dateMon 11 Apr 2016, 18:44 (11 years ago) parent8aa357a614d866
10 files changed+190−22
.travis.yml+6−5 katip-elasticsearch/katip-elasticsearch.cabal+1 katip/examples/example.hs+3−2 katip/examples/example_lens.hs+3−2 katip/katip.cabal+1 katip/src/Katip.hs+100−7 katip/src/Katip/Core.hs+20−6 katip/src/Katip/Monadic.hs+24 katip/test/Katip/Tests.hs+4 stack-7.8.yaml+28
.travis.yml+6−5
@@ -14,9 +14,10 @@ addons:
1414# change flags or use --stack-yaml to point to a different file.
1515env:
1616- ARGS=""
17−- ARGS="--resolver lts-3"
18−- ARGS="--resolver lts"
19−- ARGS="--resolver nightly"
17+- ARGS="--stack-yaml=stack-7.8.yaml"
18+- ARGS="--resolver=lts-3"
19+- ARGS="--resolver=lts"
20+- ARGS="--resolver=nightly"
2021
2122before_install:
2223# Download and unpack the stack executable
@@ -35,9 +36,9 @@ install:
3536# around some quirks in Travis's terminal implementation.
3637script:
3738 - stack $ARGS setup
38− - stack $ARGS --no-terminal test --haddock --no-haddock-deps
39+ - stack $ARGS test $BUILDFLAGS --no-terminal --haddock --no-haddock-deps
3940 - stack $ARGS bench
40− - stack $ARGS build
41+ - stack $ARGS build $BUILDFLAGS
4142 - for f in katip/examples/*.hs; do stack $ARGS ghc -- -Wall -Werror $f -o /dev/null; done
4243 - stack $ARGS sdist
4344
katip-elasticsearch/katip-elasticsearch.cabal+1
@@ -15,6 +15,7 @@ extra-source-files:
1515 changelog.md
1616 bench/Main.hs
1717 test/Main.hs
18+tested-with: GHC == 7.8.4, GHC== 7.10.3
1819
1920flag lib-Werror
2021 default: False
katip/examples/example.hs+3−2
@@ -9,6 +9,7 @@ module Main
99
1010
1111-------------------------------------------------------------------------------
12+import qualified Control.Applicative as A
1213import Control.Monad.Reader
1314import Data.Aeson
1415import Data.Monoid as M
@@ -22,7 +23,7 @@ import Katip
2223-- lens_example for a slightly cleaner and more general pattern.
2324main :: IO ()
2425main = do
25− le <- initLogEnv "main" "production"
26+ le <- initLogEnv "MyApp" "production"
2627 -- We'll set up a scribe that logs to stdout and will only log item
2728 -- fields permitted for Verbosity 2 and will throw out Debug
2829 -- messages entirely. Note that katip provides facilities like
@@ -77,7 +78,7 @@ data MyState = MyState {
7778-------------------------------------------------------------------------------
7879newtype MyStack m a = MyStack {
7980 unStack :: ReaderT MyState m a
80− } deriving (MonadReader MyState, Functor, Applicative, Monad, MonadIO)
81+ } deriving (MonadReader MyState, Functor, A.Applicative, Monad, MonadIO)
8182
8283
8384instance (MonadIO m) => Katip (MyStack m) where
katip/examples/example_lens.hs+3−2
@@ -9,6 +9,7 @@ module Main
99
1010
1111-------------------------------------------------------------------------------
12+import Control.Applicative as A
1213import Control.Lens hiding ((.=))
1314import Control.Monad.Reader
1415import Data.Aeson
@@ -38,7 +39,7 @@ makeClassy ''MyState
3839-- lens_example for a slightly cleaner and more general pattern.
3940main :: IO ()
4041main = do
41− le <- initLogEnv "main" "production"
42+ le <- initLogEnv "MyApp" "production"
4243 -- We'll set up a scribe that logs to stdout and will only log item
4344 -- fields permitted for Verbosity 2 and will throw out Debug
4445 -- messages entirely. Note that katip provides facilities like
@@ -85,7 +86,7 @@ confrabulateWidgets = return ()
8586-------------------------------------------------------------------------------
8687newtype MyStack m a = MyStack {
8788 unStack :: ReaderT MyState m a
88− } deriving (MonadReader MyState, Functor, Applicative, Monad, MonadIO)
89+ } deriving (MonadReader MyState, Functor, A.Applicative, Monad, MonadIO)
8990
9091
9192instance (MonadIO m) => Katip (MyStack m) where
katip/katip.cabal+1
@@ -23,6 +23,7 @@ extra-source-files:
2323 test/Main.hs
2424 test/Katip/Tests.hs
2525 test/Katip/Tests/Scribes/Handle.hs
26+tested-with: GHC == 7.8.4, GHC== 7.10.3
2627
2728source-repository head
2829 type: git
katip/src/Katip.hs+100−7
@@ -26,9 +26,7 @@ module Katip
2626 (
2727
2828 -- * Framework Types
29−
30− Katip (..)
31− , Namespace (..)
29+ Namespace (..)
3230 , Environment (..)
3331 , Severity (..)
3432 , renderSeverity
@@ -41,9 +39,6 @@ module Katip
4139 , PayloadSelection (..)
4240 , Scribe (..)
4341 , LogEnv (..)
44− , KatipContext(..)
45− , AnyLogContext
46− , LogContexts, liftPayload
4742 , SimpleLogPayload, sl
4843
4944 -- ** @lens@-compatible Lenses
@@ -60,7 +55,7 @@ module Katip
6055 , itemLoc
6156 , logEnvHost
6257 , logEnvPid
63− , logEnvNs
58+ , logEnvApp
6459 , logEnvEnv
6560 , logEnvTimer
6661 , logEnvScribes
@@ -79,15 +74,23 @@ module Katip
7974 , LogStr (..)
8075 , logStr, ls, showLS
8176
77+ -- ** 'Katip' LoggingFunctions
78+ -- $katiplogging
79+ , Katip (..)
8280 , logF
8381 , logMsg
8482 , logT
8583 , logItem
8684 , logException
85+ -- ** 'KatipContext' Logging Functions
86+ -- $katipcontextlogging
87+ , KatipContext (..)
8788 , logFM
8889 , logTM
8990 , logItemM
9091 , logExceptionM
92+ , AnyLogContext
93+ , LogContexts, liftPayload
9194
9295 -- * Included Scribes
9396 , mkHandleScribe
@@ -101,6 +104,8 @@ module Katip
101104 -- * KatipContextT - Utility transformer that provides Katip and KatipContext instances
102105 , KatipContextT
103106 , runKatipContextT
107+ , katipAddNamespace
108+ , katipAddContext
104109 ) where
105110
106111-------------------------------------------------------------------------------
@@ -108,3 +113,91 @@ import Katip.Core
108113import Katip.Monadic
109114import Katip.Scribes.Handle
110115-------------------------------------------------------------------------------
116+
117+
118+{- $katiplogging
119+
120+ These logging functions use the basic 'Katip' constraint and thus
121+will require varying degrees of explicit detail such as 'Namespace'
122+and individual log items to be passed in. These can be described as
123+the primitives of Katip logging. If you find yourself making multiple
124+log statements within a logical logging context for your app, you may
125+want to look into the 'KatipContext' family of logging functions like
126+'logFM' and 'logTM'. 'KatipContext' in most applications should be
127+considered the default. Here's an example of the pain point:
128+
129+@
130+doDatabaseThings = do
131+ connId <- getConnectionId
132+ logF (ConnectionIDContext connId) "database" InfoS "Doing database stuff"
133+ \-\- ...
134+ logF (ConnectionIDContext connId) "database" InfoS "Wow, passing in the same context is getting tedious"
135+@
136+
137+Another pain point to look out for is nesting actions that log in
138+eachother. Let's say you were writing a web app. You want to capture
139+some detail such as the user's ID in the logs, but you also want that
140+info to show up in doDatabaseThings' logs so you can associate those
141+two pieces of information:
142+
143+
144+@
145+webRequestHandler = do
146+ uid <- getUserId
147+ logF (UserIDContext uid) "web" InfoS "Starting web request"
148+ doDatabaseThings
149+@
150+
151+In the above example, doDatabaseThings would overwrite that
152+UderIDContext with its own context and namespace. Sometimes this is
153+what you want and that's why 'logF' and other functions which only
154+require 'Katip' exist. If you are interested in combining log
155+contexts and namespaces, see 'KatipContext'.
156+-}
157+
158+
159+{- $katipcontextlogging
160+
161+ These logging functions use the 'KatipContext' constraint which is a
162+superclass of 'Katip' that also has a mechanism for keeping track of
163+the current context and namespace. This means a few things:
164+
165+1. Functions that use 'KatipContext' like 'logFM' and 'logTM' do not
166+require you to pass in 'LogItem's or 'Namespaces', they pull them from
167+the monadic environment.
168+
169+2. It becomes easy to add functions which add namespaces and/or
170+contexts to the current stack of them. You can (and should) make that
171+action scoped to a monadic action so that when it finishes, the
172+previous context and namespace will be automatically restored.
173+
174+
175+'KatipContextT' provides a simple, 'ReaderT'-based implementation of
176+the 'KatipContext' typeclass, and provides 'katipAddContext' and
177+'katipAddNamespace' functions to append to the context for the
178+duration of a block:
179+
180+
181+@
182+main = do
183+ le <- initLogEnv "MyApp" "production"
184+ \-\- set up scribes here
185+ runKatipContext le () "main" $ do
186+ katipAddNamespace "nextlevel" $ do
187+ $(logTM) InfoS "Logs here will have namespace MyApp.main.nextlevel"
188+
189+ katipAddContext TrivialContext $ do
190+ $(logTM) InfoS "Logs here will have context from TrivialContext"
191+
192+ katipAddContext AnotherContext $ do
193+ $(logTM) InfoS "Logs here will have context from TrivialContext *merged with* context from AnotherContext!"
194+
195+ $(logTM) InfoS "Log context restored to () and namespace to MyApp.main"
196+@
197+
198+'katipAddNamespace' and 'katipAddContext' are one-liners, implemented
199+in terms of 'local' from 'MonadReader'. If you have a custom monad
200+transformer stack and want to add your own version of these, check out
201+<https://github.com/Soostone/katip/tree/master/katip/examples these
202+examples>.
203+-}
katip/src/Katip/Core.hs+20−6
@@ -489,12 +489,18 @@ permitItem sev i = _itemSeverity i >= sev
489489data LogEnv = LogEnv {
490490 _logEnvHost :: HostName
491491 , _logEnvPid :: ProcessID
492− , _logEnvNs :: Namespace
492+ , _logEnvApp :: Namespace
493+ -- ^ Name of application. This will typically never change. This
494+ -- field gets prepended to the namespace of your individual log
495+ -- messages. For example, if your app is MyApp and you write a log
496+ -- using "logItem" and the namespace "WebServer", the final
497+ -- namespace will be "MyApp.WebServer"
493498 , _logEnvEnv :: Environment
494499 , _logEnvTimer :: IO UTCTime
495500 -- ^ Action to fetch the timestamp. You can use something like
496501 -- 'AutoUpdate' for high volume logs but note that this may cause
497− -- some output forms to display logs out of order.
502+ -- some output forms to display logs out of order. Alternatively,
503+ -- you could just use 'getCurrentTime'.
498504 , _logEnvScribes :: M.Map Text Scribe
499505 }
500506makeLenses ''LogEnv
@@ -553,8 +559,16 @@ clearScribes = logEnvScribes .~ mempty
553559
554560
555561-------------------------------------------------------------------------------
556−-- | Monads where katip logging actions can be performed
557−class MonadIO m => Katip m where
562+-- | Monads where katip logging actions can be performed. Katip is the
563+-- most basic logging monad. You will typically use this directly if
564+-- you either don't want to use namespaces/contexts heavily or if you
565+-- want to pass in specific contexts and/or namespaces at each log site.
566+--
567+-- For something more powerful, look at the docs for 'KatipContext',
568+-- which keeps a namespace and merged context. You can write simple
569+-- functions that add additional namespacing and merges additional
570+-- context on the fly.
571+class MonadIO m => Katip m where
558572 getLogEnv :: m LogEnv
559573
560574
@@ -629,7 +643,7 @@ logItem a ns loc sev msg = do
629643 LogEnv{..} <- getLogEnv
630644 liftIO $ do
631645 item <- Item
632− <$> pure _logEnvNs
646+ <$> pure _logEnvApp
633647 <*> pure _logEnvEnv
634648 <*> pure sev
635649 <*> (mkThreadIdText <$> myThreadId)
@@ -638,7 +652,7 @@ logItem a ns loc sev msg = do
638652 <*> pure a
639653 <*> pure msg
640654 <*> _logEnvTimer
641− <*> pure (_logEnvNs <> ns)
655+ <*> pure (_logEnvApp <> ns)
642656 <*> pure loc
643657 FT.forM_ (M.elems _logEnvScribes) $ \ (Scribe h) -> h item
644658
katip/src/Katip/Monadic.hs+24
@@ -29,6 +29,8 @@ module Katip.Monadic
2929 -- * KatipContextT - Utility transformer that provides Katip and KatipContext instances
3030 , KatipContextT(..)
3131 , runKatipContextT
32+ , katipAddNamespace
33+ , katipAddContext
3234 , KatipContextTState(..)
3335 ) where
3436
@@ -306,3 +308,25 @@ runKatipContextT :: (LogItem c) => LogEnv -> c -> Namespace -> KatipContextT m a
306308runKatipContextT le ctx ns = flip runReaderT lts . unKatipContextT
307309 where
308310 lts = KatipContextTState le (liftPayload ctx) ns
311+
312+
313+-------------------------------------------------------------------------------
314+katipAddNamespace
315+ :: (Monad m)
316+ => Namespace
317+ -> KatipContextT m a
318+ -> KatipContextT m a
319+katipAddNamespace ns (KatipContextT f) =
320+ KatipContextT (local (\r -> r { ltsNamespace = (ltsNamespace r) <> ns}) f)
321+
322+
323+-------------------------------------------------------------------------------
324+katipAddContext
325+ :: ( LogItem i
326+ , Monad m
327+ )
328+ => i
329+ -> KatipContextT m a
330+ -> KatipContextT m a
331+katipAddContext i (KatipContextT f) =
332+ KatipContextT (local (\r -> r { ltsContext = (ltsContext r) <> liftPayload i}) f)
katip/test/Katip/Tests.hs+4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE GeneralizedNewtypeDeriving #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE RecordWildCards #-}
@@ -122,6 +123,9 @@ deriving instance Arbitrary Namespace
122123deriving instance Arbitrary Environment
123124deriving instance Arbitrary ThreadIdText
124125deriving instance Arbitrary CPid
126+#if !MIN_VERSION_base(4, 8, 0)
127+deriving instance Eq Loc
128+#endif
125129deriving instance Eq LogStr
126130deriving instance (Eq a) => Eq (Item a)
127131
stack-7.8.yamlnew file+28
@@ -0,0 +1,28 @@
1+resolver: lts-2.22
2+packages:
3+ - katip
4+ - katip-elasticsearch
5+extra-deps:
6+ - bloodhound-0.11.0.0
7+ - string-conv-0.1
8+ - aeson-0.11.1.0
9+ - criterion-1.1.0.0
10+ - attoparsec-0.13.0.1
11+ - rng-utils-0.2.1
12+ - retry-0.7.1
13+ - tasty-0.11.0.2
14+ - tagged-0.8.3
15+ - fail-4.9.0.0
16+ # just for 7.8/lts-2
17+ - microlens-th-0.3.0.1
18+ - microlens-0.4.2.0
19+ - time-1.5.0.1
20+ - lens-aeson-1.0.0.5
21+ - time-locale-compat-0.1.1.1
22+flags:
23+ katip:
24+ lib-Werror: true
25+ katip-elasticsearch:
26+ lib-Werror: true
27+ time-locale-compat:
28+ old-locale: false