Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 9d13bcb

Browse files
committed
Merge pull request #120 from alanz/new-logger
New logger
2 parents e51ca5c + f1d17eb commit 9d13bcb

File tree

9 files changed

+176
-27
lines changed

9 files changed

+176
-27
lines changed

app/MainHie.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module Main where
77
import Control.Concurrent
88
import Control.Concurrent.STM.TChan
99
import Control.Exception
10-
import Control.Logging
10+
import Control.Monad.Logger
1111
import Control.Monad
1212
import Control.Monad.STM
1313
import Control.Monad.Trans.Maybe

haskell-ide-engine.cabal

+12-9
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ library
3434
, containers
3535
, directory
3636
, either
37+
, fast-logger
3738
, ghc >= 7.10.2 && < 7.11
3839
, ghc-mod >= 5.4
3940
, gitrev >= 1.1
4041
, haskeline
4142
, hie-plugin-api
4243
, lens
43-
, logging
44+
, lifted-base
4445
, monad-control
46+
, monad-logger
4547
, mtl
4648
, optparse-applicative
4749
, optparse-simple >= 0.0.3
@@ -50,14 +52,14 @@ library
5052
, pipes-attoparsec >= 0.5
5153
, pipes-bytestring
5254
, pipes-parse
53-
, stm
5455
, servant-server
56+
, stm
5557
, text
5658
, time
5759
, transformers
60+
, vinyl >= 0.5 && < 0.6
5861
, wai
5962
, warp
60-
, vinyl >= 0.5 && < 0.6
6163
ghc-options: -Wall
6264
default-language: Haskell2010
6365

@@ -70,15 +72,16 @@ executable hie
7072
, aeson
7173
, containers
7274
, directory
75+
, fast-logger
7376
, ghc
7477
, ghc-mod
7578
, gitrev >= 1.1
7679
, haskell-ide-engine
7780
, hie-example-plugin2
78-
, hie-plugin-api
7981
, hie-ghc-mod
8082
, hie-hare
81-
, logging
83+
, hie-plugin-api
84+
, monad-logger
8285
, optparse-applicative
8386
, optparse-simple
8487
, stm
@@ -101,22 +104,22 @@ test-suite haskell-ide-test
101104
UtilsSpec
102105
build-depends: base
103106
, Diff
107+
, QuickCheck
104108
, aeson
105109
, containers
106-
, unordered-containers
107110
, directory
111+
, fast-logger
108112
, haskell-ide-engine
109113
, hie-ghc-mod
110114
, hie-hare
111115
, hie-plugin-api
112116
, hspec
113-
, logging
117+
, monad-logger
118+
, quickcheck-instances
114119
, stm
115120
, text
116121
, transformers
117122
, unordered-containers
118-
, quickcheck-instances
119-
, QuickCheck
120123
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
121124
default-language: Haskell2010
122125

src/Haskell/Ide/Engine/Monad.hs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import qualified HscTypes as GHC
1111

