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 
Initialize(Logger * logger,LogLevel level)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 
SetLevel(LogLevel level)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 
Error(const char * format,...)51 void Log::Error(const char *format, ...) {
52     LOG_EX_VARARGS(LogLevel::Error, format);
53 }
54 
Warn(const char * format,...)55 void Log::Warn(const char *format, ...) {
56     LOG_EX_VARARGS(LogLevel::Warn, format);
57 }
58 
Info(const char * format,...)59 void Log::Info(const char *format, ...) {
60     LOG_EX_VARARGS(LogLevel::Info, format);
61 }
62 
Debug(const char * format,...)63 void Log::Debug(const char *format, ...) {
64     LOG_EX_VARARGS(LogLevel::Debug, format);
65 }
66 
DebugBuf(std::vector<uint8_t> vec)67 void Log::DebugBuf(std::vector<uint8_t> vec) {
68     Log::DebugBuf(vec.data(), vec.size());
69 }
70 
DebugBuf(const uint8_t * buffer,size_t size)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 
LevelAbbrev(LogLevel level)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 
LogEx(LogLevel level,const char * format,va_list arg_list)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 
Output(const char * str)140 void PrintfLogger::Output(const char *str) {
141     printf("%s", str);
142 }
143 
Output(const char * format,va_list arg_list)144 void PrintfLogger::Output(const char *format, va_list arg_list) {
145     vprintf(format, arg_list);
146 }
147 
148 }  // namespace android
149