log.h 4.48 KB
Newer Older
1
2
/*!
 * Copyright (c) 2016 Microsoft Corporation. All rights reserved.
3
4
 * Licensed under the MIT License. See LICENSE file in the project root for
 * license information.
5
 */
6
7
#ifndef LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_LOG_H_
#define LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_LOG_H_
Guolin Ke's avatar
Guolin Ke committed
8

9
#include <cstdarg>
Guolin Ke's avatar
Guolin Ke committed
10
11
12
#include <cstdio>
#include <cstdlib>
#include <cstring>
13
#include <exception>
14
#include <iostream>
15
#include <stdexcept>
16
#include <string>
Guolin Ke's avatar
Guolin Ke committed
17

18
#ifdef LGB_R_BUILD
19
20

#ifndef R_NO_REMAP
21
#define R_NO_REMAP
22
23
24
#endif

#ifndef R_USE_C99_IN_CXX
25
#define R_USE_C99_IN_CXX
26
27
#endif

28
#include <R_ext/Print.h>
29
extern "C" void R_FlushConsole(void);
30
31
#endif

Guolin Ke's avatar
Guolin Ke committed
32
33
namespace LightGBM {

34
#if defined(_MSC_VER)
35
#define THREAD_LOCAL __declspec(thread)
36
37
38
#else
#define THREAD_LOCAL thread_local
#endif
Guolin Ke's avatar
Guolin Ke committed
39

Qiwei Ye's avatar
Qiwei Ye committed
40
#ifndef CHECK
41
42
43
44
#define CHECK(condition)                                                    \
  if (!(condition))                                                         \
    Log::Fatal("Check failed: " #condition " at %s, line %d .\n", __FILE__, \
               __LINE__);
Guolin Ke's avatar
Guolin Ke committed
45
#endif
Qiwei Ye's avatar
Qiwei Ye committed
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#ifndef CHECK_EQ
#define CHECK_EQ(a, b) CHECK((a) == (b))
#endif

#ifndef CHECK_NE
#define CHECK_NE(a, b) CHECK((a) != (b))
#endif

#ifndef CHECK_GE
#define CHECK_GE(a, b) CHECK((a) >= (b))
#endif

#ifndef CHECK_LE
#define CHECK_LE(a, b) CHECK((a) <= (b))
#endif

#ifndef CHECK_GT
#define CHECK_GT(a, b) CHECK((a) > (b))
#endif

#ifndef CHECK_LT
#define CHECK_LT(a, b) CHECK((a) < (b))
#endif

Qiwei Ye's avatar
Qiwei Ye committed
71
#ifndef CHECK_NOTNULL
72
73
74
75
#define CHECK_NOTNULL(pointer)                                         \
  if ((pointer) == nullptr)                                            \
    LightGBM::Log::Fatal(#pointer " Can't be NULL at %s, line %d .\n", \
                         __FILE__, __LINE__);
Guolin Ke's avatar
Guolin Ke committed
76
#endif
Qiwei Ye's avatar
Qiwei Ye committed
77

78
enum class LogLevel : int {
Guolin Ke's avatar
Guolin Ke committed
79
  Fatal = -1,
Qiwei Ye's avatar
Qiwei Ye committed
80
  Warning = 0,
Qiwei Ye's avatar
Qiwei Ye committed
81
  Info = 1,
Guolin Ke's avatar
Guolin Ke committed
82
  Debug = 2,
Guolin Ke's avatar
Guolin Ke committed
83
84
};

Qiwei Ye's avatar
Qiwei Ye committed
85
/*!
86
87
 * \brief A static Log class
 */
Qiwei Ye's avatar
Qiwei Ye committed
88
class Log {
Nikita Titov's avatar
Nikita Titov committed
89
 public:
90
  using Callback = void (*)(const char *);
Qiwei Ye's avatar
Qiwei Ye committed
91
  /*!
92
93
94
95
96
97
   * \brief Resets the minimal log level. It is INFO by default.
   * \param level The new minimal log level.
   */
  static void ResetLogLevel(LogLevel level) { GetLevel() = level; }

