| // Copyright 2023 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef NINJA_LOGGER_H_ |
| #define NINJA_LOGGER_H_ |
| |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <memory> |
| #include <ostream> |
| #include <string> |
| #include "string_piece.h" |
| |
| /// Convenience class to send log messages to various destinations, for |
| /// example to an stdio FILE* instance, a C++ std::ostream instance, |
| /// or a string buffer. |
| /// |
| /// Usage is: |
| /// - Create instance using one of the Logger::CreateXXX() static |
| /// method (each one selects a different destination), or even |
| /// the default constructor (which doesn't do anything). |
| /// |
| /// - Call `log.Log("message")` or `log.Log("formatted %s", "message")` |
| /// to send messages to the log. |
| /// |
| /// - Call `log.Logv(fmt, args)` when you have a printf-style formatting |
| /// string and a va_list value for formatting arguments instead. |
| /// |
| /// - Use the `log.enabled()` method to avoid doing complex computations |
| /// or allocations when logging is not necessary, for example, the |
| /// following line will always call std::to_string() and allocate |
| /// a temporary string, even if logging is disabled: |
| /// |
| /// log.Log("Error: %s", std::to_string(value).c_str()); |
| /// |
| /// Instead, use: |
| /// |
| /// log.enabled() && log.Log("Error: %s", std::to_string(value).c_str()); |
| /// |
| /// This is why each Log() and Logv() method returns a boolean, |
| /// which will be true if something was logged, and false otherwise. |
| /// |
| /// Another alternative is to use: |
| /// |
| /// LOGGER_LOG(log, "Error: %s", std::to_string(value).c_str()) |
| /// |
| /// which expands to the same thing. |
| /// |
| /// Note that: |
| /// |
| /// - Each Logger instance is only one pointer long, and thus can be |
| /// embedded in objects that need them easily. |
| /// |
| /// - Each log message is considered independent from the others, there |
| /// is no feature to decompose a single message into multiple Log() |
| /// calls. |
| /// |
| class Logger { |
| public: |
| /// Internal interface used by each implementation instance. |
| class Backend { |
| public: |
| virtual ~Backend() {} |
| virtual bool Log(StringPiece message) = 0; |
| virtual bool Log(const char* fmt, va_list args); |
| virtual bool enabled() const { return true; } |
| }; |
| |
| /// Default constructor creates an empty logger. All messages are lost. |
| Logger() = default; |
| |
| /// Create new instance that sends all messages to an stdio stream. |
| /// Each message will be followed by a newline. |
| static Logger CreateForStdio(FILE* stream); |
| |
| /// Create a new instance that sends all messages to an std::ostream |
| /// Each message will be followed by a newline. |
| static Logger CreateForStd(std::ostream& out); |
| |
| /// Create a new instance that appends all messages to a string. |
| /// Each message will be followed by a newline character. |
| static Logger CreateForString(std::string* messages); |
| |
| /// Create new instance that redirects everything to another logger. |
| static Logger CreateProxyFor(const Logger& logger); |
| |
| /// Create new instance that sends each message to two distinct loggers. |
| static Logger CreateTeeFor(const Logger& logger_a, const Logger& logger_b); |
| |
| /// Create new instance from custom Backend implementation provided |
| /// by the caller. |
| static Logger CreateForBackend(std::unique_ptr<Backend> backend); |
| |
| /// Return true if this logger is enabled. False means that any |
| /// message is lost. Useful to avoid doing un-necessary work. |
| bool enabled() const; |
| |
| /// Send formatted message to the log. |
| bool Log(StringPiece message) const; |
| |
| /// Send printf-formatted message to the log. |
| bool Log(const char* fmt, ...) const; |
| |
| /// Send vprintf-formatted message to the log. |
| bool Logv(const char* fmt, va_list args) const; |
| |
| protected: |
| /// Constructor takes ownership of new |backend| object. |
| explicit Logger(Backend* backend) : backend_(backend) {} |
| explicit Logger(std::unique_ptr<Backend> backend) |
| : backend_(std::move(backend)) {} |
| |
| std::unique_ptr<Backend> backend_; |
| }; |
| |
| /// A convenience macro used to only log arguments when the logger |
| /// is enabled. This expands to a boolean value which will be true |
| /// if something was logged. |
| #define LOGGER_LOG(log, ...) ((log).enabled() && (log).Log(__VA_ARGS__)) |
| |
| #endif // NINJA_LOGGER_H_ |