log.h 4.37 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
 */
Guolin Ke's avatar
Guolin Ke committed
6
7
8
#ifndef LIGHTGBM_UTILS_LOG_H_
#define LIGHTGBM_UTILS_LOG_H_

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
21
#define R_NO_REMAP
#define R_USE_C99_IN_CXX
#include <R_ext/Print.h>
22
extern "C" void R_FlushConsole(void);
23
24
#endif

Guolin Ke's avatar
Guolin Ke committed
25
26
namespace LightGBM {

27
#if defined(_MSC_VER)
28
#define THREAD_LOCAL __declspec(thread)
29
30
31
#else
#define THREAD_LOCAL thread_local
#endif
Guolin Ke's avatar
Guolin Ke committed
32

Qiwei Ye's avatar
Qiwei Ye committed
33
#ifndef CHECK
34
35
36
37
#define CHECK(condition)                                                    \
  if (!(condition))                                                         \
    Log::Fatal("Check failed: " #condition " at %s, line %d .\n", __FILE__, \
               __LINE__);
Guolin Ke's avatar
Guolin Ke committed
38
#endif
Qiwei Ye's avatar
Qiwei Ye committed
39

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#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
64
#ifndef CHECK_NOTNULL
65
66
67
68
#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
69
#endif
Qiwei Ye's avatar
Qiwei Ye committed
70

71
enum class LogLevel : int {
Guolin Ke's avatar
Guolin Ke committed
72
  Fatal = -1,
Qiwei Ye's avatar
Qiwei Ye committed
73
  Warning = 0,
Qiwei Ye's avatar
Qiwei Ye committed
74
  Info = 1,
Guolin Ke's avatar
Guolin Ke committed
75
  Debug = 2,
Guolin Ke's avatar
Guolin Ke committed
76
77
};

Qiwei Ye's avatar
Qiwei Ye committed
78
/*!
79
80
 * \brief A static Log class
 */
Qiwei Ye's avatar
Qiwei Ye committed
81
class Log {
Nikita Titov's avatar
Nikita Titov committed
82
 public:
83
  using Callback = void (*)(const char *);
Qiwei Ye's avatar
Qiwei Ye committed
84
  /*!
85
86
87
88
89
90
   * \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
91
92
93
94
95
96
97
98
99
100
101
102
103

  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
104
  static void Warning(const char *format, ...) {
Guolin Ke's avatar
Guolin Ke committed
105
106
    va_list val;
    va_start(val, format);
Qiwei Ye's avatar
Qiwei Ye committed
107
    Write(LogLevel::Warning, "Warning", format, val);
Guolin Ke's avatar
Guolin Ke committed
108
109
110
111
    va_end(val);
  }
  static void Fatal(const char *format, ...) {
    va_list val;
112
113
    const size_t kBufSize = 1024;
    char str_buf[kBufSize];
Guolin Ke's avatar
Guolin Ke committed
114
    va_start(val, format);
115
#ifdef _MSC_VER
116
    vsnprintf_s(str_buf, kBufSize, format, val);
117
#else
118
    vsnprintf(str_buf, kBufSize, format, val);
119
#endif
Guolin Ke's avatar
Guolin Ke committed
120
    va_end(val);
121

122
123
124
125
126
127
// 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
128
129
    REprintf("[LightGBM] [Fatal] %s\n", str_buf);
    R_FlushConsole();
130
#endif
131
    throw std::runtime_error(std::string(str_buf));
Guolin Ke's avatar
Guolin Ke committed
132
  }
Qiwei Ye's avatar
Qiwei Ye committed
133

Nikita Titov's avatar
Nikita Titov committed
134
 private:
135
136
  static void Write(LogLevel level, const char *level_str, const char *format,
                    va_list val) {
Guolin Ke's avatar
Guolin Ke committed
137
    if (level <= GetLevel()) {  // omit the message with low level
138
139
140
141
// R code should write back to R's output stream,
// otherwise to stdout
#ifndef LGB_R_BUILD
      if (GetLogCallBack() == nullptr) {
142
143
144
145
        printf("[LightGBM] [%s] ", level_str);
        vprintf(format, val);
        printf("\n");
        fflush(stdout);
146
147
148
149
150
151
152
153
154
155
156
157
158
      } 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");
159
      R_FlushConsole();
160
#endif
Guolin Ke's avatar
Guolin Ke committed
161
162
163
    }
  }

164
  // a trick to use static variable in header file.
Guolin Ke's avatar
Guolin Ke committed
165
  // May be not good, but avoid to use an additional cpp file
166
167
168
169
170
171
172
173
174
  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
175
};
Guolin Ke's avatar
Guolin Ke committed
176
177

}  // namespace LightGBM
178
#endif  // LightGBM_UTILS_LOG_H_