|
|
// 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 <cstring>
|
|
|
|
|
|
#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);
|
|
|
};
|
|
|
|
|
|
} // 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<150> 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<void>(file_name);
|
|
|
static_cast<void>(line_number);
|
|
|
#endif
|
|
|
|
|
|
// Column: Function
|
|
|
#if PW_LOG_SHOW_FUNCTION
|
|
|
buffer.Format(" %20s |", function_name);
|
|
|
#else
|
|
|
static_cast<void>(function_name);
|
|
|
#endif
|
|
|
|
|
|
// Column: Module
|
|
|
#if PW_LOG_SHOW_MODULE
|
|
|
buffer << " " BOLD;
|
|
|
buffer.Format("%3s", module_name);
|
|
|
buffer << RESET " ";
|
|
|
#else
|
|
|
static_cast<void>(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<void>(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
|