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#ifndef ARROW_UTIL_LOGGING_H
19#define ARROW_UTIL_LOGGING_H
20
21#ifdef GANDIVA_IR
22
23// The LLVM IR code doesn't have an NDEBUG mode. And, it shouldn't include references to
24// streams or stdc++. So, making the DCHECK calls void in that case.
25
26#define ARROW_IGNORE_EXPR(expr) ((void)(expr))
27
28#define DCHECK(condition) ARROW_IGNORE_EXPR(condition)
29#define DCHECK_OK(status) ARROW_IGNORE_EXPR(status)
30#define DCHECK_EQ(val1, val2) ARROW_IGNORE_EXPR(val1)
31#define DCHECK_NE(val1, val2) ARROW_IGNORE_EXPR(val1)
32#define DCHECK_LE(val1, val2) ARROW_IGNORE_EXPR(val1)
33#define DCHECK_LT(val1, val2) ARROW_IGNORE_EXPR(val1)
34#define DCHECK_GE(val1, val2) ARROW_IGNORE_EXPR(val1)
35#define DCHECK_GT(val1, val2) ARROW_IGNORE_EXPR(val1)
36
37#else // !GANDIVA_IR
38
39#include <iostream>
40#include <memory>
41#include <string>
42
43#include "arrow/util/macros.h"
44#include "arrow/util/visibility.h"
45
46namespace arrow {
47namespace util {
48
49enum class ArrowLogLevel : int {
50 ARROW_DEBUG = -1,
51 ARROW_INFO = 0,
52 ARROW_WARNING = 1,
53 ARROW_ERROR = 2,
54 ARROW_FATAL = 3
55};
56
57#define ARROW_LOG_INTERNAL(level) ::arrow::util::ArrowLog(__FILE__, __LINE__, level)
58#define ARROW_LOG(level) ARROW_LOG_INTERNAL(::arrow::util::ArrowLogLevel::ARROW_##level)
59#define ARROW_IGNORE_EXPR(expr) ((void)(expr))
60
61#define ARROW_CHECK(condition) \
62 (condition) ? ARROW_IGNORE_EXPR(0) \
63 : ::arrow::util::Voidify() & \
64 ::arrow::util::ArrowLog(__FILE__, __LINE__, \
65 ::arrow::util::ArrowLogLevel::ARROW_FATAL) \
66 << " Check failed: " #condition " "
67
68// If 'to_call' returns a bad status, CHECK immediately with a logged message
69// of 'msg' followed by the status.
70#define ARROW_CHECK_OK_PREPEND(to_call, msg) \
71 do { \
72 ::arrow::Status _s = (to_call); \
73 ARROW_CHECK(_s.ok()) << (msg) << ": " << _s.ToString(); \
74 } while (false)
75
76// If the status is bad, CHECK immediately, appending the status to the
77// logged message.
78#define ARROW_CHECK_OK(s) ARROW_CHECK_OK_PREPEND(s, "Bad status")
79
80#ifdef NDEBUG
81#define ARROW_DFATAL ::arrow::util::ArrowLogLevel::ARROW_WARNING
82
83#define DCHECK(condition) \
84 ARROW_IGNORE_EXPR(condition); \
85 while (false) ::arrow::util::ArrowLogBase()
86#define DCHECK_OK(status) \
87 ARROW_IGNORE_EXPR(status); \
88 while (false) ::arrow::util::ArrowLogBase()
89#define DCHECK_EQ(val1, val2) \
90 ARROW_IGNORE_EXPR(val1); \
91 while (false) ::arrow::util::ArrowLogBase()
92#define DCHECK_NE(val1, val2) \
93 ARROW_IGNORE_EXPR(val1); \
94 while (false) ::arrow::util::ArrowLogBase()
95#define DCHECK_LE(val1, val2) \
96 ARROW_IGNORE_EXPR(val1); \
97 while (false) ::arrow::util::ArrowLogBase()
98#define DCHECK_LT(val1, val2) \
99 ARROW_IGNORE_EXPR(val1); \
100 while (false) ::arrow::util::ArrowLogBase()
101#define DCHECK_GE(val1, val2) \
102 ARROW_IGNORE_EXPR(val1); \
103 while (false) ::arrow::util::ArrowLogBase()
104#define DCHECK_GT(val1, val2) \
105 ARROW_IGNORE_EXPR(val1); \
106 while (false) ::arrow::util::ArrowLogBase()
107
108#else
109#define ARROW_DFATAL ::arrow::util::ArrowLogLevel::ARROW_FATAL
110
111#define DCHECK(condition) ARROW_CHECK(condition)
112#define DCHECK_OK(status) (ARROW_CHECK((status).ok()) << (status).message())
113#define DCHECK_EQ(val1, val2) ARROW_CHECK((val1) == (val2))
114#define DCHECK_NE(val1, val2) ARROW_CHECK((val1) != (val2))
115#define DCHECK_LE(val1, val2) ARROW_CHECK((val1) <= (val2))
116#define DCHECK_LT(val1, val2) ARROW_CHECK((val1) < (val2))
117#define DCHECK_GE(val1, val2) ARROW_CHECK((val1) >= (val2))
118#define DCHECK_GT(val1, val2) ARROW_CHECK((val1) > (val2))
119
120#endif // NDEBUG
121
122// This code is adapted from
123// https://github.com/ray-project/ray/blob/master/src/ray/util/logging.h.
124
125// To make the logging lib plugable with other logging libs and make
126// the implementation unawared by the user, ArrowLog is only a declaration
127// which hide the implementation into logging.cc file.
128// In logging.cc, we can choose different log libs using different macros.
129
130// This is also a null log which does not output anything.
131class ARROW_EXPORT ArrowLogBase {
132 public:
133 virtual ~ArrowLogBase() {}
134
135 virtual bool IsEnabled() const { return false; }
136
137 template <typename T>
138 ArrowLogBase& operator<<(const T& t) {
139 if (IsEnabled()) {
140 Stream() << t;
141 }
142 return *this;
143 }
144
145 protected:
146 virtual std::ostream& Stream() { return std::cerr; }
147};
148
149class ARROW_EXPORT ArrowLog : public ArrowLogBase {
150 public:
151 ArrowLog(const char* file_name, int line_number, ArrowLogLevel severity);
152
153 virtual ~ArrowLog();
154
155 /// Return whether or not current logging instance is enabled.
156 ///
157 /// \return True if logging is enabled and false otherwise.
158 virtual bool IsEnabled() const;
159
160 /// The init function of arrow log for a program which should be called only once.
161 ///
162 /// \param appName The app name which starts the log.
163 /// \param severity_threshold Logging threshold for the program.
164 /// \param logDir Logging output file name. If empty, the log won't output to file.
165 static void StartArrowLog(const std::string& appName,
166 ArrowLogLevel severity_threshold = ArrowLogLevel::ARROW_INFO,
167 const std::string& logDir = "");
168
169 /// The shutdown function of arrow log, it should be used with StartArrowLog as a pair.
170 static void ShutDownArrowLog();
171
172 /// Install the failure signal handler to output call stack when crash.
173 /// If glog is not installed, this function won't do anything.
174 static void InstallFailureSignalHandler();
175
176 private:
177 ARROW_DISALLOW_COPY_AND_ASSIGN(ArrowLog);
178
179 // Hide the implementation of log provider by void *.
180 // Otherwise, lib user may define the same macro to use the correct header file.
181 void* logging_provider_;
182 /// True if log messages should be logged and false if they should be ignored.
183 bool is_enabled_;
184
185 static ArrowLogLevel severity_threshold_;
186 // In InitGoogleLogging, it simply keeps the pointer.
187 // We need to make sure the app name passed to InitGoogleLogging exist.
188 static std::unique_ptr<std::string> app_name_;
189
190 protected:
191 virtual std::ostream& Stream();
192};
193
194// This class make ARROW_CHECK compilation pass to change the << operator to void.
195// This class is copied from glog.
196class ARROW_EXPORT Voidify {
197 public:
198 Voidify() {}
199 // This has to be an operator with a precedence lower than << but
200 // higher than ?:
201 void operator&(ArrowLogBase&) {}
202};
203
204} // namespace util
205} // namespace arrow
206#endif // GANDIVA_IR
207
208#endif // ARROW_UTIL_LOGGING_H
209