Index: clangd/ClangdLSPServer.h =================================================================== --- clangd/ClangdLSPServer.h +++ clangd/ClangdLSPServer.h @@ -42,7 +42,8 @@ /// /// \return Wether we received a 'shutdown' request before an 'exit' request bool run(std::istream &In, - JSONStreamStyle InputStyle = JSONStreamStyle::Standard); + JSONStreamStyle InputStyle = JSONStreamStyle::Standard, + bool LogLspToStderr = false); private: // Implement DiagnosticsConsumer. Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -402,7 +402,8 @@ : Out(Out), CDB(std::move(CompileCommandsDir)), CCOpts(CCOpts), Server(CDB, FSProvider, /*DiagConsumer=*/*this, Opts) {} -bool ClangdLSPServer::run(std::istream &In, JSONStreamStyle InputStyle) { +bool ClangdLSPServer::run(std::istream &In, JSONStreamStyle InputStyle, + bool LogLspToStderr) { assert(!IsDone && "Run was called before"); // Set up JSONRPCDispatcher. @@ -412,7 +413,8 @@ registerCallbackHandlers(Dispatcher, /*Callbacks=*/*this); // Run the Language Server loop. - runLanguageServerLoop(In, Out, InputStyle, Dispatcher, IsDone); + runLanguageServerLoop(In, Out, InputStyle, Dispatcher, LogLspToStderr, + IsDone); // Make sure IsDone is set to true after this method exits to ensure assertion // at the start of the method fires if it's ever executed again. Index: clangd/JSONRPCDispatcher.h =================================================================== --- clangd/JSONRPCDispatcher.h +++ clangd/JSONRPCDispatcher.h @@ -30,8 +30,10 @@ // JSONOutput now that we pass Context everywhere. public: JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs, - llvm::raw_ostream *InputMirror = nullptr, bool Pretty = false) - : Pretty(Pretty), Outs(Outs), Logs(Logs), InputMirror(InputMirror) {} + llvm::raw_ostream *InputMirror = nullptr, + bool LogLspToStderr = false, bool Pretty = false) + : LogLspToStderr(LogLspToStderr), Pretty(Pretty), Outs(Outs), Logs(Logs), + InputMirror(InputMirror) {} /// Emit a JSONRPC message. void writeMessage(const json::Expr &Result); @@ -44,6 +46,9 @@ /// Unlike other methods of JSONOutput, mirrorInput is not thread-safe. void mirrorInput(const Twine &Message); + /// Whether to output all LSP communication to stderr. + const bool LogLspToStderr; + // Whether output should be pretty-printed. const bool Pretty; @@ -104,7 +109,8 @@ /// replacements of \r\n with \n. void runLanguageServerLoop(std::istream &In, JSONOutput &Out, JSONStreamStyle InputStyle, - JSONRPCDispatcher &Dispatcher, bool &IsDone); + JSONRPCDispatcher &Dispatcher, bool LogLspToStderr, + bool &IsDone); } // namespace clangd } // namespace clang Index: clangd/JSONRPCDispatcher.cpp =================================================================== --- clangd/JSONRPCDispatcher.cpp +++ clangd/JSONRPCDispatcher.cpp @@ -66,7 +66,9 @@ Outs << "Content-Length: " << S.size() << "\r\n\r\n" << S; Outs.flush(); } - log(llvm::Twine("--> ") + S); + + if (LogLspToStderr) + log(llvm::Twine("--> ") + S); } void JSONOutput::log(const Twine &Message) { @@ -299,14 +301,17 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out, JSONStreamStyle InputStyle, JSONRPCDispatcher &Dispatcher, - bool &IsDone) { + bool LogLspToStderr, bool &IsDone) { auto &ReadMessage = (InputStyle == Delimited) ? readDelimitedMessage : readStandardMessage; while (In.good()) { if (auto JSON = ReadMessage(In, Out)) { if (auto Doc = json::parse(*JSON)) { - // Log the formatted message. - log(llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc)); + if (LogLspToStderr) { + // Log the formatted message. + log(llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc)); + } + // Finally, execute the action for this JSON message. if (!Dispatcher.call(*Doc, Out)) log("JSON dispatch failed!\n"); Index: clangd/tool/ClangdMain.cpp =================================================================== --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -77,6 +77,11 @@ llvm::cl::init(JSONStreamStyle::Standard)); static llvm::cl::opt + LogLspToStderr("log-lsp-to-stderr", + llvm::cl::desc("Output LSP communication on stderr"), + llvm::cl::init(false)); + +static llvm::cl::opt PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"), llvm::cl::init(false)); @@ -190,7 +195,7 @@ JSONOutput Out(llvm::outs(), llvm::errs(), InputMirrorStream ? InputMirrorStream.getPointer() : nullptr, - PrettyPrint); + LogLspToStderr, PrettyPrint); clangd::LoggingSession LoggingSession(Out); @@ -238,5 +243,7 @@ llvm::set_thread_name("clangd.main"); // Change stdin to binary to not lose \r\n on windows. llvm::sys::ChangeStdinToBinary(); - return LSPServer.run(std::cin, InputStyle) ? 0 : NoShutdownRequestErrorCode; + return LSPServer.run(std::cin, InputStyle, LogLspToStderr) + ? 0 + : NoShutdownRequestErrorCode; }