diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp --- a/clang-tools-extra/clangd/index/remote/server/Server.cpp +++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp @@ -12,6 +12,7 @@ #include "index/Serialization.h" #include "index/Symbol.h" #include "index/remote/marshalling/Marshalling.h" +#include "support/Context.h" #include "support/Logger.h" #include "support/Shutdown.h" #include "support/ThreadsafeFS.h" @@ -23,6 +24,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/VirtualFileSystem.h" @@ -58,6 +60,12 @@ llvm::cl::init(Logger::Info), }; +llvm::cl::opt LogPublic{ + "log-public", + llvm::cl::desc("Avoid logging potentially-sensitive request details"), + llvm::cl::init(false), +}; + llvm::cl::opt TraceFile( "trace-file", llvm::cl::desc("Path to the file where tracer logs will be stored")); @@ -72,6 +80,8 @@ "server-address", llvm::cl::init("0.0.0.0:50051"), llvm::cl::desc("Address of the invoked server. Defaults to 0.0.0.0:50051")); +static Key CurrentRequest; + class RemoteIndexServer final : public v1::SymbolIndex::Service { public: RemoteIndexServer(clangd::SymbolIndex &Index, llvm::StringRef IndexRoot) @@ -87,6 +97,7 @@ grpc::Status Lookup(grpc::ServerContext *Context, const LookupRequest *Request, grpc::ServerWriter *Reply) override { + WithContextValue(CurrentRequest, Context); trace::Span Tracer("LookupRequest"); auto Req = ProtobufMarshaller->fromProtobuf(Request); if (!Req) { @@ -119,6 +130,7 @@ grpc::Status FuzzyFind(grpc::ServerContext *Context, const FuzzyFindRequest *Request, grpc::ServerWriter *Reply) override { + WithContextValue(CurrentRequest, Context); trace::Span Tracer("FuzzyFindRequest"); auto Req = ProtobufMarshaller->fromProtobuf(Request); if (!Req) { @@ -151,6 +163,7 @@ grpc::Status Refs(grpc::ServerContext *Context, const RefsRequest *Request, grpc::ServerWriter *Reply) override { + WithContextValue(CurrentRequest, Context); trace::Span Tracer("RefsRequest"); auto Req = ProtobufMarshaller->fromProtobuf(Request); if (!Req) { @@ -183,6 +196,7 @@ grpc::Status Relations(grpc::ServerContext *Context, const RelationsRequest *Request, grpc::ServerWriter *Reply) override { + WithContextValue(CurrentRequest, Context); trace::Span Tracer("RelationsRequest"); auto Req = ProtobufMarshaller->fromProtobuf(Request); if (!Req) { @@ -229,8 +243,8 @@ LastStatus.getLastModificationTime() && Status->getSize() == LastStatus.getSize())) return; - vlog("Found different index version: existing index was modified at {0}, new " - "index was modified at {1}. Attempting to reload.", + vlog("Found different index version: existing index was modified at " + "{0}, new index was modified at {1}. Attempting to reload.", LastStatus.getLastModificationTime(), Status->getLastModificationTime()); LastStatus = *Status; std::unique_ptr NewIndex = loadIndex(IndexPath); @@ -266,6 +280,29 @@ ServerShutdownWatcher.join(); } +std::unique_ptr makeLogger(llvm::raw_ostream &OS) { + if (!LogPublic) + return std::make_unique(OS, LogLevel); + // Redacted mode: + // - messages outside the scope of a request: log fully + // - messages tagged [public]: log fully + // - errors: log the format string + // - others: drop + class RedactedLogger : public StreamLogger { + public: + using StreamLogger::StreamLogger; + void log(Level L, const char *Fmt, + const llvm::formatv_object_base &Message) override { + if (Context::current().get(CurrentRequest) == nullptr || + llvm::StringRef(Fmt).startswith("[public]")) + return StreamLogger::log(L, Fmt, Message); + if (L >= Error) + return StreamLogger::log(L, Fmt, llvm::formatv("[redacted] {0}", Fmt)); + } + }; + return std::make_unique(OS, LogLevel); +} + } // namespace } // namespace remote } // namespace clangd @@ -287,8 +324,8 @@ llvm::errs().SetBuffered(); // Don't flush stdout when logging for thread safety. llvm::errs().tie(nullptr); - clang::clangd::StreamLogger Logger(llvm::errs(), LogLevel); - clang::clangd::LoggingSession LoggingSession(Logger); + auto Logger = makeLogger(llvm::errs()); + clang::clangd::LoggingSession LoggingSession(*Logger); llvm::Optional TracerStream; std::unique_ptr Tracer; diff --git a/clang-tools-extra/clangd/support/Logger.h b/clang-tools-extra/clangd/support/Logger.h --- a/clang-tools-extra/clangd/support/Logger.h +++ b/clang-tools-extra/clangd/support/Logger.h @@ -24,16 +24,19 @@ public: virtual ~Logger() = default; - enum Level { Debug, Verbose, Info, Error }; + /// The significance or severity of this message. + /// Typically used to filter the output to an interesting level. + enum Level : unsigned char { Debug, Verbose, Info, Error }; static char indicator(Level L) { return "DVIE"[L]; } /// Implementations of this method must be thread-safe. - virtual void log(Level, const llvm::formatv_object_base &Message) = 0; + virtual void log(Level, const char *Fmt, + const llvm::formatv_object_base &Message) = 0; }; namespace detail { const char *debugType(const char *Filename); -void log(Logger::Level, const llvm::formatv_object_base &); +void logImpl(Logger::Level, const char *Fmt, const llvm::formatv_object_base &); // We often want to consume llvm::Errors by value when passing them to log(). // We automatically wrap them in llvm::fmt_consume() as formatv requires. @@ -43,7 +46,8 @@ } template void log(Logger::Level L, const char *Fmt, Ts &&... Vals) { - detail::log(L, llvm::formatv(Fmt, detail::wrap(std::forward(Vals))...)); + detail::logImpl(L, Fmt, + llvm::formatv(Fmt, detail::wrap(std::forward(Vals))...)); } llvm::Error error(std::error_code, std::string &&); @@ -119,7 +123,8 @@ : MinLevel(MinLevel), Logs(Logs) {} /// Write a line to the logging stream. - void log(Level, const llvm::formatv_object_base &Message) override; + void log(Level, const char *Fmt, + const llvm::formatv_object_base &Message) override; private: Logger::Level MinLevel; diff --git a/clang-tools-extra/clangd/support/Logger.cpp b/clang-tools-extra/clangd/support/Logger.cpp --- a/clang-tools-extra/clangd/support/Logger.cpp +++ b/clang-tools-extra/clangd/support/Logger.cpp @@ -28,10 +28,10 @@ LoggingSession::~LoggingSession() { L = nullptr; } -void detail::log(Logger::Level Level, - const llvm::formatv_object_base &Message) { +void detail::logImpl(Logger::Level Level, const char *Fmt, + const llvm::formatv_object_base &Message) { if (L) - L->log(Level, Message); + L->log(Level, Fmt, Message); else { static std::mutex Mu; std::lock_guard Guard(Mu); @@ -47,7 +47,7 @@ return Filename; } -void StreamLogger::log(Logger::Level Level, +void StreamLogger::log(Logger::Level Level, const char *Fmt, const llvm::formatv_object_base &Message) { if (Level < MinLevel) return; diff --git a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp @@ -67,7 +67,8 @@ private: // Color logs so we can distinguish them from test output. - void log(Level L, const llvm::formatv_object_base &Message) override { + void log(Level L, const char *Fmt, + const llvm::formatv_object_base &Message) override { raw_ostream::Colors Color; switch (L) { case Level::Verbose: