xref: /aosp_15_r20/external/pigweed/pw_log_basic/log_basic.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // 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 
21 #include "pw_log/levels.h"
22 #include "pw_log_basic_private/config.h"
23 #include "pw_string/string_builder.h"
24 #include "pw_sys_io/sys_io.h"
25 
26 // ANSI color constants to control the terminal. Not Windows compatible.
27 // clang-format off
28 #define MAGENTA   "\033[35m"
29 #define YELLOW    "\033[33m"
30 #define RED       "\033[31m"
31 #define GREEN     "\033[32m"
32 #define BLUE      "\033[96m"
33 #define BLACK     "\033[30m"
34 #define YELLOW_BG "\033[43m"
35 #define WHITE_BG  "\033[47m"
36 #define RED_BG    "\033[41m"
37 #define BOLD      "\033[1m"
38 #define RESET     "\033[0m"
39 // clang-format on
40 
41 namespace pw::log_basic {
42 namespace {
43 
LogLevelToLogLevelName(int level)44 const char* LogLevelToLogLevelName(int level) {
45   switch (level) {
46     // clang-format off
47 #if PW_EMOJI
48     case PW_LOG_LEVEL_DEBUG    : return "��" RESET;
49     case PW_LOG_LEVEL_INFO     : return "ℹ️ " RESET;
50     case PW_LOG_LEVEL_WARN     : return "⚠️ " RESET;
51     case PW_LOG_LEVEL_ERROR    : return "❌" RESET;
52     case PW_LOG_LEVEL_CRITICAL : return "☠️ " RESET;
53     default: return "❔" RESET;
54 #else
55     case PW_LOG_LEVEL_DEBUG    : return BLUE     BOLD        "DBG" RESET;
56     case PW_LOG_LEVEL_INFO     : return MAGENTA  BOLD        "INF" RESET;
57     case PW_LOG_LEVEL_WARN     : return YELLOW   BOLD        "WRN" RESET;
58     case PW_LOG_LEVEL_ERROR    : return RED      BOLD        "ERR" RESET;
59     case PW_LOG_LEVEL_CRITICAL : return BLACK    BOLD RED_BG "FTL" RESET;
60     default                    : return GREEN    BOLD        "UNK" RESET;
61 #endif
62       // clang-format on
63   }
64 }
65 
66 #if PW_LOG_SHOW_FILENAME
GetFileBasename(const char * filename)67 const char* GetFileBasename(const char* filename) {
68   int length = std::strlen(filename);
69   if (length == 0) {
70     return filename;
71   }
72 
73   // Start on the last character.
74   // TODO(pwbug/38): This part of the function doesn't work for Windows paths.
75   const char* basename = filename + std::strlen(filename) - 1;
76   while (basename != filename && *basename != '/') {
77     basename--;
78   }
79   if (*basename == '/') {
80     basename++;
81   }
82   return basename;
83 }
84 #endif  // PW_LOG_SHOW_FILENAME
85 
__anon1f1b52ea0202(std::string_view log) 86 void (*write_log)(std::string_view) = [](std::string_view log) {
87   sys_io::WriteLine(log)
88       .IgnoreError();  // TODO: b/242598609 - Handle Status properly
89 };
90 
91 }  // namespace
92 
93 // This is a fully loaded, inefficient-at-the-callsite, log implementation.
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,...)94 extern "C" void pw_Log(int level,
95                        unsigned int flags,
96                        const char* module_name,
97                        const char* file_name,
98                        int line_number,
99                        const char* function_name,
100                        const char* message,
101                        ...) {
102   va_list args;
103   va_start(args, message);
104   pw_Log_HandleMessageVaList(level,
105                              flags,
106                              module_name,
107                              file_name,
108                              line_number,
109                              function_name,
110                              message,
111                              args);
112   va_end(args);
113 }
114 
pw_Log_HandleMessageVaList(int level,unsigned int flags,const char * module_name,const char * file_name,int line_number,const char * function_name,const char * message,va_list args)115 extern "C" void pw_Log_HandleMessageVaList(int level,
116                                            unsigned int flags,
117                                            const char* module_name,
118                                            const char* file_name,
119                                            int line_number,
120                                            const char* function_name,
121                                            const char* message,
122                                            va_list args) {
123   // Accumulate the log message in this buffer, then output it.
124   pw::StringBuffer<PW_LOG_BASIC_ENTRY_SIZE> buffer;
125 
126   // Column: Timestamp
127   // Note that this macro method defaults to a no-op.
128   PW_LOG_APPEND_TIMESTAMP(buffer);
129 
130   // Column: Filename
131 #if PW_LOG_SHOW_FILENAME
132   buffer.Format(" %-30s:%4d |", GetFileBasename(file_name), line_number);
133 #else
134   static_cast<void>(file_name);
135   static_cast<void>(line_number);
136 #endif
137 
138   // Column: Function
139 #if PW_LOG_SHOW_FUNCTION
140   buffer.Format(" %20s |", function_name);
141 #else
142   static_cast<void>(function_name);
143 #endif
144 
145   // Column: Module
146 #if PW_LOG_SHOW_MODULE
147   buffer << " " BOLD;
148   buffer.Format("%3s", module_name);
149   buffer << RESET " ";
150 #else
151   static_cast<void>(module_name);
152 #endif  // PW_LOG_SHOW_MODULE
153 
154   // Column: Flag
155 #if PW_LOG_SHOW_FLAG
156 #if PW_EMOJI
157   buffer << (flags ? "��" : "  ");
158 #else
159   buffer << (flags ? "*" : "|");
160 #endif  // PW_EMOJI
161   buffer << " ";
162 #else
163   static_cast<void>(flags);
164 #endif  // PW_LOG_SHOW_FLAG
165 
166   // Column: Level
167   buffer << LogLevelToLogLevelName(level) << "  ";
168 
169   // Column: Message
170   buffer.FormatVaList(message, args);
171 
172   // All done; flush the log.
173   write_log(buffer);
174 }
175 
SetOutput(void (* log_output)(std::string_view log))176 void SetOutput(void (*log_output)(std::string_view log)) {
177   write_log = log_output;
178 }
179 
180 }  // namespace pw::log_basic
181