1#pragma once
2
3#include <functional>
4#include <cstring>
5
6// This is necessary for TI_UNREACHABLE
7#include "taichi/common/platform_macros.h"
8
9// Must include "spdlog/common.h" to define SPDLOG_HEADER_ONLY
10// before including "spdlog/fmt/fmt.h"
11#include "spdlog/common.h"
12#include "spdlog/fmt/fmt.h"
13namespace spdlog {
14class logger;
15}
16
17#ifdef _WIN64
18#define __FILENAME__ \
19 (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
20#else
21#define __FILENAME__ \
22 (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
23#endif
24
25#define SPD_AUGMENTED_LOG(X, ...) \
26 taichi::Logger::get_instance().X( \
27 fmt::format("[{}:{}@{}] ", __FILENAME__, __FUNCTION__, __LINE__) + \
28 fmt::format(__VA_ARGS__))
29
30#if defined(TI_PLATFORM_WINDOWS)
31#define TI_UNREACHABLE __assume(0);
32#else
33#define TI_UNREACHABLE __builtin_unreachable();
34#endif
35
36#define TI_TRACE(...) SPD_AUGMENTED_LOG(trace, __VA_ARGS__)
37#define TI_DEBUG(...) SPD_AUGMENTED_LOG(debug, __VA_ARGS__)
38#define TI_INFO(...) SPD_AUGMENTED_LOG(info, __VA_ARGS__)
39#define TI_WARN(...) SPD_AUGMENTED_LOG(warn, __VA_ARGS__)
40#define TI_ERROR(...) \
41 { \
42 SPD_AUGMENTED_LOG(error, __VA_ARGS__); \
43 TI_UNREACHABLE; \
44 }
45#define TI_CRITICAL(...) \
46 { \
47 SPD_AUGMENTED_LOG(critical, __VA_ARGS__); \
48 TI_UNREACHABLE; \
49 }
50
51#define TI_TRACE_IF(condition, ...) \
52 if (condition) { \
53 TI_TRACE(__VA_ARGS__); \
54 }
55#define TI_TRACE_UNLESS(condition, ...) \
56 if (!(condition)) { \
57 TI_TRACE(__VA_ARGS__); \
58 }
59#define TI_DEBUG_IF(condition, ...) \
60 if (condition) { \
61 TI_DEBUG(__VA_ARGS__); \
62 }
63#define TI_DEBUG_UNLESS(condition, ...) \
64 if (!(condition)) { \
65 TI_DEBUG(__VA_ARGS__); \
66 }
67#define TI_INFO_IF(condition, ...) \
68 if (condition) { \
69 TI_INFO(__VA_ARGS__); \
70 }
71#define TI_INFO_UNLESS(condition, ...) \
72 if (!(condition)) { \
73 TI_INFO(__VA_ARGS__); \
74 }
75#define TI_WARN_IF(condition, ...) \
76 if (condition) { \
77 TI_WARN(__VA_ARGS__); \
78 }
79#define TI_WARN_UNLESS(condition, ...) \
80 if (!(condition)) { \
81 TI_WARN(__VA_ARGS__); \
82 }
83#define TI_ERROR_IF(condition, ...) \
84 if (condition) { \
85 TI_ERROR(__VA_ARGS__); \
86 }
87#define TI_ERROR_UNLESS(condition, ...) \
88 if (!(condition)) { \
89 TI_ERROR(__VA_ARGS__); \
90 }
91#define TI_CRITICAL_IF(condition, ...) \
92 if (condition) { \
93 TI_CRITICAL(__VA_ARGS__); \
94 }
95#define TI_CRITICAL_UNLESS(condition, ...) \
96 if (!(condition)) { \
97 TI_CRITICAL(__VA_ARGS__); \
98 }
99
100#define TI_ASSERT(x) TI_ASSERT_INFO((x), "Assertion failure: " #x)
101#define TI_ASSERT_INFO(x, ...) \
102 { \
103 bool ___ret___ = static_cast<bool>(x); \
104 if (!___ret___) { \
105 TI_ERROR(__VA_ARGS__); \
106 } \
107 }
108#define TI_NOT_IMPLEMENTED TI_ERROR("Not supported.");
109
110#define TI_STOP TI_ERROR("Stopping here")
111#define TI_TAG TI_INFO("Tagging here")
112
113#define TI_LOG_SET_PATTERN(x) spdlog::set_pattern(x);
114
115#define TI_FLUSH_LOGGER \
116 { taichi::Logger::get_instance().flush(); };
117
118#define TI_P(x) \
119 { TI_INFO("{}", taichi::TextSerializer::serialize(#x, (x))); }
120
121namespace taichi {
122
123class TI_DLL_EXPORT Logger {
124 private:
125 std::shared_ptr<spdlog::logger> console_;
126 int level_;
127 std::function<void()> print_stacktrace_fn_;
128
129 Logger();
130
131 public:
132 void trace(const std::string &s);
133 void debug(const std::string &s);
134 void info(const std::string &s);
135 void warn(const std::string &s);
136 void error(const std::string &s, bool raise_exception = true);
137 void critical(const std::string &s);
138 void flush();
139 void set_level(const std::string &level);
140 bool is_level_effective(const std::string &level_name);
141 int get_level();
142 static int level_enum_from_string(const std::string &level);
143 void set_level_default();
144
145 // This is mostly to decouple the implementation.
146 void set_print_stacktrace_func(std::function<void()> print_fn);
147
148 static Logger &get_instance();
149};
150
151} // namespace taichi
152