xref: /llvm-project/clang-tools-extra/clangd/support/Logger.h (revision 4d006520b8c0cc3a52913b4665bf741c737e5592)
1ad97ccf6SSam McCall //===--- Logger.h - Logger interface for clangd ------------------*- C++-*-===//
2ad97ccf6SSam McCall //
3ad97ccf6SSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ad97ccf6SSam McCall // See https://llvm.org/LICENSE.txt for license information.
5ad97ccf6SSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ad97ccf6SSam McCall //
7ad97ccf6SSam McCall //===----------------------------------------------------------------------===//
8ad97ccf6SSam McCall 
9ad97ccf6SSam McCall #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_LOGGER_H
10ad97ccf6SSam McCall #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_LOGGER_H
11ad97ccf6SSam McCall 
12ad97ccf6SSam McCall #include "llvm/Support/Debug.h"
13ad97ccf6SSam McCall #include "llvm/Support/Error.h"
14ad97ccf6SSam McCall #include "llvm/Support/FormatAdapters.h"
15ad97ccf6SSam McCall #include "llvm/Support/FormatVariadic.h"
16ad97ccf6SSam McCall #include <mutex>
17ad97ccf6SSam McCall 
18ad97ccf6SSam McCall namespace clang {
19ad97ccf6SSam McCall namespace clangd {
20ad97ccf6SSam McCall 
21ad97ccf6SSam McCall /// Interface to allow custom logging in clangd.
22ad97ccf6SSam McCall class Logger {
23ad97ccf6SSam McCall public:
24ad97ccf6SSam McCall   virtual ~Logger() = default;
25ad97ccf6SSam McCall 
26*65eaec9bSSam McCall   /// The significance or severity of this message.
27*65eaec9bSSam McCall   /// Typically used to filter the output to an interesting level.
28*65eaec9bSSam McCall   enum Level : unsigned char { Debug, Verbose, Info, Error };
indicator(Level L)29ad97ccf6SSam McCall   static char indicator(Level L) { return "DVIE"[L]; }
30ad97ccf6SSam McCall 
31ad97ccf6SSam McCall   /// Implementations of this method must be thread-safe.
32*65eaec9bSSam McCall   virtual void log(Level, const char *Fmt,
33*65eaec9bSSam McCall                    const llvm::formatv_object_base &Message) = 0;
34ad97ccf6SSam McCall };
35ad97ccf6SSam McCall 
36ad97ccf6SSam McCall namespace detail {
37ad97ccf6SSam McCall const char *debugType(const char *Filename);
38*65eaec9bSSam McCall void logImpl(Logger::Level, const char *Fmt, const llvm::formatv_object_base &);
39ad97ccf6SSam McCall 
40ad97ccf6SSam McCall // We often want to consume llvm::Errors by value when passing them to log().
41ad97ccf6SSam McCall // We automatically wrap them in llvm::fmt_consume() as formatv requires.
wrap(T && V)42ad97ccf6SSam McCall template <typename T> T &&wrap(T &&V) { return std::forward<T>(V); }
wrap(llvm::Error && V)43ad97ccf6SSam McCall inline decltype(fmt_consume(llvm::Error::success())) wrap(llvm::Error &&V) {
44ad97ccf6SSam McCall   return fmt_consume(std::move(V));
45ad97ccf6SSam McCall }
46ad97ccf6SSam McCall template <typename... Ts>
log(Logger::Level L,const char * Fmt,Ts &&...Vals)47ad97ccf6SSam McCall void log(Logger::Level L, const char *Fmt, Ts &&... Vals) {
48*65eaec9bSSam McCall   detail::logImpl(L, Fmt,
49*65eaec9bSSam McCall                   llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...));
50ad97ccf6SSam McCall }
5130667c96SSam McCall 
5230667c96SSam McCall llvm::Error error(std::error_code, std::string &&);
53ad97ccf6SSam McCall } // namespace detail
54ad97ccf6SSam McCall 
55ad97ccf6SSam McCall // Clangd logging functions write to a global logger set by LoggingSession.
56ad97ccf6SSam McCall // If no logger is registered, writes to llvm::errs().
57ad97ccf6SSam McCall // All accept llvm::formatv()-style arguments, e.g. log("Text={0}", Text).
58ad97ccf6SSam McCall 
59ad97ccf6SSam McCall // elog() is used for "loud" errors and warnings.
60ad97ccf6SSam McCall // This level is often visible to users.
elog(const char * Fmt,Ts &&...Vals)61ad97ccf6SSam McCall template <typename... Ts> void elog(const char *Fmt, Ts &&... Vals) {
62ad97ccf6SSam McCall   detail::log(Logger::Error, Fmt, std::forward<Ts>(Vals)...);
63ad97ccf6SSam McCall }
64ad97ccf6SSam McCall // log() is used for information important to understand a clangd session.
65ad97ccf6SSam McCall // e.g. the names of LSP messages sent are logged at this level.
66ad97ccf6SSam McCall // This level could be enabled in production builds to allow later inspection.
log(const char * Fmt,Ts &&...Vals)67ad97ccf6SSam McCall template <typename... Ts> void log(const char *Fmt, Ts &&... Vals) {
68ad97ccf6SSam McCall   detail::log(Logger::Info, Fmt, std::forward<Ts>(Vals)...);
69ad97ccf6SSam McCall }
70ad97ccf6SSam McCall // vlog() is used for details often needed for debugging clangd sessions.
71ad97ccf6SSam McCall // This level would typically be enabled for clangd developers.
vlog(const char * Fmt,Ts &&...Vals)72ad97ccf6SSam McCall template <typename... Ts> void vlog(const char *Fmt, Ts &&... Vals) {
73ad97ccf6SSam McCall   detail::log(Logger::Verbose, Fmt, std::forward<Ts>(Vals)...);
74ad97ccf6SSam McCall }
7530667c96SSam McCall // error() constructs an llvm::Error object, using formatv()-style arguments.
7630667c96SSam McCall // It is not automatically logged! (This function is a little out of place).
7730667c96SSam McCall // The error simply embeds the message string.
7830667c96SSam McCall template <typename... Ts>
error(std::error_code EC,const char * Fmt,Ts &&...Vals)7930667c96SSam McCall llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals) {
8030667c96SSam McCall   // We must render the formatv_object eagerly, while references are valid.
8130667c96SSam McCall   return detail::error(
8230667c96SSam McCall       EC, llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
8330667c96SSam McCall }
8430667c96SSam McCall // Overload with no error_code conversion, the error will be inconvertible.
error(const char * Fmt,Ts &&...Vals)8530667c96SSam McCall template <typename... Ts> llvm::Error error(const char *Fmt, Ts &&... Vals) {
8630667c96SSam McCall   return detail::error(
8730667c96SSam McCall       llvm::inconvertibleErrorCode(),
8830667c96SSam McCall       llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
8930667c96SSam McCall }
9030667c96SSam McCall // Overload to avoid formatv complexity for simple strings.
error(std::error_code EC,std::string Msg)9130667c96SSam McCall inline llvm::Error error(std::error_code EC, std::string Msg) {
9230667c96SSam McCall   return detail::error(EC, std::move(Msg));
9330667c96SSam McCall }
9430667c96SSam McCall // Overload for simple strings with no error_code conversion.
error(std::string Msg)9530667c96SSam McCall inline llvm::Error error(std::string Msg) {
9630667c96SSam McCall   return detail::error(llvm::inconvertibleErrorCode(), std::move(Msg));
9730667c96SSam McCall }
9830667c96SSam McCall 
99ad97ccf6SSam McCall // dlog only logs if --debug was passed, or --debug_only=Basename.
100ad97ccf6SSam McCall // This level would be enabled in a targeted way when debugging.
101ad97ccf6SSam McCall #define dlog(...)                                                              \
102ad97ccf6SSam McCall   DEBUG_WITH_TYPE(::clang::clangd::detail::debugType(__FILE__),                \
103ad97ccf6SSam McCall                   ::clang::clangd::detail::log(Logger::Debug, __VA_ARGS__))
104ad97ccf6SSam McCall 
105ad97ccf6SSam McCall /// Only one LoggingSession can be active at a time.
106ad97ccf6SSam McCall class LoggingSession {
107ad97ccf6SSam McCall public:
108ad97ccf6SSam McCall   LoggingSession(clangd::Logger &Instance);
109ad97ccf6SSam McCall   ~LoggingSession();
110ad97ccf6SSam McCall 
111ad97ccf6SSam McCall   LoggingSession(LoggingSession &&) = delete;
112ad97ccf6SSam McCall   LoggingSession &operator=(LoggingSession &&) = delete;
113ad97ccf6SSam McCall 
114ad97ccf6SSam McCall   LoggingSession(LoggingSession const &) = delete;
115ad97ccf6SSam McCall   LoggingSession &operator=(LoggingSession const &) = delete;
116ad97ccf6SSam McCall };
117ad97ccf6SSam McCall 
118ad97ccf6SSam McCall // Logs to an output stream, such as stderr.
119ad97ccf6SSam McCall class StreamLogger : public Logger {
120ad97ccf6SSam McCall public:
StreamLogger(llvm::raw_ostream & Logs,Logger::Level MinLevel)121ad97ccf6SSam McCall   StreamLogger(llvm::raw_ostream &Logs, Logger::Level MinLevel)
122ad97ccf6SSam McCall       : MinLevel(MinLevel), Logs(Logs) {}
123ad97ccf6SSam McCall 
124ad97ccf6SSam McCall   /// Write a line to the logging stream.
125*65eaec9bSSam McCall   void log(Level, const char *Fmt,
126*65eaec9bSSam McCall            const llvm::formatv_object_base &Message) override;
127ad97ccf6SSam McCall 
128ad97ccf6SSam McCall private:
129ad97ccf6SSam McCall   Logger::Level MinLevel;
130ad97ccf6SSam McCall   llvm::raw_ostream &Logs;
131ad97ccf6SSam McCall 
132ad97ccf6SSam McCall   std::mutex StreamMutex;
133ad97ccf6SSam McCall };
134ad97ccf6SSam McCall 
135ad97ccf6SSam McCall } // namespace clangd
136ad97ccf6SSam McCall } // namespace clang
137ad97ccf6SSam McCall 
138ad97ccf6SSam McCall #endif
139