11-- Copyright (c) 2019 The DAML Authors. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
3- {-# LANGUAGE NamedFieldPuns #-}
4- {-# LANGUAGE OverloadedStrings #-}
3+ {-# LANGUAGE LambdaCase #-}
4+ {-# LANGUAGE NamedFieldPuns #-}
5+ {-# LANGUAGE OverloadedStrings #-}
6+ {-# LANGUAGE ScopedTypeVariables #-}
57module Main (main ) where
68
79import Control.Arrow ((&&&) )
@@ -10,13 +12,14 @@ import Data.Function ((&))
1012import Data.Text (Text )
1113import qualified Development.IDE.Main as GhcideMain
1214import Development.IDE.Types.Logger (Doc , Priority (Error , Info ),
15+ Recorder ,
1316 WithPriority (WithPriority , priority ),
1417 cfilter , cmapWithPrio ,
1518 defaultLayoutOptions ,
16- layoutPretty ,
19+ layoutPretty , logWith ,
1720 makeDefaultStderrRecorder ,
1821 payload , renderStrict ,
19- withDefaultRecorder )
22+ withFileRecorder )
2023import qualified Development.IDE.Types.Logger as Logger
2124import qualified HlsPlugins as Plugins
2225import Ide.Arguments (Arguments (.. ),
@@ -30,7 +33,11 @@ import Ide.Types (PluginDescriptor (pluginNotificat
3033 mkPluginNotificationHandler )
3134import Language.LSP.Server as LSP
3235import Language.LSP.Types as LSP
33- import Prettyprinter (Pretty (pretty ), vsep )
36+ import Prettyprinter (Pretty (pretty ), vcat , vsep )
37+ import Control.Exception (displayException )
38+ import Data.Bifunctor (first )
39+ import Data.Functor ((<&>) )
40+ import Data.Maybe (catMaybes )
3441
3542data Log
3643 = LogIdeMain IdeMain. Log
@@ -43,13 +50,27 @@ instance Pretty Log where
4350
4451main :: IO ()
4552main = do
53+ stderrRecorder <- makeDefaultStderrRecorder Nothing
4654 -- plugin cli commands use stderr logger for now unless we change the args
4755 -- parser to get logging arguments first or do more complicated things
48- pluginCliRecorder <- cmapWithPrio pretty <$> makeDefaultStderrRecorder Nothing
56+ let pluginCliRecorder = cmapWithPrio pretty stderrRecorder
4957 args <- getArguments " haskell-language-server" (Plugins. idePlugins (cmapWithPrio LogPlugins pluginCliRecorder))
5058
51- (lspLogRecorder, cb1) <- Logger. withBacklog Logger. lspClientLogRecorder
52- (lspMessageRecorder, cb2) <- Logger. withBacklog Logger. lspClientMessageRecorder
59+ -- Recorder that logs to the LSP client with logMessage
60+ (lspLogRecorder, cb1) <-
61+ Logger. withBacklog Logger. lspClientLogRecorder
62+ <&> first (cmapWithPrio renderDoc)
63+ -- Recorder that logs to the LSP client with showMessage
64+ (lspMessageRecorder, cb2) <-
65+ Logger. withBacklog Logger. lspClientMessageRecorder
66+ <&> first (cmapWithPrio renderDoc)
67+ -- Recorder that logs Error severity logs to the client with showMessage and some extra text
68+ let lspErrorMessageRecorder = lspMessageRecorder
69+ & cfilter (\ WithPriority { priority } -> priority >= Error )
70+ & cmapWithPrio (\ msg -> vsep
71+ [" Error condition, please check your setup and/or the [issue tracker](" <> issueTrackerUrl <> " ): "
72+ , msg
73+ ])
5374 -- This plugin just installs a handler for the `initialized` notification, which then
5475 -- picks up the LSP environment and feeds it to our recorders
5576 let lspRecorderPlugin = (defaultPluginDescriptor " LSPRecorderCallback" )
@@ -58,28 +79,35 @@ main = do
5879 liftIO $ (cb1 <> cb2) env
5980 }
6081
61- let (argsTesting, minPriority, logFilePath) =
82+ let (minPriority, logFilePath, logStderr, logClient ) =
6283 case args of
63- Ghcide GhcideArguments { argsTesting, argsLogLevel, argsLogFile} ->
64- (argsTesting, argsLogLevel, argsLogFile)
65- _ -> (False , Info , Nothing )
84+ Ghcide GhcideArguments { argsLogLevel, argsLogFile, argsLogStderr, argsLogClient } ->
85+ (argsLogLevel, argsLogFile, argsLogStderr, argsLogClient )
86+ _ -> (Info , Nothing , True , False )
6687
67- withDefaultRecorder logFilePath Nothing $ \ textWithPriorityRecorder -> do
88+ -- Adapter for withFileRecorder to handle the case where we don't want to log to a file
89+ let withLogFileRecorder action = case logFilePath of
90+ Just p -> withFileRecorder p Nothing $ \ case
91+ Left e -> do
92+ let exceptionMessage = pretty $ displayException e
93+ let message = vcat [exceptionMessage, " Couldn't open log file; not logging to it." ]
94+ logWith stderrRecorder Error message
95+ action Nothing
96+ Right r -> action (Just r)
97+ Nothing -> action Nothing
98+
99+ withLogFileRecorder $ \ logFileRecorder -> do
68100 let
69- recorder = cmapWithPrio (pretty &&& id ) $ mconcat
70- [textWithPriorityRecorder
71- & cfilter (\ WithPriority { priority } -> priority >= minPriority)
72- & cmapWithPrio fst
73- , lspMessageRecorder
74- & cfilter (\ WithPriority { priority } -> priority >= Error )
75- & cmapWithPrio (renderDoc . fst )
76- , lspLogRecorder
77- & cfilter (\ WithPriority { priority } -> priority >= minPriority)
78- & cmapWithPrio (renderStrict . layoutPretty defaultLayoutOptions . fst )
79- -- do not log heap stats to the LSP log as they interfere with the
80- -- ability of lsp-test to detect a stuck server in tests and benchmarks
81- & if argsTesting then cfilter (not . heapStats . snd . payload) else id
82- ]
101+ lfr = logFileRecorder
102+ ser = if logStderr then Just stderrRecorder else Nothing
103+ lemr = Just lspErrorMessageRecorder
104+ llr = if logClient then Just lspLogRecorder else Nothing
105+ recorder :: Recorder (WithPriority Log ) =
106+ [lfr, ser, lemr, llr]
107+ & catMaybes
108+ & mconcat
109+ & cmapWithPrio pretty
110+ & cfilter (\ WithPriority { priority } -> priority >= minPriority)
83111 plugins = Plugins. idePlugins (cmapWithPrio LogPlugins recorder)
84112
85113 defaultMain
@@ -88,14 +116,7 @@ main = do
88116 (plugins <> pluginDescToIdePlugins [lspRecorderPlugin])
89117
90118renderDoc :: Doc a -> Text
91- renderDoc d = renderStrict $ layoutPretty defaultLayoutOptions $ vsep
92- [" Error condition, please check your setup and/or the [issue tracker](" <> issueTrackerUrl <> " ): "
93- ,d
94- ]
119+ renderDoc d = renderStrict $ layoutPretty defaultLayoutOptions d
95120
96121issueTrackerUrl :: Doc a
97122issueTrackerUrl = " https://github.com/haskell/haskell-language-server/issues"
98-
99- heapStats :: Log -> Bool
100- heapStats (LogIdeMain (IdeMain. LogIDEMain (GhcideMain. LogHeapStats _))) = True
101- heapStats _ = False
0 commit comments