1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "log.h" 18 19 #include <cctype> 20 #include <chrono> 21 #include <cstdio> 22 #include <string> 23 24 namespace android { 25 26 Log::LogLevel Log::level_; 27 Logger* Log::logger_; 28 std::chrono::time_point<std::chrono::steady_clock> Log::init_time_; 29 30 void Log::Initialize(Logger *logger, LogLevel level) { 31 if (Log::logger_) { 32 Log::Warn("Re-initializing logger"); 33 } 34 Log::init_time_ = std::chrono::steady_clock::now(); 35 Log::logger_ = logger; 36 Log::SetLevel(level); 37 } 38 39 void Log::SetLevel(LogLevel level) { 40 Log::level_ = level; 41 } 42 43 #define LOG_EX_VARARGS(level, format) \ 44 do { \ 45 va_list arg_list; \ 46 va_start(arg_list, format); \ 47 Log::LogEx(level, format, arg_list); \ 48 va_end(arg_list); \ 49 } while (0) 50 51 void Log::Error(const char *format, ...) { 52 LOG_EX_VARARGS(LogLevel::Error, format); 53 } 54 55 void Log::Warn(const char *format, ...) { 56 LOG_EX_VARARGS(LogLevel::Warn, format); 57 } 58 59 void Log::Info(const char *format, ...) { 60 LOG_EX_VARARGS(LogLevel::Info, format); 61 } 62 63 void Log::Debug(const char *format, ...) { 64 LOG_EX_VARARGS(LogLevel::Debug, format); 65 } 66 67 void Log::DebugBuf(std::vector<uint8_t> vec) { 68 Log::DebugBuf(vec.data(), vec.size()); 69 } 70 71 void Log::DebugBuf(const uint8_t *buffer, size_t size) { 72 if (Log::level_ < LogLevel::Debug) { 73 return; 74 } 75 76 char line[32]; 77 int offset = 0; 78 char line_chars[32]; 79 int offset_chars = 0; 80 81 Log::Debug("Dumping buffer of size %zu bytes", size); 82 for (size_t i = 1; i <= size; ++i) { 83 offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ", 84 buffer[i - 1]); 85 offset_chars += snprintf( 86 &line_chars[offset_chars], sizeof(line_chars) - offset_chars, 87 "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.'); 88 if ((i % 8) == 0) { 89 Log::Debug(" %s\t%s", line, line_chars); 90 offset = 0; 91 offset_chars = 0; 92 } else if ((i % 4) == 0) { 93 offset += snprintf(&line[offset], sizeof(line) - offset, " "); 94 } 95 } 96 97 if (offset > 0) { 98 std::string tabs; 99 while (offset < 28) { 100 tabs += "\t"; 101 offset += 8; 102 } 103 Log::Debug(" %s%s%s", line, tabs.c_str(), line_chars); 104 } 105 } 106 107 char Log::LevelAbbrev(LogLevel level) { 108 switch (level) { 109 case LogLevel::Error: 110 return 'E'; 111 case LogLevel::Warn: 112 return 'W'; 113 case LogLevel::Info: 114 return 'I'; 115 case LogLevel::Debug: 116 return 'D'; 117 default: 118 return '?'; 119 } 120 } 121 122 void Log::LogEx(LogLevel level, const char *format, va_list arg_list) { 123 if (Log::level_ < level) { 124 return; 125 } 126 127 std::chrono::duration<float> log_time = 128 (std::chrono::steady_clock::now() - Log::init_time_); 129 130 // Can add colorization here if desired (should be configurable) 131 char prefix[20]; 132 snprintf(prefix, sizeof(prefix), "%c %6.03f: ", Log::LevelAbbrev(level), 133 log_time.count()); 134 135 Log::logger_->Output(prefix); 136 Log::logger_->Output(format, arg_list); 137 Log::logger_->Output("\n"); 138 } 139 140 void PrintfLogger::Output(const char *str) { 141 printf("%s", str); 142 } 143 144 void PrintfLogger::Output(const char *format, va_list arg_list) { 145 vprintf(format, arg_list); 146 } 147 148 } // namespace android 149