log.h 4.25 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
22
#define R_NO_REMAP
#define R_USE_C99_IN_CXX
#include <R_ext/Error.h>
#include <R_ext/Print.h>
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
    char str_buf[1024];
Guolin Ke's avatar
Guolin Ke committed
113
    va_start(val, format);
114
115
116
117
118
#ifdef _MSC_VER
    vsprintf_s(str_buf, format, val);
#else
    vsprintf(str_buf, format, val);
#endif
Guolin Ke's avatar
Guolin Ke committed
119
    va_end(val);
120

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

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

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

}  // namespace LightGBM
175
#endif  // LightGBM_UTILS_LOG_H_