// Copyright 2020 The Pigweed Authors // // 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 // // https://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. // This is a very basic direct output log implementation with no buffering. #include "pw_log_basic/log_basic.h" #include #include "pw_log/levels.h" #include "pw_log_basic_private/config.h" #include "pw_string/string_builder.h" #include "pw_sys_io/sys_io.h" // ANSI color constants to control the terminal. Not Windows compatible. // clang-format off #define MAGENTA "\033[35m" #define YELLOW "\033[33m" #define RED "\033[31m" #define GREEN "\033[32m" #define BLUE "\033[96m" #define BLACK "\033[30m" #define YELLOW_BG "\033[43m" #define WHITE_BG "\033[47m" #define RED_BG "\033[41m" #define BOLD "\033[1m" #define RESET "\033[0m" // clang-format on namespace pw::log_basic { namespace { const char* LogLevelToLogLevelName(int level) { switch (level) { // clang-format off #if PW_EMOJI case PW_LOG_LEVEL_DEBUG : return "👾" RESET; case PW_LOG_LEVEL_INFO : return "ℹī¸ " RESET; case PW_LOG_LEVEL_WARN : return "⚠ī¸ " RESET; case PW_LOG_LEVEL_ERROR : return "❌" RESET; case PW_LOG_LEVEL_CRITICAL : return "☠ī¸ " RESET; default: return "❔" RESET; #else case PW_LOG_LEVEL_DEBUG : return BLUE BOLD "DBG" RESET; case PW_LOG_LEVEL_INFO : return MAGENTA BOLD "INF" RESET; case PW_LOG_LEVEL_WARN : return YELLOW BOLD "WRN" RESET; case PW_LOG_LEVEL_ERROR : return RED BOLD "ERR" RESET; case PW_LOG_LEVEL_CRITICAL : return BLACK BOLD RED_BG "FTL" RESET; default : return GREEN BOLD "UNK" RESET; #endif // clang-format on } } #if PW_LOG_SHOW_FILENAME const char* GetFileBasename(const char* filename) { int length = std::strlen(filename); if (length == 0) { return filename; } // Start on the last character. // TODO(pwbug/38): This part of the function doesn't work for Windows paths. const char* basename = filename + std::strlen(filename) - 1; while (basename != filename && *basename != '/') { basename--; } if (*basename == '/') { basename++; } return basename; } #endif // PW_LOG_SHOW_FILENAME void (*write_log)(std::string_view) = [](std::string_view log) { sys_io::WriteLine(log) .IgnoreError(); // TODO: b/242598609 - Handle Status properly }; } // namespace // This is a fully loaded, inefficient-at-the-callsite, log implementation. extern "C" void pw_Log(int level, unsigned int flags, const char* module_name, const char* file_name, int line_number, const char* function_name, const char* message, ...) { // Accumulate the log message in this buffer, then output it. pw::StringBuffer buffer; // Column: Timestamp // Note that this macro method defaults to a no-op. PW_LOG_APPEND_TIMESTAMP(buffer); // Column: Filename #if PW_LOG_SHOW_FILENAME buffer.Format(" %-30s:%4d |", GetFileBasename(file_name), line_number); #else static_cast(file_name); static_cast(line_number); #endif // Column: Function #if PW_LOG_SHOW_FUNCTION buffer.Format(" %20s |", function_name); #else static_cast(function_name); #endif // Column: Module #if PW_LOG_SHOW_MODULE buffer << " " BOLD; buffer.Format("%3s", module_name); buffer << RESET " "; #else static_cast(module_name); #endif // PW_LOG_SHOW_MODULE // Column: Flag #if PW_LOG_SHOW_FLAG #if PW_EMOJI buffer << (flags ? "🚩" : " "); #else buffer << (flags ? "*" : "|"); #endif // PW_EMOJI buffer << " "; #else static_cast(flags); #endif // PW_LOG_SHOW_FLAG // Column: Level buffer << LogLevelToLogLevelName(level) << " "; // Column: Message va_list args; va_start(args, message); buffer.FormatVaList(message, args); va_end(args); // All done; flush the log. write_log(buffer); } void SetOutput(void (*log_output)(std::string_view log)) { write_log = log_output; } } // namespace pw::log_basic