  static void ResetCallBack(Callback callback) { GetLogCallBack() = callback; }
Guolin Ke's avatar
Guolin Ke committed
98
99
100
101
102
103
104
105
106
107
108
109
110

  static void Debug(const char *format, ...) {
    va_list val;
    va_start(val, format);
    Write(LogLevel::Debug, "Debug", format, val);
    va_end(val);
  }
  static void Info(const char *format, ...) {
    va_list val;
    va_start(val, format);
    Write(LogLevel::Info, "Info", format, val);
    va_end(val);
  }
Qiwei Ye's avatar
Qiwei Ye committed
111
  static void Warning(const char *format, ...) {
Guolin Ke's avatar
Guolin Ke committed
112
113
    va_list val;
    va_start(val, format);
Qiwei Ye's avatar
Qiwei Ye committed
114
    Write(LogLevel::Warning, "Warning", format, val);
Guolin Ke's avatar
Guolin Ke committed
115
116
117
118
    va_end(val);
  }
  static void Fatal(const char *format, ...) {
    va_list val;
119
120
    const size_t kBufSize = 1024;
    char str_buf[kBufSize];
Guolin Ke's avatar
Guolin Ke committed
121
    va_start(val, format);
122
#ifdef _MSC_VER
123
    vsnprintf_s(str_buf, kBufSize, format, val);
124
#else
125
    vsnprintf(str_buf, kBufSize, format, val);
126
#endif
Guolin Ke's avatar
Guolin Ke committed
127
    va_end(val);
128

129
130
131
132
133
134
// R code should write back to R's error stream,
// otherwise to stderr
#ifndef LGB_R_BUILD
    fprintf(stderr, "[LightGBM] [Fatal] %s\n", str_buf);
    fflush(stderr);
#else
135
136
    REprintf("[LightGBM] [Fatal] %s\n", str_buf);
    R_FlushConsole();
137
#endif
138
    throw std::runtime_error(std::string(str_buf));
Guolin Ke's avatar
Guolin Ke committed
139
  }
Qiwei Ye's avatar
Qiwei Ye committed
140

Nikita Titov's avatar
Nikita Titov committed
141
 private:
142
143
  static void Write(LogLevel level, const char *level_str, const char *format,
                    va_list val) {
Guolin Ke's avatar
Guolin Ke committed
144
    if (level <= GetLevel()) {  // omit the message with low level
145
146
147
148
// R code should write back to R's output stream,
// otherwise to stdout
#ifndef LGB_R_BUILD
      if (GetLogCallBack() == nullptr) {
149
150
151
152
        printf("[LightGBM] [%s] ", level_str);
        vprintf(format, val);
        printf("\n");
        fflush(stdout);
153
154
155
156
157
158
159
160
161
162
163
164
165
      } else {
        const size_t kBufSize = 512;
        char buf[kBufSize];
        snprintf(buf, kBufSize, "[LightGBM] [%s] ", level_str);
        GetLogCallBack()(buf);
        vsnprintf(buf, kBufSize, format, val);
        GetLogCallBack()(buf);
        GetLogCallBack()("\n");
      }
#else
      Rprintf("[LightGBM] [%s] ", level_str);
      Rvprintf(format, val);
      Rprintf("\n");
166
      R_FlushConsole();
167
#endif
Guolin Ke's avatar
Guolin Ke committed
168
169
170
    }
  }

171
  // a trick to use static variable in header file.
Guolin Ke's avatar
Guolin Ke committed
172
  // May be not good, but avoid to use an additional cpp file
173
174
175
176
177
178
179
180
181
  static LogLevel &GetLevel() {
    static THREAD_LOCAL LogLevel level = LogLevel::Info;
    return level;
  }

  static Callback &GetLogCallBack() {
    static THREAD_LOCAL Callback callback = nullptr;
    return callback;
  }
Qiwei Ye's avatar
Qiwei Ye committed
182
};
Guolin Ke's avatar
Guolin Ke committed
183
184

}  // namespace LightGBM
185
#endif  // LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_LOG_H_