]> git.proxmox.com Git - ceph.git/blob - 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
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
54 namespace arrow {
55 namespace 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.
62 class 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
104 typedef google::LogMessage LoggingProvider;
105 #else
106 typedef CerrLog LoggingProvider;
107 #endif
108
109 ArrowLogLevel ArrowLog::severity_threshold_ = ArrowLogLevel::ARROW_INFO;
110 // Keep the log directory.
111 static std::unique_ptr<std::string> log_dir_;
112
113 #ifdef ARROW_USE_GLOG
114
115 // Glog's severity map.
116 static 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
137 void 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
180 void 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
202 void ArrowLog::ShutDownArrowLog() {
203 #ifdef ARROW_USE_GLOG
204 if (!log_dir_->empty()) {
205 google::ShutdownGoogleLogging();
206 }
207 #endif
208 }
209
210 void ArrowLog::InstallFailureSignalHandler() {
211 #ifdef ARROW_USE_GLOG
212 google::InstallFailureSignalHandler();
213 #endif
214 }
215
216 bool ArrowLog::IsLevelEnabled(ArrowLogLevel log_level) {
217 return log_level >= severity_threshold_;
218 }
219
220 ArrowLog::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
235 std::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
246 bool ArrowLog::IsEnabled() const { return is_enabled_; }
247
248 ArrowLog::~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