1212
import Control.Applicative
1313
import Control.Exception
14+
import Control.Monad.IO.Class
1415
import Control.Monad.State
1516
import Data.IORef
1617
import Exception
+152-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,167 @@
1+
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE FlexibleContexts #-}
3+
{-# OPTIONS_GHC -fno-warn-orphans #-} -- For MonadLogger IO instance
14
module Haskell.Ide.Engine.MonadFunctions
25
(
36
-- * Logging functions
4-
logm
7+
withStdoutLogging
8+
, withStderrLogging
9+
, withFileLogging
10+
, setLogLevel
11+
, setLogTimeFormat
12+
, logm
513
, debugm
614
) where
715

8-
9-
import Control.Logging
1016
import Control.Monad.IO.Class
17+
import Control.Monad.Logger
1118
import qualified Data.Text as T
19+
import Haskell.Ide.Engine.Monad()
1220
import Prelude hiding (log)
21+
import Control.Exception.Lifted
22+
import Control.Monad
23+
import Control.Monad.Trans.Control
24+
import Data.IORef
25+
import Data.Monoid
26+
import Data.Text as T
27+
import Data.Time
28+
import Prelude hiding (log)
29+
import System.IO.Unsafe
30+
import System.Log.FastLogger
1331

1432
-- ---------------------------------------------------------------------
1533

1634
logm :: MonadIO m => String -> m ()
17-
logm s = liftIO $ log $ T.pack s
35+
logm s = do
36+
liftIO (logInfoN $ T.pack s)
37+
flushLog
38+
39+
debugm :: MonadIO m => String -> m ()
40+
debugm s = do
41+
liftIO $ logDebugN $ T.pack s
42+
flushLog
43+
44+
-- ---------------------------------------------------------------------
45+
46+
-- instance MonadLoggerIO IO where
47+
instance MonadLogger IO where
48+
monadLoggerLog loc src lvl msg = loggingLogger loc lvl src msg
49+
50+
-- ---------------------------------------------------------------------
51+
52+
{-
53+
From https://hackage.haskell.org/package/logging-3.0.2/docs/src/Control-Logging.html
54+
-}
55+
56+
57+
-- |Create a new global variable to hold the system-wide log level
58+
logLevel :: IORef LogLevel
59+
{-# NOINLINE logLevel #-}
60+
logLevel = unsafePerformIO $ newIORef LevelDebug
61+
62+
-- | Set the global verbosity level. Messages at our higher than this level are
63+
-- displayed. It defaults to 'LevelDebug'.
64+
setLogLevel :: LogLevel -> IO ()
65+
setLogLevel = atomicWriteIORef logLevel
66+
67+
-- |Create a new global variable to hold the system-wide log output device
68+
logSet :: IORef LoggerSet
69+
{-# NOINLINE logSet #-}
70+
logSet = unsafePerformIO $
71+
newIORef (error "Must call withStdoutLogging or withStderrLogging")
72+
73+
-- |Create a new global variable to hold the system-wide log time format
74+
logTimeFormat :: IORef String
75+
{-# NOINLINE logTimeFormat #-}
76+
logTimeFormat = unsafePerformIO $ newIORef "%Y %b-%d %H:%M:%S%Q"
77+
78+
-- | Set the global format used for log timestamps.
79+
setLogTimeFormat :: String -> IO ()
80+
setLogTimeFormat = atomicWriteIORef logTimeFormat
81+
82+
-- | This function, or 'withStderrLogging' or 'withFileLogging', must be wrapped
83+
-- around whatever region of your application will be alive for the duration
84+
-- that logging will be used. Typically it would be wrapped around the body of
85+
-- 'main'.
86+
withStdoutLogging :: (MonadBaseControl IO m, MonadIO m) => m a -> m a
87+
withStdoutLogging f = do
88+
liftIO $ do
89+
set <- newStdoutLoggerSet defaultBufSize
90+
atomicWriteIORef logSet set
91+
f `finally` flushLog
92+
93+
withStderrLogging :: (MonadBaseControl IO m, MonadIO m) => m a -> m a
94+
withStderrLogging f = do
95+
liftIO $ do
96+
set <- newStderrLoggerSet defaultBufSize
97+
atomicWriteIORef logSet set
98+
f `finally` flushLog
99+
100+
withFileLogging :: (MonadBaseControl IO m, MonadIO m) => FilePath -> m a -> m a
101+
withFileLogging path f = do
102+
liftIO $ do
103+
set <- newFileLoggerSet defaultBufSize path
104+
atomicWriteIORef logSet set
105+
f `finally` flushLog
106+
107+
-- | Flush all collected logging messages. This is automatically called by
108+
-- 'withStdoutLogging', 'withStderrLogging' and 'withFileLogging' when those
109+
-- blocks are exited by whatever means.
110+
flushLog :: MonadIO m => m ()
111+
flushLog = liftIO $ do
112+
set <- readIORef logSet
113+
flushLogStr set
114+
115+
-- ---------------------------------------------------------------------
116+
-- Taken from Control.Monad.Logger source
117+
118+
119+
-- NOTE: general principle: a log line should not have more than one "\n" in it,
120+
-- else grepping the log becomes impossible.
121+
loggingLogger :: ToLogStr msg => Loc -> LogLevel -> LogSource -> msg -> IO ()
122+
loggingLogger !loc !lvl !src str = do
123+
maxLvl <- readIORef logLevel
124+
when (lvl >= maxLvl) $ do
125+
let willLog = True
126+
when willLog $ do
127+
now <- getCurrentTime
128+
fmt <- readIORef logTimeFormat
129+
let stamp = formatTime defaultTimeLocale fmt now
130+
set <- readIORef logSet
131+
pushLogStr set
132+
$ toLogStr (stamp ++ " " ++ renderLevel lvl
133+
++ " " ++ renderSource src)
134+
<> toLogStr str
135+
<> toLogStr locStr
136+
<> toLogStr (pack "\n")
137+
where
138+
renderSource :: Text -> String
139+
renderSource txt
140+
| T.null txt = ""
141+
| otherwise = unpack txt ++ ": "
142+
143+
renderLevel LevelDebug = "[DEBUG]"
144+
renderLevel LevelInfo = "[INFO]"
145+
renderLevel LevelWarn = "[WARN]"
146+
renderLevel LevelError = "[ERROR]"
147+
renderLevel (LevelOther txt) = "[" ++ unpack txt ++ "]"
148+
149+
locStr =
150+
if isDefaultLoc loc
151+
then ""
152+
else (" @(" ++ fileLocStr ++ ")" )
153+
154+
-- taken from file-location package
155+
-- turn the TH Loc loaction information into a human readable string
156+
-- leaving out the loc_end parameter
157+
fileLocStr = (loc_package loc) ++ ':' : (loc_module loc) ++
158+
' ' : (loc_filename loc) ++ ':' : (line loc) ++ ':' : (char loc)
159+
where
160+
line = show . fst . loc_start
161+
char = show . snd . loc_start
18162

19-
debugm :: MonadIO m =>String -> m ()
20-
debugm s = liftIO $ log $ T.pack s
163+
isDefaultLoc :: Loc -> Bool
164+
isDefaultLoc (Loc "<unknown>" "<unknown>" "<unknown>" (0,0) (0,0)) = True
165+
isDefaultLoc _ = False
21166

167+
-- EOF

src/Haskell/Ide/Engine/Transport/JsonStdio.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Control.Applicative
99
import Control.Concurrent
1010
import Control.Concurrent.STM.TChan
1111
import Control.Lens (view)
12-
import Control.Logging
12+
-- import Control.Logging
1313
import Control.Monad.IO.Class
1414
import Control.Monad.STM
1515
import Control.Monad.State.Strict
@@ -21,6 +21,7 @@ import qualified Data.ByteString.Lazy as BL
2121
import Data.Char
2222
import qualified Data.Map as Map
2323
import qualified Data.Text as T
24+
import Haskell.Ide.Engine.MonadFunctions
2425
import Haskell.Ide.Engine.PluginDescriptor
2526
import Haskell.Ide.Engine.Types
2627
import qualified Pipes as P
@@ -51,8 +52,7 @@ parseToJsonPipe cin cout cid =
5152
CResp "" cid $
5253
IdeResponseError
5354
(IdeError ParseError (T.pack $ show decodeErr) Nothing)
54-
liftIO $ debug $
55-
T.pack $ "jsonStdioTransport:parse error:" ++ show decodeErr
55+
liftIO $ debugm $ "jsonStdioTransport:parse error:" ++ show decodeErr
5656
liftIO $ atomically $ writeTChan cout rsp
5757
Right req ->
5858
do liftIO $ atomically $ writeTChan cin (wireToChannel cout cid req)

stack.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#resolver: lts-3.11
22
# Nightly has ghc-mod/cabal-helper, not in lts yet
3-
resolver: nightly-2015-10-27
3+
resolver: nightly-2015-12-02
44
packages:
55
- .
66
- hie-example-plugin2
@@ -9,6 +9,5 @@ packages:
99
- hie-hare
1010
extra-deps:
1111
- HaRe-0.8.2.1
12-
- logging-3.0.2
1312
- rosezipper-0.2
1413
- syz-0.2.0.0

test/DispatcherSpec.hs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module DispatcherSpec where
33

44
import Control.Concurrent
55
import Control.Concurrent.STM.TChan
6-
import Control.Logging
76
import Control.Monad.IO.Class
87
import Control.Monad.STM
98
import Data.Aeson

test/GhcModPluginSpec.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
module GhcModPluginSpec where
33

44
import Control.Concurrent.STM.TChan
5-
import Control.Logging
65
import Control.Monad.STM
76
import Data.Aeson
87
import qualified Data.HashMap.Strict as H
98
import Haskell.Ide.Engine.Dispatcher
109
import Haskell.Ide.Engine.Monad
10+
import Haskell.Ide.Engine.MonadFunctions
1111
import Haskell.Ide.Engine.PluginDescriptor
1212
import Haskell.Ide.Engine.SemanticTypes
1313
import Haskell.Ide.Engine.Types

test/HaRePluginSpec.hs

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ module HaRePluginSpec where
33

44
import Control.Concurrent.STM.TChan
55
import Control.Monad.STM
6-
import Control.Logging
76
import Data.Aeson
87
import Data.Algorithm.Diff
9-
-- import qualified Data.HashMap.Strict as H
108
import qualified Data.Map as Map
119
import Haskell.Ide.Engine.Dispatcher
1210
import Haskell.Ide.Engine.Monad
11+
import Haskell.Ide.Engine.MonadFunctions
1312
import Haskell.Ide.Engine.PluginDescriptor
1413
import Haskell.Ide.Engine.SemanticTypes
1514
import Haskell.Ide.Engine.Types
@@ -132,9 +131,11 @@ hareSpec = do
132131
, (First (9, " x"))
133132
, (Second (5, "foo x = case odd x of"))
134133
, (Second (6, " True ->"))
135-
, (Second (7, " x + 3"))
134+
-- , (Second (7, " x + 3"))
135+
, (Second (7, " x + 3"))
136136
, (Second (8, " False ->"))
137-
, (Second (9, " x"))
137+
-- , (Second (9, " x"))
138+
, (Second (9, " x"))
138139
]
139140
]))
140141

0 commit comments

Comments
 (0)