Skip to content

Commit 3087066

Browse files
committed
Attribute response error logs to plugins
1 parent 42e74f2 commit 3087066

File tree

1 file changed

+34
-16
lines changed
  • ghcide/src/Development/IDE/Plugin

1 file changed

+34
-16
lines changed

ghcide/src/Development/IDE/Plugin/HLS.hs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ import Control.Exception (SomeException)
1313
import Control.Lens ((^.))
1414
import Control.Monad
1515
import qualified Data.Aeson as J
16+
import Data.Bifunctor (first)
1617
import Data.Dependent.Map (DMap)
1718
import qualified Data.Dependent.Map as DMap
1819
import Data.Dependent.Sum
1920
import Data.Either
2021
import qualified Data.List as List
2122
import Data.List.NonEmpty (NonEmpty, nonEmpty, toList)
23+
import qualified Data.List.NonEmpty as NE
2224
import qualified Data.Map as Map
25+
import Data.Some
2326
import Data.String
2427
import Data.Text (Text)
2528
import qualified Data.Text as T
@@ -38,6 +41,7 @@ import Language.LSP.Types
3841
import qualified Language.LSP.Types as J
3942
import qualified Language.LSP.Types.Lens as LSP
4043
import Language.LSP.VFS
44+
import Prettyprinter.Render.String (renderString)
4145
import Text.Regex.TDFA.Text ()
4246
import UnliftIO (MonadUnliftIO)
4347
import UnliftIO.Async (forConcurrently)
@@ -46,12 +50,18 @@ import UnliftIO.Exception (catchAny)
4650
-- ---------------------------------------------------------------------
4751
--
4852

49-
data Log = LogPluginError ResponseError
50-
deriving Show
51-
53+
data Log
54+
= LogPluginError PluginId ResponseError
55+
| LogNoPluginForMethod (Some SMethod)
56+
| LogInvalidCommandIdentifier
5257
instance Pretty Log where
5358
pretty = \case
54-
LogPluginError err -> prettyResponseError err
59+
LogPluginError pId err -> pretty (show pId) <> ":" <+> prettyResponseError err
60+
LogNoPluginForMethod (Some method) ->
61+
"No plugin enabled for " <> pretty (show method)
62+
LogInvalidCommandIdentifier-> "Invalid command identifier"
63+
64+
instance Show Log where show = renderString . layoutCompact . pretty
5565

5666
-- various error message specific builders
5767
prettyResponseError :: ResponseError -> Doc a
@@ -77,10 +87,10 @@ failedToParseArgs :: CommandId -- ^ command that failed to parse
7787
failedToParseArgs (CommandId com) (PluginId pid) err arg = "Error while parsing args for " <> com <> " in plugin " <> pid <> ": " <> T.pack err <> "\narg = " <> T.pack (show arg)
7888

7989
-- | Build a ResponseError and log it before returning to the caller
80-
logAndReturnError :: Recorder (WithPriority Log) -> ErrorCode -> Text -> LSP.LspT Config IO (Either ResponseError a)
81-
logAndReturnError recorder errCode msg = do
90+
logAndReturnError :: Recorder (WithPriority Log) -> PluginId -> ErrorCode -> Text -> LSP.LspT Config IO (Either ResponseError a)
91+
logAndReturnError recorder p errCode msg = do
8292
let err = ResponseError errCode msg Nothing
83-
logWith recorder Warning $ LogPluginError err
93+
logWith recorder Warning $ LogPluginError p err
8494
pure $ Left err
8595

8696
-- | Map a set of plugins to the underlying ghcide engine.
@@ -164,15 +174,17 @@ executeCommandHandlers recorder ecs = requestHandler SWorkspaceExecuteCommand ex
164174
Just (plugin, cmd) -> runPluginCommand ide plugin cmd cmdParams
165175

166176
-- Couldn't parse the command identifier
167-
_ -> logAndReturnError recorder InvalidParams "Invalid command Identifier"
177+
_ -> do
178+
logWith recorder Warning LogInvalidCommandIdentifier
179+
return $ Left $ ResponseError InvalidParams "Invalid command identifier" Nothing
168180

169181
runPluginCommand ide p com arg =
170182
case Map.lookup p pluginMap of
171-
Nothing -> logAndReturnError recorder InvalidRequest (pluginDoesntExist p)
183+
Nothing -> logAndReturnError recorder p InvalidRequest (pluginDoesntExist p)
172184
Just xs -> case List.find ((com ==) . commandId) xs of
173-
Nothing -> logAndReturnError recorder InvalidRequest (commandDoesntExist com p xs)
185+
Nothing -> logAndReturnError recorder p InvalidRequest (commandDoesntExist com p xs)
174186
Just (PluginCommand _ _ f) -> case J.fromJSON arg of
175-
J.Error err -> logAndReturnError recorder InvalidParams (failedToParseArgs com p err arg)
187+
J.Error err -> logAndReturnError recorder p InvalidParams (failedToParseArgs com p err arg)
176188
J.Success a -> f ide a
177189

178190
-- ---------------------------------------------------------------------
@@ -195,15 +207,20 @@ extensiblePlugins recorder xs = mempty { P.pluginHandlers = handlers }
195207
let fs = filter (\(_, desc, _) -> pluginEnabled m params desc config) fs'
196208
-- Clients generally don't display ResponseErrors so instead we log any that we come across
197209
case nonEmpty fs of
198-
Nothing -> logAndReturnError recorder InvalidRequest (pluginNotEnabled m fs')
210+
Nothing -> do
211+
logWith recorder Warning (LogNoPluginForMethod $ Some m)
212+
let err = ResponseError InvalidRequest msg Nothing
213+
msg = pluginNotEnabled m fs'
214+
return $ Left err
199215
Just fs -> do
200216
let msg e pid = "Exception in plugin " <> T.pack (show pid) <> " while processing " <> T.pack (show m) <> ": " <> T.pack (show e)
201217
handlers = fmap (\(plid,_,handler) -> (plid,handler)) fs
202218
es <- runConcurrently msg (show m) handlers ide params
203-
let (errs,succs) = partitionEithers $ toList es
204-
unless (null errs) $ forM_ errs $ \err -> logWith recorder Warning $ LogPluginError err
219+
let (errs,succs) = partitionEithers $ toList $ NE.zipWith (\(pId,_) -> first (pId,)) handlers es
220+
unless (null errs) $ forM_ errs $ \(pId, err) ->
221+
logWith recorder Warning $ LogPluginError pId err
205222
case nonEmpty succs of
206-
Nothing -> pure $ Left $ combineErrors errs
223+
Nothing -> pure $ Left $ combineErrors $ map snd errs
207224
Just xs -> do
208225
caps <- LSP.getClientCapabilities
209226
pure $ Right $ combineResponses m config caps params xs
@@ -226,7 +243,8 @@ extensibleNotificationPlugins recorder xs = mempty { P.pluginHandlers = handlers
226243
-- Only run plugins that are allowed to run on this request
227244
let fs = filter (\(_, desc, _) -> pluginEnabled m params desc config) fs'
228245
case nonEmpty fs of
229-
Nothing -> void $ logAndReturnError recorder InvalidRequest (pluginNotEnabled m fs')
246+
Nothing -> do
247+
logWith recorder Warning (LogNoPluginForMethod $ Some m)
230248
Just fs -> do
231249
-- We run the notifications in order, so the core ghcide provider
232250
-- (which restarts the shake process) hopefully comes last

0 commit comments

Comments
 (0)