Skip to content

Commit b875a0e

Browse files
committed
Add multi-package library.
1 parent e803870 commit b875a0e

File tree

4 files changed

+185
-141
lines changed

4 files changed

+185
-141
lines changed

cheops-logger.cabal

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,14 @@ name: cheops-logger
33
version: 0.0.1.0
44
synopsis: Structured logger implementation.
55
description:
6-
Implementation of a very simple structured logger.
7-
This logger is provides following functionality:
86

9-
* asynchronous background logging (using co-log-concurrent);
10-
* structured logging with katip like interface;
11-
* handle pattern approach that is compatible with other approaches
12-
for effect stucturing.
7+
The library implements of a very simple structured logging. This package provides
8+
a library that can be used in [co-log](https://hackage.haskell.org/package/co-log)
9+
ecosystem. It provides:
1310

14-
Entry tutorial can be found on GitHub Readme page.
15-
16-
Reference documentation can be found in "Cheops.Logger" module.
17-
18-
Internal module describe details and design choices.
19-
20-
This logger asynchronously emits json messages to the stdout, of the form,
21-
pretty-printed for convenience:
11+
* "Cheops.Logger.Structured" — API for adding structured context to the log messages
12+
* "Cheops.Logger.Internal.Writer" — efficient function for dumping logs in the
13+
following format.
2214

2315
@
2416
{ "namespace":"server.package"
@@ -34,6 +26,26 @@ description:
3426
}
3527
}
3628
@
29+
30+
== cheops-logger:instance
31+
32+
In addition the package provides an @cheops-logger:instance@ library that
33+
can be used in the application as-is. The library is provides following
34+
functionality:
35+
36+
* asynchronous background logging using [co-log-concurrent](https://hackage.haskell.org/package/co-log-concurrent);
37+
* configuration
38+
* optional metrics support
39+
40+
== References
41+
42+
Entry tutorial can be found on GitHub Readme page.
43+
44+
Reference documentation can be found in "Cheops.Logger" module.
45+
46+
Internal module describe details and design choices.
47+
48+
== Notes
3749

3850
The library allows to keep track and output additional user information ("data")
3951
with the messages. Implement fast and safe API for message output.
@@ -58,14 +70,13 @@ category: System
5870
build-type: Simple
5971
extra-source-files: ChangeLog.md
6072

61-
6273
library metrics-prometheus
6374
default-language: Haskell2010
6475
visibility: public
6576
exposed-modules:
6677
Cheops.Logger.Internal.Metric.Prometheus
6778
reexported-modules:
68-
Cheops.Logger.Internal.Metric.Prometheus as Cheops.Logger.Internal.Metrics
79+
Cheops.Logger.Internal.Metric.Prometheus as Cheops.Logger.Metrics
6980
hs-source-dirs: src
7081
default-extensions:
7182
OverloadedStrings
@@ -79,17 +90,36 @@ library metrics-noop
7990
visibility: public
8091
exposed-modules:
8192
Cheops.Logger.Internal.Metric.Noop
82-
reexported-modules:
83-
Cheops.Logger.Internal.Metric.Noop as Cheops.Logger.Internal.Metrics
8493
hs-source-dirs: src
8594
default-language: Haskell2010
8695
build-depends:
8796
base >= 4.11 && <5
8897

8998

90-
library
99+
library instance
100+
visibility: public
101+
default-language: Haskell2010
91102
exposed-modules:
92103
Cheops.Logger
104+
default-extensions:
105+
ImportQualifiedPost
106+
RecordWildCards
107+
OverloadedStrings
108+
hs-source-dirs:
109+
logger
110+
signatures: Cheops.Logger.Metrics
111+
build-depends:
112+
base >= 4.11 && <5
113+
, aeson ^>= 1.5
114+
, co-log-core
115+
, cheops-logger
116+
, co-log-concurrent ^>=0.5
117+
, stm ^>=2.5
118+
ghc-options: -Wall -Werror
119+
120+
library
121+
exposed-modules:
122+
Cheops.Logger.Structured
93123
Cheops.Logger.Internal.Structured
94124
Cheops.Logger.Internal.Writer
95125
default-extensions:
@@ -114,10 +144,7 @@ library
114144
, text ^>=1.2
115145
, containers ^>=0.6
116146
, co-log-core ^>=0.2
117-
, co-log-concurrent ^>=0.5
118147
, string-conv ^>=0.1
119-
, stm ^>=2.5
120-
signatures: Cheops.Logger.Internal.Metrics
121148
ghc-options: -Wall -Werror
122149
hs-source-dirs: src
123150
default-language: Haskell2010
@@ -128,6 +155,6 @@ executable Example
128155
main-is: Main.hs
129156
build-depends:
130157
base >=4.11 && <5,
131-
cheops-logger,
158+
cheops-logger:instance,
132159
cheops-logger:metrics-prometheus
133160
default-language: Haskell2010

src/Cheops/Logger.hs renamed to logger/Cheops/Logger.hs

Lines changed: 4 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -24,50 +24,23 @@
2424
module Cheops.Logger
2525
( -- * Initialization
2626
withLogger
27-
, emptyLogger
2827
, defCapacity
2928
, LoggerConfig(..)
30-
, LoggerEnv
31-
-- * High level
32-
-- ** Writing logs
33-
-- $writing-logs
34-
, ls
35-
, showLS
36-
, LogStr(..)
37-
-- $writing-helpers
38-
, logDebug
39-
, logNotice
40-
, logInfo
41-
, logErr
42-
, logWarn
43-
, logAlert
44-
, logCrit
45-
, logEmergency
46-
, Severity(..)
47-
-- ** Adding context
48-
-- $adding-context
49-
, addContext
50-
, addNamespace
51-
, sl
52-
-- * Low level
53-
, PushContext
54-
, logSay
29+
, module Cheops.Logger.Structured
5530
-- * Metrics support
5631
-- $metrics-support
5732
-- $setup
5833
) where
5934

60-
import Cheops.Logger.Internal.Metrics (flushLog, submitLog)
35+
import Cheops.Logger.Metrics (flushLog, submitLog)
6136
import Cheops.Logger.Internal.Structured
6237
import Cheops.Logger.Internal.Writer
38+
import Cheops.Logger.Structured
6339
import Colog.Concurrent
6440
import Colog.Concurrent.Internal
6541
import Colog.Core hiding (Severity, Info)
66-
import Control.Concurrent
6742
import Data.Aeson
6843
import System.IO
69-
import qualified Data.Sequence as Seq
70-
import qualified Data.Text as T
7144

7245
-- | Logger configuration
7346
data LoggerConfig = LoggerConfig
@@ -87,13 +60,6 @@ instance FromJSON LoggerConfig where
8760
n <- o .:? "disabled"
8861
pure $ LoggerConfig defCapacity n
8962

90-
-- | Logger environment, keeps internal Katip environment,
91-
-- current contexts (metadata), namespaces and minimal interesting
92-
-- severity and verbosity.
93-
data LoggerEnv = LoggerEnv
94-
{ action :: LogAction IO Message
95-
, context :: Seq.Seq Structured
96-
}
9763

9864
-- | Create logger and initialize it with defaults.
9965
withLogger
@@ -108,90 +74,11 @@ withLogger LoggerConfig{..} f
10874
(LogAction $ flushLog . feed)
10975
(hFlush stdout)
11076
$ \(LogAction log_action) ->
111-
f $ LoggerEnv
112-
(LogAction $ submitLog . log_action)
113-
Seq.Empty
77+
f $ mkLogger (LogAction $ submitLog . log_action)
11478
where
11579
LogAction feed = feedHandle stdout
11680

117-
-- | Internal logger function.
118-
logSay :: LoggerEnv -- ^ Logger handle.
119-
-> Severity -- ^ Message severity.
120-
-> LogStr -- ^ Message itself.
121-
-> IO ()
122-
logSay (LoggerEnv action context) lvl msg = do
123-
tid <- myThreadId
124-
unLogAction action $ Message lvl (mkThreadId tid) context msg
125-
126-
-- | Logger that does nothing. Useful for the testing purpose.
127-
emptyLogger :: LoggerEnv
128-
emptyLogger = LoggerEnv (LogAction $ \_ -> pure ()) Seq.empty
129-
130-
-- $adding-context
131-
--
132-
-- Messages in the library forms a stack, and you can attach 2 kinds of data to it:
133-
--
134-
-- 1. @namespace@ - a list of locations, that allows to tell that the component
135-
-- is it.
136-
-- 2. @context@ - context is a list of key-value pairs, where key is a text and
137-
-- a value is any JSON value.
138-
--
139-
-- When you attach that information to the 'LoggerContext' it will be added to
140-
-- each message that is written in that context. Allowing to analyze data in the
141-
-- external systems.
142-
--
143-
144-
-- | Helper to update context, by appending another item to the log.
145-
--
146-
-- @
147-
-- local ('addContext' ('sl' "key" "value")) $ do
148-
-- ...
149-
-- @
150-
addContext
151-
:: PushContext -- ^ New data to store
152-
-> LoggerEnv -- ^ Old context.
153-
-> LoggerEnv
154-
addContext (PushContext f) LoggerEnv{..} = LoggerEnv{context = f context, ..}
155-
156-
-- | Helper to extend current namespace by appending sub-namespace.
157-
--
158-
-- @
159-
-- local ('addNamespace' "subcomponent") $ do
160-
-- ...
161-
-- @
162-
addNamespace :: T.Text -> LoggerEnv -> LoggerEnv
163-
addNamespace ns LoggerEnv{..} = LoggerEnv{context=context Seq.|> Segment ns, ..}
164-
165-
-- $writing-logs
166-
-- Logs can we written using one of the following helpers. The general pattern is
167-
--
168-
-- @
169-
-- 'logDebug' logger "message"
170-
-- @
171-
--
172-
-- Messages has type 'LogStr'. This is an abstraction over a data-type for efficient
173-
-- log concatenation. Currently it uses 'Data.Text.Lazy.Builder' but it's an implementation
174-
-- detail and may change in the future.
175-
--
176-
-- 'LogStr' implements 'Data.String.IsString' class, so you can write constant strings
177-
-- without any boilerplate. For other types you should use 'ls' or 'showLS' names are
178-
-- taken from 'Katip' interface.
179-
180-
181-
-- $writing-helpers
182-
-- Library provides helper for each 'Severity' level.
18381

184-
logDebug, logNotice, logInfo, logWarn,
185-
logErr, logAlert, logCrit, logEmergency
186-
:: LoggerEnv -> LogStr -> IO ()
187-
logDebug x = logSay x DebugS
188-
logNotice x = logSay x InfoS
189-
logInfo x = logSay x InfoS
190-
logWarn x = logSay x WarningS
191-
logErr x = logSay x ErrorS
192-
logCrit x = logSay x CriticalS
193-
logAlert x = logSay x AlertS
194-
logEmergency x = logSay x EmergencyS
19582

19683

19784
-- $metrics-support
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
signature Cheops.Logger.Internal.Metrics where
1+
signature Cheops.Logger.Metrics where
22
flushLog :: IO () -> IO ()
33
submitLog :: IO () -> IO ()

0 commit comments

Comments
 (0)