]> git.proxmox.com Git - ceph.git/blame - ceph/src/arrow/cpp/src/arrow/util/logging.cc
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / cpp / src / arrow / util / logging.cc
CommitLineData
1d09f67e
TL
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#include "arrow/util/logging.h"
19
20#ifdef ARROW_WITH_BACKTRACE
21#include <execinfo.h>
22#endif
23#include <cstdlib>
24#include <iostream>
25
26#ifdef ARROW_USE_GLOG
27
28#include <signal.h>
29#include <vector>
30
31#include "glog/logging.h"
32
33// Restore our versions of DCHECK and friends, as GLog defines its own
34#undef DCHECK
35#undef DCHECK_OK
36#undef DCHECK_EQ
37#undef DCHECK_NE
38#undef DCHECK_LE
39#undef DCHECK_LT
40#undef DCHECK_GE
41#undef DCHECK_GT
42
43#define DCHECK ARROW_DCHECK
44#define DCHECK_OK ARROW_DCHECK_OK
45#define DCHECK_EQ ARROW_DCHECK_EQ
46#define DCHECK_NE ARROW_DCHECK_NE
47#define DCHECK_LE ARROW_DCHECK_LE
48#define DCHECK_LT ARROW_DCHECK_LT
49#define DCHECK_GE ARROW_DCHECK_GE
50#define DCHECK_GT ARROW_DCHECK_GT
51
52#endif
53
54namespace arrow {
55namespace util {
56
57// This code is adapted from
58// https://github.com/ray-project/ray/blob/master/src/ray/util/logging.cc.
59
60// This is the default implementation of arrow log,
61// which is independent of any libs.
62class CerrLog {
63 public:
64 explicit CerrLog(ArrowLogLevel severity) : severity_(severity), has_logged_(false) {}
65
66 virtual ~CerrLog() {
67 if (has_logged_) {
68 std::cerr << std::endl;
69 }
70 if (severity_ == ArrowLogLevel::ARROW_FATAL) {
71 PrintBackTrace();
72 std::abort();
73 }
74 }
75
76 std::ostream& Stream() {
77 has_logged_ = true;
78 return std::cerr;
79 }
80
81 template <class T>
82 CerrLog& operator<<(const T& t) {
83 if (severity_ != ArrowLogLevel::ARROW_DEBUG) {
84 has_logged_ = true;
85 std::cerr << t;
86 }
87 return *this;
88 }
89
90 protected:
91 const ArrowLogLevel severity_;
92 bool has_logged_;
93
94 void PrintBackTrace() {
95#ifdef ARROW_WITH_BACKTRACE
96 void* buffer[255];
97 const int calls = backtrace(buffer, static_cast<int>(sizeof(buffer) / sizeof(void*)));
98 backtrace_symbols_fd(buffer, calls, 1);
99#endif
100 }
101};
102
103#ifdef ARROW_USE_GLOG
104typedef google::LogMessage LoggingProvider;
105#else
106typedef CerrLog LoggingProvider;
107#endif
108
109ArrowLogLevel ArrowLog::severity_threshold_ = ArrowLogLevel::ARROW_INFO;
110// Keep the log directory.
111static std::unique_ptr<std::string> log_dir_;
112
113#ifdef ARROW_USE_GLOG
114
115// Glog's severity map.
116static int GetMappedSeverity(ArrowLogLevel severity) {
117 switch (severity) {
118 case ArrowLogLevel::ARROW_DEBUG:
119 return google::GLOG_INFO;
120 case ArrowLogLevel::ARROW_INFO:
121 return google::GLOG_INFO;
122 case ArrowLogLevel::ARROW_WARNING:
123 return google::GLOG_WARNING;
124 case ArrowLogLevel::ARROW_ERROR:
125 return google::GLOG_ERROR;
126 case ArrowLogLevel::ARROW_FATAL:
127 return google::GLOG_FATAL;
128 default:
129 ARROW_LOG(FATAL) << "Unsupported logging level: " << static_cast<int>(severity);
130 // This return won't be hit but compiler needs it.
131 return google::GLOG_FATAL;
132 }
133}
134
135#endif
136
137void ArrowLog::StartArrowLog(const std::string& app_name,
138 ArrowLogLevel severity_threshold,
139 const std::string& log_dir) {
140 severity_threshold_ = severity_threshold;
141 // In InitGoogleLogging, it simply keeps the pointer.
142 // We need to make sure the app name passed to InitGoogleLogging exist.
143 // We should avoid using static string is a dynamic lib.
144 static std::unique_ptr<std::string> app_name_;
145 app_name_.reset(new std::string(app_name));
146 log_dir_.reset(new std::string(log_dir));
147#ifdef ARROW_USE_GLOG
148 int mapped_severity_threshold = GetMappedSeverity(severity_threshold_);
149 google::SetStderrLogging(mapped_severity_threshold);
150 // Enble log file if log_dir is not empty.
151 if (!log_dir.empty()) {
152 auto dir_ends_with_slash = log_dir;
153 if (log_dir[log_dir.length() - 1] != '/') {
154 dir_ends_with_slash += "/";
155 }
156 auto app_name_without_path = app_name;
157 if (app_name.empty()) {
158 app_name_without_path = "DefaultApp";
159 } else {
160 // Find the app name without the path.
161 size_t pos = app_name.rfind('/');
162 if (pos != app_name.npos && pos + 1 < app_name.length()) {
163 app_name_without_path = app_name.substr(pos + 1);
164 }
165 }
166 // If InitGoogleLogging is called but SetLogDestination is not called,
167 // the log will be output to /tmp besides stderr. If log_dir is not
168 // provided, we'd better not call InitGoogleLogging.
169 google::InitGoogleLogging(app_name_->c_str());
170 google::SetLogFilenameExtension(app_name_without_path.c_str());
171 for (int i = static_cast<int>(severity_threshold_);
172 i <= static_cast<int>(ArrowLogLevel::ARROW_FATAL); ++i) {
173 int level = GetMappedSeverity(static_cast<ArrowLogLevel>(i));
174 google::SetLogDestination(level, dir_ends_with_slash.c_str());
175 }
176 }
177#endif
178}
179
180void ArrowLog::UninstallSignalAction() {
181#ifdef ARROW_USE_GLOG
182 ARROW_LOG(DEBUG) << "Uninstall signal handlers.";
183 // This signal list comes from glog's signalhandler.cc.
184 // https://github.com/google/glog/blob/master/src/signalhandler.cc#L58-L70
185 std::vector<int> installed_signals({SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM});
186#ifdef WIN32
187 for (int signal_num : installed_signals) {
188 ARROW_CHECK(signal(signal_num, SIG_DFL) != SIG_ERR);
189 }
190#else
191 struct sigaction sig_action;
192 memset(&sig_action, 0, sizeof(sig_action));
193 sigemptyset(&sig_action.sa_mask);
194 sig_action.sa_handler = SIG_DFL;
195 for (int signal_num : installed_signals) {
196 ARROW_CHECK(sigaction(signal_num, &sig_action, NULL) == 0);
197 }
198#endif
199#endif
200}
201
202void ArrowLog::ShutDownArrowLog() {
203#ifdef ARROW_USE_GLOG
204 if (!log_dir_->empty()) {
205 google::ShutdownGoogleLogging();
206 }
207#endif
208}
209
210void ArrowLog::InstallFailureSignalHandler() {
211#ifdef ARROW_USE_GLOG
212 google::InstallFailureSignalHandler();
213#endif
214}
215
216bool ArrowLog::IsLevelEnabled(ArrowLogLevel log_level) {
217 return log_level >= severity_threshold_;
218}
219
220ArrowLog::ArrowLog(const char* file_name, int line_number, ArrowLogLevel severity)
221 // glog does not have DEBUG level, we can handle it using is_enabled_.
222 : logging_provider_(nullptr), is_enabled_(severity >= severity_threshold_) {
223#ifdef ARROW_USE_GLOG
224 if (is_enabled_) {
225 logging_provider_ =
226 new google::LogMessage(file_name, line_number, GetMappedSeverity(severity));
227 }
228#else
229 auto logging_provider = new CerrLog(severity);
230 *logging_provider << file_name << ":" << line_number << ": ";
231 logging_provider_ = logging_provider;
232#endif
233}
234
235std::ostream& ArrowLog::Stream() {
236 auto logging_provider = reinterpret_cast<LoggingProvider*>(logging_provider_);
237#ifdef ARROW_USE_GLOG
238 // Before calling this function, user should check IsEnabled.
239 // When IsEnabled == false, logging_provider_ will be empty.
240 return logging_provider->stream();
241#else
242 return logging_provider->Stream();
243#endif
244}
245
246bool ArrowLog::IsEnabled() const { return is_enabled_; }
247
248ArrowLog::~ArrowLog() {
249 if (logging_provider_ != nullptr) {
250 delete reinterpret_cast<LoggingProvider*>(logging_provider_);
251 logging_provider_ = nullptr;
252 }
253}
254
255} // namespace util
256} // namespace arrow