C++程序  |  149行  |  3.83 KB

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "log.h"

#include <cctype>
#include <chrono>
#include <cstdio>
#include <string>

namespace android {

Log::LogLevel Log::level_;
Logger* Log::logger_;
std::chrono::time_point<std::chrono::steady_clock> Log::init_time_;

void Log::Initialize(Logger *logger, LogLevel level) {
    if (Log::logger_) {
        Log::Warn("Re-initializing logger");
    }
    Log::init_time_ = std::chrono::steady_clock::now();
    Log::logger_ = logger;
    Log::SetLevel(level);
}

void Log::SetLevel(LogLevel level) {
    Log::level_ = level;
}

#define LOG_EX_VARARGS(level, format) \
    do { \
        va_list arg_list; \
        va_start(arg_list, format); \
        Log::LogEx(level, format, arg_list); \
        va_end(arg_list); \
    } while (0)

void Log::Error(const char *format, ...) {
    LOG_EX_VARARGS(LogLevel::Error, format);
}

void Log::Warn(const char *format, ...) {
    LOG_EX_VARARGS(LogLevel::Warn, format);
}

void Log::Info(const char *format, ...) {
    LOG_EX_VARARGS(LogLevel::Info, format);
}

void Log::Debug(const char *format, ...) {
    LOG_EX_VARARGS(LogLevel::Debug, format);
}

void Log::DebugBuf(std::vector<uint8_t> vec) {
    Log::DebugBuf(vec.data(), vec.size());
}

void Log::DebugBuf(const uint8_t *buffer, size_t size) {
    if (Log::level_ < LogLevel::Debug) {
        return;
    }

    char line[32];
    int offset = 0;
    char line_chars[32];
    int offset_chars = 0;

    Log::Debug("Dumping buffer of size %zu bytes", size);
    for (size_t i = 1; i <= size; ++i) {
        offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
                           buffer[i - 1]);
        offset_chars += snprintf(
            &line_chars[offset_chars], sizeof(line_chars) - offset_chars,
            "%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
        if ((i % 8) == 0) {
            Log::Debug("  %s\t%s", line, line_chars);
            offset = 0;
            offset_chars = 0;
        } else if ((i % 4) == 0) {
            offset += snprintf(&line[offset], sizeof(line) - offset, " ");
        }
    }

    if (offset > 0) {
        std::string tabs;
        while (offset < 28) {
            tabs += "\t";
            offset += 8;
        }
        Log::Debug("  %s%s%s", line, tabs.c_str(), line_chars);
    }
}

char Log::LevelAbbrev(LogLevel level) {
    switch (level) {
    case LogLevel::Error:
        return 'E';
    case LogLevel::Warn:
        return 'W';
    case LogLevel::Info:
        return 'I';
    case LogLevel::Debug:
        return 'D';
    default:
        return '?';
    }
}

void Log::LogEx(LogLevel level, const char *format, va_list arg_list) {
    if (Log::level_ < level) {
        return;
    }

    std::chrono::duration<float> log_time =
        (std::chrono::steady_clock::now() - Log::init_time_);

    // Can add colorization here if desired (should be configurable)
    char prefix[20];
    snprintf(prefix, sizeof(prefix), "%c %6.03f: ", Log::LevelAbbrev(level),
             log_time.count());

    Log::logger_->Output(prefix);
    Log::logger_->Output(format, arg_list);
    Log::logger_->Output("\n");
}

void PrintfLogger::Output(const char *str) {
    printf("%s", str);
}

void PrintfLogger::Output(const char *format, va_list arg_list) {
    vprintf(format, arg_list);
}

}  // namespace android