Commit 914442a5 authored by Toralf Wittner's avatar Toralf Wittner
Browse files

Add support for netstrings encoding.

parent 3db20f2f
Loading
Loading
Loading
Loading

CHANGELOG.md

0 → 100644
+7 −0
Original line number Diff line number Diff line
0.9
-----------------------------------------------------------------------------
- Add support for netstrings encoding.

0.8
-----------------------------------------------------------------------------
- Initial release.

bench/Bench.hs

0 → 100644
+52 −0
Original line number Diff line number Diff line
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.

{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Criterion.Main
import Criterion.Config
import Data.Int
import System.Logger.Message

import qualified Data.ByteString.Lazy as L

main :: IO ()
main = defaultMainWith defaultConfig (return ())
    [ bgroup "direct"
        [ bench "msg/8"  (whnf (f False) 8)
        , bench "msg/16" (whnf (f False) 16)
        , bench "msg/32" (whnf (f False) 32)
        ]
    , bgroup "netstr"
        [ bench "msg/8"  (whnf (f True) 8)
        , bench "msg/16" (whnf (f True) 16)
        , bench "msg/32" (whnf (f True) 32)
        ]
    , bgroup "direct"
        [ bench "field/8"  (whnf (g False) 8)
        , bench "field/16" (whnf (g False) 16)
        , bench "field/32" (whnf (g False) 32)
        ]
    , bgroup "netstr"
        [ bench "field/8"  (whnf (g True) 8)
        , bench "field/16" (whnf (g True) 16)
        , bench "field/32" (whnf (g True) 32)
        ]
    ]

f :: Bool -> Int -> Int64
f b n = L.length
      . render ", " b
      . foldr1 (.)
      . replicate n
      $ msg (val "hello world")

g :: Bool -> Int -> Int64
g b n = L.length
      . render ", " b
      . foldr1 (.)
      . replicate n
      $ field "key" (val "value")
+12 −7
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ data Settings = Settings
    , output     :: Output     -- ^ log sink
    , format     :: DateFormat -- ^ the timestamp format (use \"\" to disable timestamps)
    , delimiter  :: ByteString -- ^ text to intersperse between fields of a log line
    , netstrings :: Bool       -- ^ use <http://cr.yp.to/proto/netstrings.txt netstrings> encoding (fixes delimiter to \",\")
    , bufSize    :: BufSize    -- ^ how many bytes to buffer before commiting to sink
    } deriving (Eq, Ord, Show)

@@ -99,10 +100,12 @@ iso8601UTC = "%Y-%0m-%0dT%0H:%0M:%0SZ"
--
--   * 'delimiter' = \", \"
--
--   * 'netstrings' = False
--
--   * 'bufSize'   = 'FL.defaultBufSize'
--
defSettings :: Settings
defSettings = Settings Debug StdOut iso8601UTC ", " FL.defaultBufSize
defSettings = Settings Debug StdOut iso8601UTC ", " False FL.defaultBufSize

-- | Create a new 'Logger' with the given 'Settings'.
-- Please note that the 'logLevel' can be dynamically adjusted by setting
@@ -175,7 +178,9 @@ level = logLevel . _settings
putMsg :: MonadIO m => Logger -> Level -> (Msg -> Msg) -> m ()
putMsg g l f = liftIO $ do
    d <- maybe (return id) (liftM msg) (_getDate g)
    let m = render (delimiter $ _settings g) (d . msg (l2b l) . f)
    let n = netstrings $ _settings g
    let x = delimiter  $ _settings g
    let m = render x n (d . msg (l2b l) . f)
    FL.pushLogStr (_logger g) (FL.toLogStr m)
  where
    l2b :: Level -> ByteString
+41 −14
Original line number Diff line number Diff line
@@ -35,11 +35,12 @@ import Data.Text (Text)
import Data.Text.Encoding (encodeUtf8)
import Data.Word

import qualified Data.Text.Lazy                      as T
import qualified Data.Text.Lazy.Encoding             as T
import qualified Data.ByteString                     as S
import qualified Data.ByteString.Lazy                as L
import qualified Data.ByteString.Lazy.Builder        as B
import qualified Data.ByteString.Lazy.Builder.Extras as B
import qualified Data.Text.Lazy                      as T
import qualified Data.Text.Lazy.Encoding             as T

-- | Convert some value to a 'Builder'.
class ToBytes a where
@@ -54,6 +55,7 @@ instance ToBytes Int8 where bytes = B.int8Dec
instance ToBytes Int16        where bytes = B.int16Dec
instance ToBytes Int32        where bytes = B.int32Dec
instance ToBytes Int64        where bytes = B.int64Dec
instance ToBytes Integer      where bytes = B.integerDec
instance ToBytes Word         where bytes = B.wordDec
instance ToBytes Word8        where bytes = B.word8Dec
instance ToBytes Word16       where bytes = B.word16Dec
@@ -70,15 +72,19 @@ instance ToBytes Bool where
    bytes False = val "False"

-- | Type representing log messages.
newtype Msg = Msg { builders :: [Builder] }
newtype Msg = Msg { elements :: [Element] }

data Element
    = Bytes L.ByteString
    | Field ByteString L.ByteString

-- | Turn some value into a 'Msg'.
msg :: ToBytes a => a -> Msg -> Msg
msg p (Msg m) = Msg (bytes p : m)
msg p (Msg m) = Msg $ Bytes (lbstr p) : m

-- | Render some field, i.e. a key-value pair delimited by \"=\".
field :: ToBytes a => ByteString -> a -> Msg -> Msg
field k v (Msg m) = Msg $ bytes k <> B.byteString "=" <> bytes v : m
field k v (Msg m) = Msg $ Field k (lbstr v) : m

-- | Alias of 'field'.
(.=) :: ToBytes a => ByteString -> a -> Msg -> Msg
@@ -103,14 +109,35 @@ val = bytes

-- | Intersperse parts of the log message with the given delimiter and
-- render the whole builder into a 'L.ByteString'.
render :: ByteString -> (Msg -> Msg) -> L.ByteString
render s f = finish
           . mconcat
           . intersperse (B.byteString s)
           . builders
           . f
           $ empty
--
-- If the second parameter is set to @True@, netstrings encoding is used for
-- the message elements. Cf. <http://cr.yp.to/proto/netstrings.txt> for
-- details.
render :: ByteString -> Bool -> (Msg -> Msg) -> L.ByteString
render _ True m = finish . mconcat . map enc . elements . m $ empty
  where
    finish = B.toLazyByteStringWith (B.untrimmedStrategy 128 256) "\n"
    enc (Bytes   e) = netstrLB e
    enc (Field k v) = netstrSB k <> eq <> netstrLB v
    eq              = val "1:=,"

render s False m = finish . mconcat . seps . map enc . elements . m $ empty
  where
    enc (Bytes   e) = bytes e
    enc (Field k v) = k +++ val "=" +++ v
    seps            = intersperse (bytes s)

finish :: Builder -> L.ByteString
finish = B.toLazyByteStringWith (B.untrimmedStrategy 256 256) "\n"

empty :: Msg
empty = Msg []

netstrSB :: ByteString -> Builder
netstrSB b = S.length b +++ val ":" +++ b +++ val ","

netstrLB :: L.ByteString -> Builder
netstrLB b = L.length b +++ val ":" +++ b +++ val ","

lbstr :: ToBytes a => a -> L.ByteString
lbstr = B.toLazyByteStringWith (B.untrimmedStrategy 64 64) L.empty . bytes
+16 −1
Original line number Diff line number Diff line
name:                 tinylog
version:              0.8
version:              0.9
synopsis:             Simplistic logging using fast-logger.
author:               Toralf Wittner
maintainer:           Toralf Wittner <tw@dtex.org>
copyright:            (c) 2014 Toralf Wittner
homepage:             https://github.com/twittner/tinylog/
bug-reports:          https://github.com/twittner/tinylog/issues
license:              OtherLicense
license-file:         LICENSE
category:             System
build-type:           Simple
cabal-version:        >= 1.10
extra-source-files:   CHANGELOG.md

description:
    Trivial logger on top of fast-logger.
@@ -36,3 +39,15 @@ library
        , text         >= 0.11   && < 1.2
        , transformers >= 0.3
        , unix-time    >= 0.1    && < 0.3

benchmark tinylog-bench
    type:             exitcode-stdio-1.0
    default-language: Haskell2010
    main-is:          Bench.hs
    hs-source-dirs:   bench
    ghc-options:      -Wall -O2 -fwarn-tabs
    build-depends:
          base       == 4.*
        , bytestring
        , criterion  == 0.8.*
        , tinylog