| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_COMMON_LOG_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_COMMON_LOG_H_ |
| |
| #include <cstddef> |
| |
| #include <ddk/driver.h> |
| |
| #include "src/lib/fxl/compiler_specific.h" |
| |
| // Logging utilities for the host library. This provides a common abstraction |
| // over Zircon DDK debug utilities (used when the host stack code runs in a |
| // driver) and printf (when it's used in unit tests and command-line tools). |
| // |
| // USAGE: |
| // |
| // Functions have been provided to check if logging has been enabled at a |
| // certain severity and to log a message using a tag, file name, and line |
| // number: |
| // |
| // if (IsLogLevelEnabled(LogSeverity::TRACE)) { |
| // LogMessage(__FILE__, __LINE__, LogSeverity::TRACE, "bt-host", "oops: %d", foo); |
| // } |
| // |
| // or using the bt_log convenience macro: |
| // |
| // bt_log(TRACE, "bt-host", "oops: %d", foo); |
| // |
| // DRIVER MODE: |
| // |
| // By default, the log messages use <ddk/debug.h> as its backend. In this mode |
| // the ERROR, WARN, INFO, TRACE, and SPEW severity levels directly correspond to |
| // the DDK severity levels. Log levels are supplied to the kernel commandline, |
| // e.g. to disable INFO level and enable TRACE level messages in the bt-host |
| // driver use the following: |
| // |
| // driver.bthost.log=-info,+trace |
| // |
| // In driver mode, the "tag" argument to bt_log is informational and gets |
| // included in the log message. |
| // |
| // (refer to https://fuchsia.dev/fuchsia-src/reference/kernel/kernel_cmdline#drivernamelogflags |
| // for all supported DDK debug log flags). |
| // |
| // PRINTF MODE: |
| // |
| // When the host stack code is run outside a driver (e.g. bt-host-unittests) log |
| // messages can be routed to stdout via printf instead of driver_logf. To enable |
| // this mode, call the UsePrintf() function at process start-up: |
| // |
| // int main() { |
| // bt::UsePrintf(bt::LogSeverity::ERROR); |
| // |
| // ...do stuff... |
| // |
| // return 0; |
| // } |
| // |
| // The |min_severity| parameter determines the smallest severity level that will |
| // be allowed. For example, passing LogSeverity::INFO will enable INFO, WARN, |
| // and ERROR severity levels. |
| // |
| // The UsePrintf() function is NOT thread-safe. This should be called EARLY |
| // and ONLY ONCE during initialization. Once the printf mode is enabled it |
| // cannot be toggled back to driver mode. |
| // |
| // CAVEATS: |
| // |
| // Since the logging mode is determined at run-time and not compile-time (due |
| // to build dependency reasons) users of these utilities will need to link a |
| // symbol for |__zircon_driver_rec__|. While this symbol will remain unused in |
| // printf-mode it is needed to pass compilation if the target is not a driver. |
| // Use the BT_DECLARE_FAKE_DRIVER macro for this purpose: |
| // |
| // BT_DECLARE_FAKE_DRIVER(); |
| // |
| // int main() { |
| // bt::UsePrintf(bt::LogSeverity::TRACE); |
| // } |
| |
| namespace bt { |
| |
| // Log severity levels used by the host library, following the convention of |
| // <ddk/debug.h> |
| enum class LogSeverity { |
| // Indicates unexpected failures. |
| ERROR = 0, |
| |
| // Indicates a situation that is not an error but may be indicative of an |
| // impending problem. |
| WARN = 1, |
| |
| // Terse information messages for startup, shutdown, or other infrequent state |
| // changes. |
| INFO = 2, |
| |
| // Verbose messages for transactions and state changes |
| TRACE = 3, |
| |
| // Very verbose messages. |
| SPEW = 4, |
| }; |
| |
| constexpr size_t kNumLogSeverities = 5; |
| |
| bool IsLogLevelEnabled(LogSeverity severity); |
| void LogMessage(const char* file, int line, LogSeverity severity, const char* tag, const char* fmt, |
| ...) FXL_PRINTF_FORMAT(5, 6); |
| |
| void UsePrintf(LogSeverity min_severity); |
| |
| namespace internal { |
| |
| // Returns the part of a path following the final '/', or the whole path if there is no '/'. |
| constexpr const char* BaseName(const char* path) { |
| for (const char* c = path; c && (*c != '\0'); c++) { |
| if (*c == '/') { |
| path = c + 1; |
| } |
| } |
| return path; |
| } |
| |
| } // namespace internal |
| } // namespace bt |
| |
| #define bt_log(flag, tag, fmt...) \ |
| do { \ |
| if (bt::IsLogLevelEnabled(bt::LogSeverity::flag)) { \ |
| bt::LogMessage(bt::internal::BaseName(__FILE__), __LINE__, bt::LogSeverity::flag, tag, fmt); \ |
| } \ |
| } while (0) |
| |
| #define BT_DECLARE_FAKE_DRIVER() zx_driver_rec_t __zircon_driver_rec__ = {}; |
| |
| // Convenience macro for printf-style formatting of an object with a ToString() |
| // method e.g.: |
| // bt_log(INFO, "tag", "foo happened: %s", bt_str(id)); |
| #define bt_str(id) ((id).ToString().c_str()) |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_COMMON_LOG_H_ |