text: /*
   * 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 <errno.h>
  #include <string.h>  // 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
  
  #if PERFETTO_BUILDFLAG(PERFETTO_FORCE_DCHECK_ON)
  #define PERFETTO_DCHECK_IS_ON() 1
  #elif PERFETTO_BUILDFLAG(PERFETTO_FORCE_DCHECK_OFF)
  #define PERFETTO_DCHECK_IS_ON() 0
  #elif defined(DCHECK_ALWAYS_ON) ||                                         \
      (!defined(NDEBUG) && (PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) || \
                            PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) ||   \
                            PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)))
  #define PERFETTO_DCHECK_IS_ON() 1
  #else
  #define PERFETTO_DCHECK_IS_ON() 0
  #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 <async_safe/log.h>
  #elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  // Normal android logging.
  #include <android/log.h>
  #endif
  
  // Enable the "Print the most recent PERFETTO_LOG(s) before crashing" feature
  // on Android in-tree builds and on standalone builds (mainly for testing).
  // This is deliberately no PERFETTO_OS_ANDROID because we don't want this
  // feature when perfetto is embedded in other Android projects (e.g. SDK).
  // TODO(b/203795298): TFLite is using the client library in blaze builds and is
  // targeting API 19. For now disable the feature based on API level.
  #if defined(PERFETTO_ANDROID_ASYNC_SAFE_LOG)
  #define PERFETTO_ENABLE_LOG_RING_BUFFER() 0
  #elif PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  #define PERFETTO_ENABLE_LOG_RING_BUFFER() 1
  #elif PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) && \
      (!PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) ||       \
       (defined(__ANDROID_API__) && __ANDROID_API__ >= 21))
  #define PERFETTO_ENABLE_LOG_RING_BUFFER() 1
  #else
  #define PERFETTO_ENABLE_LOG_RING_BUFFER() 0
  #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);
  
  // This is defined in debug_crash_stack_trace.cc, but that is only linked in
  // standalone && debug builds, see enable_perfetto_stderr_crash_dump in
  // perfetto.gni.
  PERFETTO_EXPORT void EnableStacktraceOnCrashForDebug();
  
  #if PERFETTO_ENABLE_LOG_RING_BUFFER()
  // Gets a snapshot of the logs from the internal log ring buffer and:
  // - On Android in-tree builds: Passes that to android_set_abort_message().
  //   That will attach the logs to the crash report.
  // - On standalone builds (all otther OSes) prints that on stderr.
  // This function must called only once, right before inducing a crash (This is
  // because android_set_abort_message() can only be called once).
  PERFETTO_EXPORT void MaybeSerializeLastLogsForCrashReporting();
  #else
  inline void MaybeSerializeLastLogsForCrashReporting() {}
  #endif
  
  #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(level, fmt, ...) ::perfetto::base::ignore_result(level, \
                                  fmt, ##__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 {                                                           \
      ::perfetto::base::MaybeSerializeLastLogsForCrashReporting(); \
      __debugbreak();                                              \
      __assume(0);                                                 \
    } while (0)
  #else
  #define PERFETTO_IMMEDIATE_CRASH()                               \
    do {                                                           \
      ::perfetto::base::MaybeSerializeLastLogsForCrashReporting(); \
      __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_
  