blob: 18423a37f4fce58d30a619dc5a25cbd010143c83 [file] [log] [blame]
Keir Mierleaf5e3582019-12-30 13:11:05 -08001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15// This is a very basic direct output log implementation with no buffering.
16
17#include "pw_log_basic/log_basic.h"
18
19#include <cstring>
20
Keir Mierleaf5e3582019-12-30 13:11:05 -080021#include "pw_log/levels.h"
22#include "pw_string/string_builder.h"
Armando Montanezf7a5a742020-03-02 14:58:59 -080023#include "pw_sys_io/sys_io.h"
Keir Mierleaf5e3582019-12-30 13:11:05 -080024
25// ANSI color constants to control the terminal. Not Windows compatible.
26// clang-format off
27#define MAGENTA "\033[35m"
28#define YELLOW "\033[33m"
29#define RED "\033[31m"
30#define GREEN "\033[32m"
31#define BLUE "\033[96m"
32#define BLACK "\033[30m"
33#define YELLOW_BG "\033[43m"
34#define WHITE_BG "\033[47m"
35#define RED_BG "\033[41m"
36#define BOLD "\033[1m"
37#define RESET "\033[0m"
38// clang-format on
39
Armando Montaneza1065b92020-03-19 12:36:31 -070040#ifndef PW_EMOJI
41#define PW_EMOJI 0
42#endif // PW_EMOJI
43
Keir Mierleaf5e3582019-12-30 13:11:05 -080044// TODO(pwbug/17): Expose these through the config system.
Keir Mierleaf5e3582019-12-30 13:11:05 -080045#define PW_LOG_SHOW_FILENAME 0
Keir Mierle8c352dc2020-02-02 13:58:19 -080046#define PW_LOG_SHOW_FUNCTION 0
Keir Mierleaf5e3582019-12-30 13:11:05 -080047#define PW_LOG_SHOW_FLAG 0
Keir Mierleda0bccb2020-01-17 13:51:35 -080048#define PW_LOG_SHOW_MODULE 0
Keir Mierleaf5e3582019-12-30 13:11:05 -080049
Wyatt Hepler2ccde062020-09-16 21:58:53 -070050namespace pw::log_basic {
Keir Mierleaf5e3582019-12-30 13:11:05 -080051namespace {
52
53const char* LogLevelToLogLevelName(int level) {
54 switch (level) {
55 // clang-format off
Armando Montaneza1065b92020-03-19 12:36:31 -070056#if PW_EMOJI
Keir Mierleaf5e3582019-12-30 13:11:05 -080057 case PW_LOG_LEVEL_DEBUG : return "👾" RESET;
58 case PW_LOG_LEVEL_INFO : return "ℹī¸ " RESET;
59 case PW_LOG_LEVEL_WARN : return "⚠ī¸ " RESET;
60 case PW_LOG_LEVEL_ERROR : return "❌" RESET;
61 case PW_LOG_LEVEL_CRITICAL : return "☠ī¸ " RESET;
62 default: return "❔" RESET;
63#else
64 case PW_LOG_LEVEL_DEBUG : return BLUE BOLD "DBG" RESET;
65 case PW_LOG_LEVEL_INFO : return MAGENTA BOLD "INF" RESET;
66 case PW_LOG_LEVEL_WARN : return YELLOW BOLD "WRN" RESET;
67 case PW_LOG_LEVEL_ERROR : return RED BOLD "ERR" RESET;
68 case PW_LOG_LEVEL_CRITICAL : return BLACK BOLD RED_BG "FTL" RESET;
69 default : return GREEN BOLD "UNK" RESET;
70#endif
71 // clang-format on
72 }
73}
74
75#if PW_LOG_SHOW_FILENAME
76const char* GetFileBasename(const char* filename) {
77 int length = std::strlen(filename);
78 if (length == 0) {
79 return filename;
80 }
81
82 // Start on the last character.
83 // TODO(pwbug/38): This part of the function doesn't work for Windows paths.
84 const char* basename = filename + std::strlen(filename) - 1;
85 while (basename != filename && *basename != '/') {
86 basename--;
87 }
88 if (*basename == '/') {
89 basename++;
90 }
91 return basename;
92}
93#endif // PW_LOG_SHOW_FILENAME
94
Wyatt Hepler2ccde062020-09-16 21:58:53 -070095void (*write_log)(std::string_view) = [](std::string_view log) {
96 sys_io::WriteLine(log);
97};
98
Keir Mierleaf5e3582019-12-30 13:11:05 -080099} // namespace
100
101// This is a fully loaded, inefficient-at-the-callsite, log implementation.
102extern "C" void pw_Log(int level,
103 unsigned int flags,
104 const char* module_name,
105 const char* file_name,
106 int line_number,
107 const char* function_name,
108 const char* message,
109 ...) {
Keir Mierleaf5e3582019-12-30 13:11:05 -0800110 // Accumulate the log message in this buffer, then output it.
111 pw::StringBuffer<150> buffer;
112
113 // Column: Filename
Keir Mierleda0bccb2020-01-17 13:51:35 -0800114#if PW_LOG_SHOW_FILENAME
Keir Mierle8c352dc2020-02-02 13:58:19 -0800115 buffer.Format(" %-30s:%4d |", GetFileBasename(file_name), line_number);
Keir Mierleaf5e3582019-12-30 13:11:05 -0800116#else
117 PW_UNUSED(file_name);
Keir Mierle8c352dc2020-02-02 13:58:19 -0800118 PW_UNUSED(line_number);
119#endif
120
121 // Column: Function
122#if PW_LOG_SHOW_FUNCTION
123 buffer.Format(" %20s |", function_name);
124#else
125 PW_UNUSED(function_name);
Keir Mierleaf5e3582019-12-30 13:11:05 -0800126#endif
127
128 // Column: Module
Keir Mierleda0bccb2020-01-17 13:51:35 -0800129#if PW_LOG_SHOW_MODULE
Keir Mierleaf5e3582019-12-30 13:11:05 -0800130 buffer << " " BOLD;
131 buffer.Format("%3s", module_name);
132 buffer << RESET " ";
Keir Mierleda0bccb2020-01-17 13:51:35 -0800133#else
134 PW_UNUSED(module_name);
135#endif // PW_LOG_SHOW_MODULE
Keir Mierleaf5e3582019-12-30 13:11:05 -0800136
137 // Column: Flag
138#if PW_LOG_SHOW_FLAG
Armando Montaneza1065b92020-03-19 12:36:31 -0700139#if PW_EMOJI
Keir Mierleaf5e3582019-12-30 13:11:05 -0800140 buffer << (flags ? "🚩" : " ");
141#else
142 buffer << (flags ? "*" : "|");
Armando Montaneza1065b92020-03-19 12:36:31 -0700143#endif // PW_EMOJI
Keir Mierleaf5e3582019-12-30 13:11:05 -0800144 buffer << " ";
145#else
146 PW_UNUSED(flags);
147#endif // PW_LOG_SHOW_FLAG
148
149 // Column: Level
Keir Mierleda0bccb2020-01-17 13:51:35 -0800150 buffer << LogLevelToLogLevelName(level) << " ";
Keir Mierleaf5e3582019-12-30 13:11:05 -0800151
152 // Column: Message
153 va_list args;
154 va_start(args, message);
Wyatt Hepler2596fe52020-01-23 17:40:10 -0800155 buffer.FormatVaList(message, args);
Keir Mierleaf5e3582019-12-30 13:11:05 -0800156 va_end(args);
157
158 // All done; flush the log.
Wyatt Hepler2ccde062020-09-16 21:58:53 -0700159 write_log(buffer);
Keir Mierleaf5e3582019-12-30 13:11:05 -0800160}
Wyatt Hepler2ccde062020-09-16 21:58:53 -0700161
162void SetOutput(void (*log_output)(std::string_view log)) {
163 write_log = log_output;
164}
165
166} // namespace pw::log_basic