// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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 #include #include #include #include #include "arrow/result.h" #include "arrow/status.h" #include "arrow/util/logging.h" #include "arrow/util/macros.h" #include "arrow/util/visibility.h" namespace arrow { namespace util { struct SourceLocation { const char* file = ""; int line = 0; }; struct LogDetails { ArrowLogLevel severity = ArrowLogLevel::ARROW_INFO; std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now(); SourceLocation source_location{}; std::string_view message = ""; }; /// \brief A base interface for custom loggers. /// /// Loggers can be added to the LoggerRegistry for global access or directly provided to /// certain logging utilities. class Logger { public: virtual ~Logger() = default; virtual void Log(const LogDetails& details) = 0; virtual bool Flush(std::chrono::microseconds timeout) { return true; } bool Flush() { return this->Flush(std::chrono::microseconds::max()); } virtual bool is_enabled() const { return true; } virtual ArrowLogLevel severity_threshold() const { return ArrowLogLevel::ARROW_TRACE; } }; /// \brief Creates a simple logger that redirects output to std::cerr ARROW_EXPORT std::shared_ptr MakeOStreamLogger(ArrowLogLevel severity_threshold); /// \brief Creates a simple logger that redirects output to the provided ostream ARROW_EXPORT std::shared_ptr MakeOStreamLogger(ArrowLogLevel severity_threshold, std::ostream& sink); class ARROW_EXPORT LoggerRegistry { public: /// \brief Add a logger to the registry with the associated name /// /// Returns Invalid if a logger with the provided name already exists. Users should call /// `UnregisterLogger` first if they wish to overwrite it. static Status RegisterLogger(std::string_view name, std::shared_ptr logger); /// \brief Remove a logger from the registry static void UnregisterLogger(std::string_view name); /// \brief Return the logger associated with the provided name /// /// If `name` is empty, the default logger is returned. If `name` doesn't match any of /// the registered loggers then a non-null noop logger is returned static std::shared_ptr GetLogger(std::string_view name = ""); /// \brief Return the default logger static std::shared_ptr GetDefaultLogger(); /// \brief Set the default logger static void SetDefaultLogger(std::shared_ptr logger); }; /// \brief Represents a single log record to be emitted by an underlying logger class ARROW_EXPORT LogMessage { public: /// \brief Construct a LogMessage with the provided underlying logger LogMessage(ArrowLogLevel severity, std::shared_ptr logger, SourceLocation source_location = {}); /// \brief Construct a LogMessage with the provided logger name, which will be used to /// find an underlying logger in the registry LogMessage(ArrowLogLevel severity, std::string_view logger_name, SourceLocation source_location = {}); std::ostream& Stream(); // Convenience method - mainly for use in ARROW_LOG_* macros. This prevents unnecessary // argument evaluation when log statements are stripped in certain builds template LogMessage& Append(Args&&... args) { if constexpr (sizeof...(Args) > 0) { if (CheckIsEnabled()) { (Stream() << ... << args); } } return *this; } private: bool CheckIsEnabled(); class Impl; std::shared_ptr impl_; }; } // namespace util } // namespace arrow // For the following macros, log statements with a lower severity than // `ARROW_MINIMUM_LOG_LEVEL` will be stripped from the build #ifndef ARROW_MINIMUM_LOG_LEVEL # define ARROW_MINIMUM_LOG_LEVEL -1000 #endif #define ARROW_LOGGER_INTERNAL(LOGGER, LEVEL) \ (::arrow::util::LogMessage(::arrow::util::ArrowLogLevel::ARROW_##LEVEL, LOGGER, \ ::arrow::util::SourceLocation{__FILE__, __LINE__})) static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_TRACE) == -2); #if ARROW_MINIMUM_LOG_LEVEL <= -2 # define ARROW_LOGGER_TRACE(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, TRACE).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_TRACE(...) ARROW_UNUSED(0) #endif static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_DEBUG) == -1); #if ARROW_MINIMUM_LOG_LEVEL <= -1 # define ARROW_LOGGER_DEBUG(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, DEBUG).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_DEBUG(...) ARROW_UNUSED(0) #endif static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_INFO) == 0); #if ARROW_MINIMUM_LOG_LEVEL <= 0 # define ARROW_LOGGER_INFO(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, INFO).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_INFO(...) ARROW_UNUSED(0) #endif static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_WARNING) == 1); #if ARROW_MINIMUM_LOG_LEVEL <= 1 # define ARROW_LOGGER_WARNING(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, WARNING).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_WARNING(...) ARROW_UNUSED(0) #endif static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_ERROR) == 2); #if ARROW_MINIMUM_LOG_LEVEL <= 2 # define ARROW_LOGGER_ERROR(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, ERROR).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_ERROR(...) ARROW_UNUSED(0) #endif static_assert(static_cast(::arrow::util::ArrowLogLevel::ARROW_FATAL) == 3); #if ARROW_MINIMUM_LOG_LEVEL <= 3 # define ARROW_LOGGER_FATAL(LOGGER, ...) \ (ARROW_LOGGER_INTERNAL(LOGGER, FATAL).Append(__VA_ARGS__)) #else # define ARROW_LOGGER_FATAL(...) ARROW_UNUSED(0) #endif #define ARROW_LOGGER_CALL(LOGGER, LEVEL, ...) ARROW_LOGGER_##LEVEL(LOGGER, __VA_ARGS__)