| // |
| // Copyright (c) 2010-2012 Linaro Limited |
| // |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the MIT License which accompanies |
| // this distribution, and is available at |
| // http://www.opensource.org/licenses/mit-license.php |
| // |
| // Contributors: |
| // Alexandros Frantzis <alexandros.frantzis@linaro.org> |
| // Jesse Barker <jesse.barker@linaro.org> |
| // |
| #include <unistd.h> |
| #include <cstdio> |
| #include <cstdarg> |
| #include <string> |
| #include <sstream> |
| #include <iostream> |
| #include "log.h" |
| |
| #ifdef ANDROID |
| #include <android/log.h> |
| #endif |
| |
| using std::string; |
| |
| const string Log::continuation_prefix("\x10"); |
| string Log::appname_; |
| bool Log::do_debug_(false); |
| std::ostream* Log::extra_out_(0); |
| |
| static const string terminal_color_normal("\033[0m"); |
| static const string terminal_color_red("\033[1;31m"); |
| static const string terminal_color_cyan("\033[36m"); |
| static const string terminal_color_yellow("\033[33m"); |
| static const string empty; |
| |
| static void |
| print_prefixed_message(std::ostream& stream, const string& color, const string& prefix, |
| const string& fmt, va_list ap) |
| { |
| va_list aq; |
| |
| /* Estimate message size */ |
| va_copy(aq, ap); |
| int msg_size = vsnprintf(NULL, 0, fmt.c_str(), aq); |
| va_end(aq); |
| |
| /* Create the buffer to hold the message */ |
| char *buf = new char[msg_size + 1]; |
| |
| /* Store the message in the buffer */ |
| va_copy(aq, ap); |
| vsnprintf(buf, msg_size + 1, fmt.c_str(), aq); |
| va_end(aq); |
| |
| /* |
| * Print the message lines prefixed with the supplied prefix. |
| * If the target stream is a terminal make the prefix colored. |
| */ |
| string linePrefix; |
| if (!prefix.empty()) |
| { |
| static const string colon(": "); |
| string start_color; |
| string end_color; |
| if (!color.empty()) |
| { |
| start_color = color; |
| end_color = terminal_color_normal; |
| } |
| linePrefix = start_color + prefix + end_color + colon; |
| } |
| |
| std::string line; |
| std::stringstream ss(buf); |
| |
| while(std::getline(ss, line)) { |
| /* |
| * If this line is a continuation of a previous log message |
| * just print the line plainly. |
| */ |
| if (line[0] == Log::continuation_prefix[0]) { |
| stream << line.c_str() + 1; |
| } |
| else { |
| /* Normal line, emit the prefix. */ |
| stream << linePrefix << line; |
| } |
| |
| /* Only emit a newline if the original message has it. */ |
| if (!(ss.rdstate() & std::stringstream::eofbit)) |
| stream << std::endl; |
| } |
| |
| delete[] buf; |
| } |
| |
| |
| void |
| Log::info(const char *fmt, ...) |
| { |
| static const string infoprefix("Info"); |
| const string& prefix(do_debug_ ? infoprefix : empty); |
| va_list ap; |
| va_start(ap, fmt); |
| |
| #ifndef ANDROID |
| static const string& infocolor(isatty(fileno(stdout)) ? terminal_color_cyan : empty); |
| const string& color(do_debug_ ? infocolor : empty); |
| print_prefixed_message(std::cout, color, prefix, fmt, ap); |
| #else |
| __android_log_vprint(ANDROID_LOG_INFO, appname_.c_str(), fmt, ap); |
| #endif |
| |
| if (extra_out_) |
| print_prefixed_message(*extra_out_, empty, prefix, fmt, ap); |
| |
| va_end(ap); |
| } |
| |
| void |
| Log::debug(const char *fmt, ...) |
| { |
| static const string dbgprefix("Debug"); |
| if (!do_debug_) |
| return; |
| va_list ap; |
| va_start(ap, fmt); |
| |
| #ifndef ANDROID |
| static const string& dbgcolor(isatty(fileno(stdout)) ? terminal_color_yellow : empty); |
| print_prefixed_message(std::cout, dbgcolor, dbgprefix, fmt, ap); |
| #else |
| __android_log_vprint(ANDROID_LOG_DEBUG, appname_.c_str(), fmt, ap); |
| #endif |
| |
| if (extra_out_) |
| print_prefixed_message(*extra_out_, empty, dbgprefix, fmt, ap); |
| |
| va_end(ap); |
| } |
| |
| void |
| Log::error(const char *fmt, ...) |
| { |
| static const string errprefix("Error"); |
| va_list ap; |
| va_start(ap, fmt); |
| |
| #ifndef ANDROID |
| static const string& errcolor(isatty(fileno(stderr)) ? terminal_color_red : empty); |
| print_prefixed_message(std::cerr, errcolor, errprefix, fmt, ap); |
| #else |
| __android_log_vprint(ANDROID_LOG_ERROR, appname_.c_str(), fmt, ap); |
| #endif |
| |
| if (extra_out_) |
| print_prefixed_message(*extra_out_, empty, errprefix, fmt, ap); |
| |
| va_end(ap); |
| } |
| |
| void |
| Log::flush() |
| { |
| #ifndef ANDROID |
| std::cout.flush(); |
| std::cerr.flush(); |
| #endif |
| if (extra_out_) |
| extra_out_->flush(); |
| } |