Documented log class (#4711)

* Documented log class

* cspell
This commit is contained in:
Larry Osterman 2023-06-12 16:59:28 -07:00 committed by GitHub
parent 5a9106f2a5
commit 0b59e5a94c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 137 additions and 7 deletions

View File

@ -12,6 +12,47 @@
#include <type_traits>
namespace Azure { namespace Core { namespace Diagnostics { namespace _internal {
/** @brief Internal Log class used for generating diagnostic logs.
*
* When components within the Azure SDK wish to emit diagnostic log messages, they should use the
* Azure::Core::Diagnostics::_internal::Log class to generate those messages.
*
* The Log class methods integrate with the public diagnostic logging infrastructure to generate
* log messages which will be captured by either the default logger or a customer provided logger.
*
* Usage:
*
* There are two primary interfaces to the Log class. The first (and most common) is to use the
* Log::Write method to write a string to the configured logger. For example:
*
* ```cpp
* using namespace Azure::Core::Diagnostics::_internal;
* using namespace Azure::Core::Diagnostics;
* :
* :
* Log::Write(Logger::Level::Verbose, "This is a diagnostic message");
* ```
*
* this will pass the string "This is a diagnostic message" to the configured logger at the
* "Verbose" error level.
*
* The second interface is to use the Log::Stream() class to stream a string to the configured
* logger. For example:
*
* ```cpp
* using namespace Azure::Core::Diagnostics::_internal;
* using namespace Azure::Core::Diagnostics;
* :
* :
* int resultCode = 500;
* Log::Stream(Logger::Level::Error) << "An error has occurred " << resultCode;
* ```
*
* this will pass the string "An error has occurred 500" to the configured logger at the "Error"
* error level.
*
*/
class Log final {
static_assert(
std::is_same<int, std::underlying_type<Logger::Level>::type>::value == true,
@ -27,20 +68,35 @@ namespace Azure { namespace Core { namespace Diagnostics { namespace _internal {
Log() = delete;
~Log() = delete;
/** @brief String buffer for use in the logger.
*
* A specialization of std::stringbuf for use in the logger.
*
* This function primarily exists to implement the sync() function which triggers a call to
* Log::Write().
*/
class LoggerStringBuffer : public std::stringbuf {
public:
/** @brief Configure a LogStringBuffer with the specified logging level. */
LoggerStringBuffer(Logger::Level level) : m_level{level} {}
LoggerStringBuffer(LoggerStringBuffer&& that) = default;
LoggerStringBuffer& operator=(LoggerStringBuffer&& that) = default;
~LoggerStringBuffer() override = default;
/** @brief Implementation of std::basic_streambuf<char>::sync.
*
* @returns 0 on success, -1 otherwise.
*/
virtual int sync() override;
private:
Logger::Level m_level;
};
public:
/** @brief Logger Stream used internally by the GetStream() private method.
*
* Stream class used to wrap a LoggerStringBuffer stringbuf object.
*/
class LoggerStream : public std::basic_ostream<char> {
public:
LoggerStream(Logger::Level level) : std::ostream(&m_stringBuffer), m_stringBuffer{level} {}
@ -50,30 +106,105 @@ namespace Azure { namespace Core { namespace Diagnostics { namespace _internal {
LoggerStringBuffer m_stringBuffer;
};
public:
/** @brief Stream class used to enable using iomanip operators on an I/O stream.
* Usage:
*
* ```cpp
* using namespace Azure::Core::Diagnostics::_internal;
* using namespace Azure::Core::Diagnostics;
* :
* :
* int resultCode = 500;
* Log::Stream(Logger::Level::Error) << "An error has occurred " << resultCode;
* ```
*
* this will pass the string "An error has occurred 500" to the configured logger at the "Error"
* error level.
*
* @remarks The Log::Stream() construct creates a temporary Stream object whose lifetime ends a
* the end of the statement creating the Stream object. In the destructor for the stream, the
* underlying stream object is flushed thus ensuring that the output is generated at the end of
* the statement, even if the caller does not insert the std::endl object.
*/
class Stream {
public:
/** @brief Construct a new Stream object with the configured I/O level.
*
* @param level - Represents the desired diagnostic level for the operation.
*/
Stream(Logger::Level level) : m_stream(GetStream(level)) {}
/** @brief Called when the Stream object goes out of scope. */
~Stream() { m_stream.flush(); }
Stream(Stream const&) = delete;
Stream& operator=(Stream const&) = delete;
/** @brief Insert an object of type T into the output stream.
*
* @tparam T Type of the object being inserted.
* @param val value to be inserted into the underlying stream.
*/
template <typename T> std::ostream& operator<<(T val) { return m_stream << val; }
private:
LoggerStream& m_stream;
};
/** @brief Returns true if the logger would write a string at the specified level.
*
* This function primarily exists to enable callers to avoid expensive computations if the
* currently configured log level doesn't support logging at the specified level.
*
* @param level - log level to check.
* @returns true if the logger will write at that log level.
*/
static bool ShouldWrite(Logger::Level level)
{
return g_isLoggingEnabled && level >= g_logLevel;
}
/** @brief Write a string to the configured logger at the specified log level.
*
* Expected usage:
*
* ```cpp
* using namespace Azure::Core::Diagnostics::_internal;
* using namespace Azure::Core::Diagnostics;
* :
* :
* Log::Write(Logger::Level::Verbose, "This is a diagnostic message");
* ```
*
* this will pass the string "This is a diagnostic message" to the configured logger at the
* "Verbose" error level.
*
* @param level - log level to use for the message.
* @param message - message to write to the logger.
*
*/
static void Write(Logger::Level level, std::string const& message);
/** @brief Enable logging.
*
* @param isEnabled - true if logging should be enabled, false if it should be disabled.
*/
static void EnableLogging(bool isEnabled);
/** @brief Set the current log level globally.
*
* Note that this overrides any customer configuration of the log level and should generally be
* avoided.
*
* @param logLevel - New global log level.
*/
static void SetLogLevel(Logger::Level logLevel);
private:
static LoggerStream g_verboseLogger;
static LoggerStream g_informationalLogger;
static LoggerStream g_warningLogger;
static LoggerStream g_errorLogger;
static LoggerStream& GetStream(Logger::Level level);
};
}}}} // namespace Azure::Core::Diagnostics::_internal

View File

@ -61,12 +61,11 @@ int Log::LoggerStringBuffer::sync()
str(std::string());
return 0;
}
namespace {
static Log::LoggerStream g_verboseLogger{Logger::Level::Verbose};
static Log::LoggerStream g_informationalLogger{Logger::Level::Informational};
static Log::LoggerStream g_warningLogger{Logger::Level::Warning};
static Log::LoggerStream g_errorLogger{Logger::Level::Error};
} // namespace
Log::LoggerStream Log::g_verboseLogger{Logger::Level::Verbose};
Log::LoggerStream Log::g_informationalLogger{Logger::Level::Informational};
Log::LoggerStream Log::g_warningLogger{Logger::Level::Warning};
Log::LoggerStream Log::g_errorLogger{Logger::Level::Error};
/** Returns a custom ostream implementation with a logger based stream buffer.
* @param level The level of the log message.