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
9 // http://www.apache.org/licenses/LICENSE-2.0
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
18 #include "arrow/util/logging.h"
20 #ifdef ARROW_WITH_BACKTRACE
31 #include "glog/logging.h"
33 // Restore our versions of DCHECK and friends, as GLog defines its own
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
57 // This code is adapted from
58 // https://github.com/ray-project/ray/blob/master/src/ray/util/logging.cc.
60 // This is the default implementation of arrow log,
61 // which is independent of any libs.
64 explicit CerrLog(ArrowLogLevel severity
) : severity_(severity
), has_logged_(false) {}
68 std::cerr
<< std::endl
;
70 if (severity_
== ArrowLogLevel::ARROW_FATAL
) {
76 std::ostream
& Stream() {
82 CerrLog
& operator<<(const T
& t
) {
83 if (severity_
!= ArrowLogLevel::ARROW_DEBUG
) {
91 const ArrowLogLevel severity_
;
94 void PrintBackTrace() {
95 #ifdef ARROW_WITH_BACKTRACE
97 const int calls
= backtrace(buffer
, static_cast<int>(sizeof(buffer
) / sizeof(void*)));
98 backtrace_symbols_fd(buffer
, calls
, 1);
103 #ifdef ARROW_USE_GLOG
104 typedef google::LogMessage LoggingProvider
;
106 typedef CerrLog LoggingProvider
;
109 ArrowLogLevel
ArrowLog::severity_threshold_
= ArrowLogLevel::ARROW_INFO
;
110 // Keep the log directory.
111 static std::unique_ptr
<std::string
> log_dir_
;
113 #ifdef ARROW_USE_GLOG
115 // Glog's severity map.
116 static int GetMappedSeverity(ArrowLogLevel 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
;
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
;
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
+= "/";
156 auto app_name_without_path
= app_name
;
157 if (app_name
.empty()) {
158 app_name_without_path
= "DefaultApp";
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);
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());
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
});
187 for (int signal_num
: installed_signals
) {
188 ARROW_CHECK(signal(signal_num
, SIG_DFL
) != SIG_ERR
);
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);
202 void ArrowLog::ShutDownArrowLog() {
203 #ifdef ARROW_USE_GLOG
204 if (!log_dir_
->empty()) {
205 google::ShutdownGoogleLogging();
210 void ArrowLog::InstallFailureSignalHandler() {
211 #ifdef ARROW_USE_GLOG
212 google::InstallFailureSignalHandler();
216 bool ArrowLog::IsLevelEnabled(ArrowLogLevel log_level
) {
217 return log_level
>= severity_threshold_
;
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
226 new google::LogMessage(file_name
, line_number
, GetMappedSeverity(severity
));
229 auto logging_provider
= new CerrLog(severity
);
230 *logging_provider
<< file_name
<< ":" << line_number
<< ": ";
231 logging_provider_
= logging_provider
;
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();
242 return logging_provider
->Stream();
246 bool ArrowLog::IsEnabled() const { return is_enabled_
; }
248 ArrowLog::~ArrowLog() {
249 if (logging_provider_
!= nullptr) {
250 delete reinterpret_cast<LoggingProvider
*>(logging_provider_
);
251 logging_provider_
= nullptr;