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 | #include "glog/logging.h" |
28 | #endif |
29 | |
30 | namespace arrow { |
31 | namespace util { |
32 | |
33 | // This code is adapted from |
34 | // https://github.com/ray-project/ray/blob/master/src/ray/util/logging.cc. |
35 | |
36 | // This is the default implementation of arrow log, |
37 | // which is independent of any libs. |
38 | class CerrLog { |
39 | public: |
40 | explicit CerrLog(ArrowLogLevel severity) : severity_(severity), has_logged_(false) {} |
41 | |
42 | virtual ~CerrLog() { |
43 | if (has_logged_) { |
44 | std::cerr << std::endl; |
45 | } |
46 | if (severity_ == ArrowLogLevel::ARROW_FATAL) { |
47 | PrintBackTrace(); |
48 | std::abort(); |
49 | } |
50 | } |
51 | |
52 | std::ostream& Stream() { |
53 | has_logged_ = true; |
54 | return std::cerr; |
55 | } |
56 | |
57 | template <class T> |
58 | CerrLog& operator<<(const T& t) { |
59 | if (severity_ != ArrowLogLevel::ARROW_DEBUG) { |
60 | has_logged_ = true; |
61 | std::cerr << t; |
62 | } |
63 | return *this; |
64 | } |
65 | |
66 | protected: |
67 | const ArrowLogLevel severity_; |
68 | bool has_logged_; |
69 | |
70 | void PrintBackTrace() { |
71 | #ifdef ARROW_WITH_BACKTRACE |
72 | void* buffer[255]; |
73 | const int calls = backtrace(buffer, static_cast<int>(sizeof(buffer) / sizeof(void*))); |
74 | backtrace_symbols_fd(buffer, calls, 1); |
75 | #endif |
76 | } |
77 | }; |
78 | |
79 | #ifdef ARROW_USE_GLOG |
80 | typedef google::LogMessage LoggingProvider; |
81 | #else |
82 | typedef CerrLog LoggingProvider; |
83 | #endif |
84 | |
85 | ArrowLogLevel ArrowLog::severity_threshold_ = ArrowLogLevel::ARROW_INFO; |
86 | std::unique_ptr<std::string> ArrowLog::app_name_; |
87 | |
88 | #ifdef ARROW_USE_GLOG |
89 | |
90 | // Glog's severity map. |
91 | static int GetMappedSeverity(ArrowLogLevel severity) { |
92 | switch (severity) { |
93 | case ArrowLogLevel::ARROW_DEBUG: |
94 | return google::GLOG_INFO; |
95 | case ArrowLogLevel::ARROW_INFO: |
96 | return google::GLOG_INFO; |
97 | case ArrowLogLevel::ARROW_WARNING: |
98 | return google::GLOG_WARNING; |
99 | case ArrowLogLevel::ARROW_ERROR: |
100 | return google::GLOG_ERROR; |
101 | case ArrowLogLevel::ARROW_FATAL: |
102 | return google::GLOG_FATAL; |
103 | default: |
104 | ARROW_LOG(FATAL) << "Unsupported logging level: " << static_cast<int>(severity); |
105 | // This return won't be hit but compiler needs it. |
106 | return google::GLOG_FATAL; |
107 | } |
108 | } |
109 | |
110 | #endif |
111 | |
112 | void ArrowLog::StartArrowLog(const std::string& app_name, |
113 | ArrowLogLevel severity_threshold, |
114 | const std::string& log_dir) { |
115 | severity_threshold_ = severity_threshold; |
116 | app_name_.reset(new std::string(app_name.c_str())); |
117 | #ifdef ARROW_USE_GLOG |
118 | int mapped_severity_threshold = GetMappedSeverity(severity_threshold_); |
119 | google::InitGoogleLogging(app_name_->c_str()); |
120 | google::SetStderrLogging(mapped_severity_threshold); |
121 | // Enble log file if log_dir is not empty. |
122 | if (!log_dir.empty()) { |
123 | auto dir_ends_with_slash = log_dir; |
124 | if (log_dir[log_dir.length() - 1] != '/') { |
125 | dir_ends_with_slash += "/" ; |
126 | } |
127 | auto app_name_without_path = app_name; |
128 | if (app_name.empty()) { |
129 | app_name_without_path = "DefaultApp" ; |
130 | } else { |
131 | // Find the app name without the path. |
132 | size_t pos = app_name.rfind('/'); |
133 | if (pos != app_name.npos && pos + 1 < app_name.length()) { |
134 | app_name_without_path = app_name.substr(pos + 1); |
135 | } |
136 | } |
137 | google::SetLogFilenameExtension(app_name_without_path.c_str()); |
138 | google::SetLogDestination(mapped_severity_threshold, log_dir.c_str()); |
139 | } |
140 | #endif |
141 | } |
142 | |
143 | void ArrowLog::ShutDownArrowLog() { |
144 | #ifdef ARROW_USE_GLOG |
145 | google::ShutdownGoogleLogging(); |
146 | #endif |
147 | } |
148 | |
149 | void ArrowLog::InstallFailureSignalHandler() { |
150 | #ifdef ARROW_USE_GLOG |
151 | google::InstallFailureSignalHandler(); |
152 | #endif |
153 | } |
154 | |
155 | ArrowLog::ArrowLog(const char* file_name, int line_number, ArrowLogLevel severity) |
156 | // glog does not have DEBUG level, we can handle it using is_enabled_. |
157 | : logging_provider_(nullptr), is_enabled_(severity >= severity_threshold_) { |
158 | #ifdef ARROW_USE_GLOG |
159 | if (is_enabled_) { |
160 | logging_provider_ = |
161 | new google::LogMessage(file_name, line_number, GetMappedSeverity(severity)); |
162 | } |
163 | #else |
164 | auto logging_provider = new CerrLog(severity); |
165 | *logging_provider << file_name << ":" << line_number << ": " ; |
166 | logging_provider_ = logging_provider; |
167 | #endif |
168 | } |
169 | |
170 | std::ostream& ArrowLog::Stream() { |
171 | auto logging_provider = reinterpret_cast<LoggingProvider*>(logging_provider_); |
172 | #ifdef ARROW_USE_GLOG |
173 | // Before calling this function, user should check IsEnabled. |
174 | // When IsEnabled == false, logging_provider_ will be empty. |
175 | return logging_provider->stream(); |
176 | #else |
177 | return logging_provider->Stream(); |
178 | #endif |
179 | } |
180 | |
181 | bool ArrowLog::IsEnabled() const { return is_enabled_; } |
182 | |
183 | ArrowLog::~ArrowLog() { |
184 | if (logging_provider_ != nullptr) { |
185 | delete reinterpret_cast<LoggingProvider*>(logging_provider_); |
186 | logging_provider_ = nullptr; |
187 | } |
188 | } |
189 | |
190 | } // namespace util |
191 | } // namespace arrow |
192 | |