blob: e45e5416e48d1fc01d65520d1309278b8a542283 [file] [log] [blame]
/*
* Copyright 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.
*/
#pragma once
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#include <fmt/format.h>
#include <log/log.h>
#pragma clang diagnostic pop
#include <type_traits>
namespace android {
namespace gfx {
/* SafeLog is a mix-in that can be used to easily add typesafe logging using fmtlib to any class.
* To use it, inherit from it using CRTP and implement the getLogTag method.
*
* For example:
*
* class Frobnicator : private SafeLog<Frobnicator> {
* friend class SafeLog<Frobnicator>; // Allows getLogTag to be private
*
* public:
* void frobnicate(int32_t i);
*
* private:
* // SafeLog does member access on the object calling alog*, so this tag can theoretically vary
* // by instance unless getLogTag is made static
* const char* getLogTag() { return "Frobnicator"; }
* };
*
* void Frobnicator::frobnicate(int32_t i) {
* // Logs something like "04-16 21:35:46.811 3513 3513 I Frobnicator: frobnicating 42"
* alogi("frobnicating {}", i);
* }
*
* See http://fmtlib.net for more information on the formatting API.
*/
template <typename T>
class SafeLog {
protected:
template <typename... Args>
#if LOG_NDEBUG
void alogv(Args&&... /*unused*/) const {
}
#else
void alogv(Args&&... args) const {
alog<ANDROID_LOG_VERBOSE>(std::forward<Args>(args)...);
}
#endif
template <typename... Args>
void alogd(Args&&... args) const {
alog<ANDROID_LOG_DEBUG>(std::forward<Args>(args)...);
}
template <typename... Args>
void alogi(Args&&... args) const {
alog<ANDROID_LOG_INFO>(std::forward<Args>(args)...);
}
template <typename... Args>
void alogw(Args&&... args) const {
alog<ANDROID_LOG_WARN>(std::forward<Args>(args)...);
}
template <typename... Args>
void aloge(Args&&... args) const {
alog<ANDROID_LOG_ERROR>(std::forward<Args>(args)...);
}
private:
// Suppresses clang-tidy check cppcoreguidelines-pro-bounds-array-to-pointer-decay
template <size_t strlen, typename... Args>
void write(fmt::MemoryWriter* writer, const char (&str)[strlen], Args&&... args) const {
writer->write(static_cast<const char*>(str), std::forward<Args>(args)...);
}
template <int priority, typename... Args>
void alog(Args&&... args) const {
static_assert(std::is_base_of<SafeLog<T>, T>::value, "Can't convert to SafeLog pointer");
fmt::MemoryWriter writer;
write(&writer, std::forward<Args>(args)...);
auto derivedThis = static_cast<const T*>(this);
android_writeLog(priority, derivedThis->getLogTag(), writer.c_str());
}
};
} // namespace gfx
} // namespace android