blob: 33a384f9b32e92213d439c924db5db0250e4a6c8 [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Very simple logger that is similar to Chromium's logger. Example usage:
// LOG(INFO) << "hello world";
// LOG(INFO) << window << " says hello world";
#ifndef VM_TOOLS_SOMMELIER_SOMMELIER_LOGGING_H_
#define VM_TOOLS_SOMMELIER_SOMMELIER_LOGGING_H_
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <iosfwd>
#include <iostream>
#include <ostream>
#include <sstream>
#include <string>
#include "sommelier.h" // NOLINT(build/include_directory)
#include "sommelier-window.h" // NOLINT(build/include_directory)
// Build Sommelier with -Dlog_level=X to define LOG_LEVEL
#ifndef LOG_LEVEL
// Default log level is INFO
#define LOG_LEVEL 0
#endif // LOG_LEVEL
// Predefined log levels
constexpr int LOG_LEVEL_VERBOSE = -1;
constexpr int LOG_LEVEL_INFO = 0;
constexpr int LOG_LEVEL_WARNING = 1;
constexpr int LOG_LEVEL_ERROR = 2;
constexpr int LOG_LEVEL_FATAL = 3;
#define LOG(level) \
::logging::Log(LOG_LEVEL_##level, __func__, ::logging::file_name(__FILE__), \
__LINE__)
namespace logging {
std::string file_name(std::string file_path);
std::string log_level_to_string(int level);
// not thread-safe
extern int64_t min_log_level;
inline void set_min_log_level(int64_t level) {
min_log_level = level;
}
class Log {
private:
std::stringstream log_content;
public:
std::string function;
std::string file;
int line;
int log_level;
explicit Log(int log_level,
std::string function,
std::string file,
int line) {
this->log_level = log_level;
this->function = function;
this->file = file;
this->line = line;
}
template <typename T>
Log& operator<<(T const& value) {
if (log_level >= min_log_level) {
this->log_content << value;
}
return *this;
}
Log& operator<<(sl_window* window) {
*this << "(" << window->name << "#" << std::hex << window->id << ")"
<< std::dec;
return *this;
}
#ifdef GAMEPAD_SUPPORT
Log& operator<<(sl_host_gamepad* host_gamepad) {
*this << "(name=" << host_gamepad->name << ", bus=" << host_gamepad->bus
<< ", vendor_id=" << std::hex << host_gamepad->vendor_id
<< ", product_id=" << host_gamepad->product_id
<< ", version=" << host_gamepad->version << std::dec
<< ", input_mapping="
<< (host_gamepad->input_mapping ? host_gamepad->input_mapping->id
: "none")
<< ")";
return *this;
}
#endif
~Log() {
// Example expected usage:
// LOG(INFO) << "hello world ";
// Temporary objects are destroyed after the end of the expression, which
// means this destructor is called at 'semicolon', resulting in printing to
// cerr.
if (this->log_content.peek() == EOF) {
return;
}
std::cerr << log_level_to_string(this->log_level) << " <" << this->file
<< ":" << this->line << "> " << this->function << ": "
<< this->log_content.rdbuf() << std::endl;
}
};
} // namespace logging
#endif // VM_TOOLS_SOMMELIER_SOMMELIER_LOGGING_H_