mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-20 05:41:06 +00:00
d1ca56c8cd
Bug: 387 Change-Id: I720b7a99a1c7a24eb8e2554629529d1e24394cb1 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/49041 Reviewed-by: Keir Mierle <keir@google.com> Commit-Queue: Keir Mierle <keir@google.com>
163 lines
4.6 KiB
C++
163 lines
4.6 KiB
C++
// 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)
|
||
.IgnoreError(); // TODO(pwbug/387): 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<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
|