// 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. #include "contrib/libs/apache/arrow_next/cpp/src/arrow/util/logging.h" #include "contrib/libs/apache/arrow_next/src/arrow/util/config.h" #ifdef ARROW_WITH_BACKTRACE # include #endif #include #include #ifdef ARROW_USE_GLOG # include # include # error #include // Restore our versions of DCHECK and friends, as GLog defines its own # undef DCHECK # undef DCHECK_OK # undef DCHECK_EQ # undef DCHECK_NE # undef DCHECK_LE # undef DCHECK_LT # undef DCHECK_GE # undef DCHECK_GT # define DCHECK ARROW_DCHECK # define DCHECK_OK ARROW_DCHECK_OK # define DCHECK_EQ ARROW_DCHECK_EQ # define DCHECK_NE ARROW_DCHECK_NE # define DCHECK_LE ARROW_DCHECK_LE # define DCHECK_LT ARROW_DCHECK_LT # define DCHECK_GE ARROW_DCHECK_GE # define DCHECK_GT ARROW_DCHECK_GT #endif namespace arrow20 { namespace util { // This code is adapted from // https://github.com/ray-project/ray/blob/master/src/ray/util/logging.cc. // This is the default implementation of arrow log, // which is independent of any libs. class CerrLog { public: explicit CerrLog(ArrowLogLevel severity) : severity_(severity), has_logged_(false) {} virtual ~CerrLog() { if (has_logged_) { std::cerr << std::endl; } if (severity_ == ArrowLogLevel::ARROW_FATAL) { PrintBackTrace(); std::abort(); } } std::ostream& Stream() { has_logged_ = true; return std::cerr; } template CerrLog& operator<<(const T& t) { if (severity_ != ArrowLogLevel::ARROW_DEBUG) { has_logged_ = true; std::cerr << t; } return *this; } protected: const ArrowLogLevel severity_; bool has_logged_; void PrintBackTrace() { #ifdef ARROW_WITH_BACKTRACE void* buffer[255]; const auto calls = backtrace(buffer, static_cast(sizeof(buffer) / sizeof(void*))); backtrace_symbols_fd(buffer, calls, 1); #endif } }; #ifdef ARROW_USE_GLOG typedef google::LogMessage LoggingProvider; #else typedef CerrLog LoggingProvider; #endif ArrowLogLevel ArrowLog::severity_threshold_ = ArrowLogLevel::ARROW_INFO; // Keep the log directory. static std::unique_ptr log_dir_; #ifdef ARROW_USE_GLOG // Glog's severity map. static google::LogSeverity GetMappedSeverity(ArrowLogLevel severity) { switch (severity) { case ArrowLogLevel::ARROW_TRACE: return google::GLOG_INFO; case ArrowLogLevel::ARROW_DEBUG: return google::GLOG_INFO; case ArrowLogLevel::ARROW_INFO: return google::GLOG_INFO; case ArrowLogLevel::ARROW_WARNING: return google::GLOG_WARNING; case ArrowLogLevel::ARROW_ERROR: return google::GLOG_ERROR; case ArrowLogLevel::ARROW_FATAL: return google::GLOG_FATAL; default: ARROW_LOG(FATAL) << "Unsupported logging level: " << static_cast(severity); // This return won't be hit but compiler needs it. return google::GLOG_FATAL; } } #endif void ArrowLog::StartArrowLog(const std::string& app_name, ArrowLogLevel severity_threshold, const std::string& log_dir) { severity_threshold_ = severity_threshold; // In InitGoogleLogging, it simply keeps the pointer. // We need to make sure the app name passed to InitGoogleLogging exist. // We should avoid using static string is a dynamic lib. static std::unique_ptr app_name_; app_name_.reset(new std::string(app_name)); log_dir_.reset(new std::string(log_dir)); #ifdef ARROW_USE_GLOG google::LogSeverity mapped_severity_threshold = GetMappedSeverity(severity_threshold_); google::SetStderrLogging(mapped_severity_threshold); // Enable log file if log_dir is not empty. if (!log_dir.empty()) { auto dir_ends_with_slash = log_dir; if (log_dir[log_dir.length() - 1] != '/') { dir_ends_with_slash += "/"; } auto app_name_without_path = app_name; if (app_name.empty()) { app_name_without_path = "DefaultApp"; } else { // Find the app name without the path. size_t pos = app_name.rfind('/'); if (pos != app_name.npos && pos + 1 < app_name.length()) { app_name_without_path = app_name.substr(pos + 1); } } // If InitGoogleLogging is called but SetLogDestination is not called, // the log will be output to /tmp besides stderr. If log_dir is not // provided, we'd better not call InitGoogleLogging. google::InitGoogleLogging(app_name_->c_str()); google::SetLogFilenameExtension(app_name_without_path.c_str()); for (int i = static_cast(severity_threshold_); i <= static_cast(ArrowLogLevel::ARROW_FATAL); ++i) { google::LogSeverity level = GetMappedSeverity(static_cast(i)); google::SetLogDestination(level, dir_ends_with_slash.c_str()); } } #endif } void ArrowLog::UninstallSignalAction() { #ifdef ARROW_USE_GLOG ARROW_LOG(DEBUG) << "Uninstall signal handlers."; // This signal list comes from glog's signalhandler.cc. // https://github.com/google/glog/blob/master/src/signalhandler.cc#L58-L70 std::vector installed_signals({SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM}); # ifdef WIN32 for (int signal_num : installed_signals) { ARROW_CHECK(signal(signal_num, SIG_DFL) != SIG_ERR); } # else struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; for (int signal_num : installed_signals) { ARROW_CHECK(sigaction(signal_num, &sig_action, NULL) == 0); } # endif #endif } void ArrowLog::ShutDownArrowLog() { #ifdef ARROW_USE_GLOG if (!log_dir_->empty()) { google::ShutdownGoogleLogging(); } #endif } void ArrowLog::InstallFailureSignalHandler() { #ifdef ARROW_USE_GLOG google::InstallFailureSignalHandler(); #endif } bool ArrowLog::IsLevelEnabled(ArrowLogLevel log_level) { return log_level >= severity_threshold_; } ArrowLog::ArrowLog(const char* file_name, int line_number, ArrowLogLevel severity) // glog does not have DEBUG level, we can handle it using is_enabled_. : logging_provider_(nullptr), is_enabled_(severity >= severity_threshold_) { #ifdef ARROW_USE_GLOG if (is_enabled_) { logging_provider_ = new google::LogMessage(file_name, line_number, GetMappedSeverity(severity)); } #else auto logging_provider = new CerrLog(severity); *logging_provider << file_name << ":" << line_number << ": "; logging_provider_ = logging_provider; #endif } std::ostream& ArrowLog::Stream() { auto logging_provider = reinterpret_cast(logging_provider_); #ifdef ARROW_USE_GLOG // Before calling this function, user should check IsEnabled. // When IsEnabled == false, logging_provider_ will be empty. return logging_provider->stream(); #else return logging_provider->Stream(); #endif } bool ArrowLog::IsEnabled() const { return is_enabled_; } ArrowLog::~ArrowLog() { if (logging_provider_ != nullptr) { delete reinterpret_cast(logging_provider_); logging_provider_ = nullptr; } } } // namespace util } // namespace arrow20