/* * Copyright (C) 2017 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. */ #ifndef INCLUDE_PERFETTO_BASE_LOGGING_H_ #define INCLUDE_PERFETTO_BASE_LOGGING_H_ #include #include // For strerror. #include "perfetto/base/build_config.h" #include "perfetto/base/compiler.h" #include "perfetto/base/export.h" #if defined(__GNUC__) || defined(__clang__) // Ignore GCC warning about a missing argument for a variadic macro parameter. #pragma GCC system_header #endif // TODO(primiano): move this to base/build_config.h, turn into // PERFETTO_BUILDFLAG(DCHECK_IS_ON) and update call sites to use that instead. #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) #define PERFETTO_DCHECK_IS_ON() 0 #else #define PERFETTO_DCHECK_IS_ON() 1 #endif #if PERFETTO_BUILDFLAG(PERFETTO_FORCE_DLOG_ON) #define PERFETTO_DLOG_IS_ON() 1 #elif PERFETTO_BUILDFLAG(PERFETTO_FORCE_DLOG_OFF) #define PERFETTO_DLOG_IS_ON() 0 #else #define PERFETTO_DLOG_IS_ON() PERFETTO_DCHECK_IS_ON() #endif #if defined(PERFETTO_ANDROID_ASYNC_SAFE_LOG) #if !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) #error "Async-safe logging is limited to Android tree builds" #endif // For binaries which need a very lightweight logging implementation. // Note that this header is incompatible with android/log.h. #include #elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) // Normal android logging. #include #endif namespace perfetto { namespace base { // Constexpr functions to extract basename(__FILE__), e.g.: ../foo/f.c -> f.c . constexpr const char* StrEnd(const char* s) { return *s ? StrEnd(s + 1) : s; } constexpr const char* BasenameRecursive(const char* s, const char* begin, const char* end) { return (*s == '/' && s < end) ? (s + 1) : ((s > begin) ? BasenameRecursive(s - 1, begin, end) : s); } constexpr const char* Basename(const char* str) { return BasenameRecursive(StrEnd(str), str, StrEnd(str)); } enum LogLev { kLogDebug = 0, kLogInfo, kLogImportant, kLogError }; struct LogMessageCallbackArgs { LogLev level; int line; const char* filename; const char* message; }; using LogMessageCallback = void (*)(LogMessageCallbackArgs); // This is not thread safe and must be called before using tracing from other // threads. PERFETTO_EXPORT void SetLogMessageCallback(LogMessageCallback callback); PERFETTO_EXPORT void LogMessage(LogLev, const char* fname, int line, const char* fmt, ...) PERFETTO_PRINTF_FORMAT(4, 5); #if defined(PERFETTO_ANDROID_ASYNC_SAFE_LOG) #define PERFETTO_XLOG(level, fmt, ...) \ do { \ async_safe_format_log((ANDROID_LOG_DEBUG + level), "perfetto", \ "%s:%d " fmt, ::perfetto::base::Basename(__FILE__), \ __LINE__, ##__VA_ARGS__); \ } while (0) #elif defined(PERFETTO_DISABLE_LOG) #define PERFETTO_XLOG(...) ::perfetto::base::ignore_result(__VA_ARGS__) #else #define PERFETTO_XLOG(level, fmt, ...) \ ::perfetto::base::LogMessage(level, ::perfetto::base::Basename(__FILE__), \ __LINE__, fmt, ##__VA_ARGS__) #endif #if defined(_MSC_VER) #define PERFETTO_IMMEDIATE_CRASH() \ do { \ __debugbreak(); \ __assume(0); \ } while (0) #else #define PERFETTO_IMMEDIATE_CRASH() \ do { \ __builtin_trap(); \ __builtin_unreachable(); \ } while (0) #endif #if PERFETTO_BUILDFLAG(PERFETTO_VERBOSE_LOGS) #define PERFETTO_LOG(fmt, ...) \ PERFETTO_XLOG(::perfetto::base::kLogInfo, fmt, ##__VA_ARGS__) #else // PERFETTO_BUILDFLAG(PERFETTO_VERBOSE_LOGS) #define PERFETTO_LOG(...) ::perfetto::base::ignore_result(__VA_ARGS__) #endif // PERFETTO_BUILDFLAG(PERFETTO_VERBOSE_LOGS) #define PERFETTO_ILOG(fmt, ...) \ PERFETTO_XLOG(::perfetto::base::kLogImportant, fmt, ##__VA_ARGS__) #define PERFETTO_ELOG(fmt, ...) \ PERFETTO_XLOG(::perfetto::base::kLogError, fmt, ##__VA_ARGS__) #define PERFETTO_FATAL(fmt, ...) \ do { \ PERFETTO_PLOG(fmt, ##__VA_ARGS__); \ PERFETTO_IMMEDIATE_CRASH(); \ } while (0) #if defined(__GNUC__) || defined(__clang__) #define PERFETTO_PLOG(x, ...) \ PERFETTO_ELOG(x " (errno: %d, %s)", ##__VA_ARGS__, errno, strerror(errno)) #else // MSVC expands __VA_ARGS__ in a different order. Give up, not worth it. #define PERFETTO_PLOG PERFETTO_ELOG #endif #define PERFETTO_CHECK(x) \ do { \ if (PERFETTO_UNLIKELY(!(x))) { \ PERFETTO_PLOG("%s", "PERFETTO_CHECK(" #x ")"); \ PERFETTO_IMMEDIATE_CRASH(); \ } \ } while (0) #if PERFETTO_DLOG_IS_ON() #define PERFETTO_DLOG(fmt, ...) \ PERFETTO_XLOG(::perfetto::base::kLogDebug, fmt, ##__VA_ARGS__) #if defined(__GNUC__) || defined(__clang__) #define PERFETTO_DPLOG(x, ...) \ PERFETTO_DLOG(x " (errno: %d, %s)", ##__VA_ARGS__, errno, strerror(errno)) #else // MSVC expands __VA_ARGS__ in a different order. Give up, not worth it. #define PERFETTO_DPLOG PERFETTO_DLOG #endif #else // PERFETTO_DLOG_IS_ON() #define PERFETTO_DLOG(...) ::perfetto::base::ignore_result(__VA_ARGS__) #define PERFETTO_DPLOG(...) ::perfetto::base::ignore_result(__VA_ARGS__) #endif // PERFETTO_DLOG_IS_ON() #if PERFETTO_DCHECK_IS_ON() #define PERFETTO_DCHECK(x) PERFETTO_CHECK(x) #define PERFETTO_DFATAL(...) PERFETTO_FATAL(__VA_ARGS__) #define PERFETTO_DFATAL_OR_ELOG(...) PERFETTO_DFATAL(__VA_ARGS__) #else // PERFETTO_DCHECK_IS_ON() #define PERFETTO_DCHECK(x) \ do { \ } while (false && (x)) #define PERFETTO_DFATAL(...) ::perfetto::base::ignore_result(__VA_ARGS__) #define PERFETTO_DFATAL_OR_ELOG(...) PERFETTO_ELOG(__VA_ARGS__) #endif // PERFETTO_DCHECK_IS_ON() } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_BASE_LOGGING_H_