// 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 <chrono>
#include <iosfwd>
#include <memory>
#include <string_view>
#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<Logger> MakeOStreamLogger(ArrowLogLevel severity_threshold);
/// \brief Creates a simple logger that redirects output to the provided ostream
ARROW_EXPORT std::shared_ptr<Logger> 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> 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<Logger> GetLogger(std::string_view name = "");
/// \brief Return the default logger
static std::shared_ptr<Logger> GetDefaultLogger();
/// \brief Set the default logger
static void SetDefaultLogger(std::shared_ptr<Logger> 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> 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 <typename... Args>
LogMessage& Append(Args&&... args) {
if constexpr (sizeof...(Args) > 0) {
if (CheckIsEnabled()) {
(Stream() << ... << args);
}
}
return *this;
}
private:
bool CheckIsEnabled();
class Impl;
std::shared_ptr<Impl> 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<int>(::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<int>(::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<int>(::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<int>(::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<int>(::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<int>(::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__)