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

8
9
#include <string>
#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>
Guolin Ke's avatar
Guolin Ke committed
16

17
18
19
20
21
22
23
#ifdef LGB_R_BUILD
  #define R_NO_REMAP
  #define R_USE_C99_IN_CXX
  #include <R_ext/Error.h>
  #include <R_ext/Print.h>
#endif

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

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

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

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#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
62
63
#ifndef CHECK_NOTNULL
#define CHECK_NOTNULL(pointer)                             \
Guolin Ke's avatar
Guolin Ke committed
64
  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
65
#endif
Qiwei Ye's avatar
Qiwei Ye committed
66

Guolin Ke's avatar
Guolin Ke committed
67
68
enum class LogLevel: int {
  Fatal = -1,
Qiwei Ye's avatar
Qiwei Ye committed
69
  Warning = 0,
Qiwei Ye's avatar
Qiwei Ye committed
70
  Info = 1,
Guolin Ke's avatar
Guolin Ke committed
71
  Debug = 2,
Guolin Ke's avatar
Guolin Ke committed
72
73
};

Qiwei Ye's avatar
Qiwei Ye committed
74
/*!
75
* \brief A static Log class
Qiwei Ye's avatar
Qiwei Ye committed
76
77
*/
class Log {
Nikita Titov's avatar
Nikita Titov committed
78
 public:
Qiwei Ye's avatar
Qiwei Ye committed
79
80
81
82
  /*!
  * \brief Resets the minimal log level. It is INFO by default.
  * \param level The new minimal log level.
  */
Guolin Ke's avatar
Guolin Ke committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  static void ResetLogLevel(LogLevel level) {
    GetLevel() = level;
  }

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

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

Nikita Titov's avatar
Nikita Titov committed
127
 private:
Guolin Ke's avatar
Guolin Ke committed
128
129
  static void Write(LogLevel level, const char* level_str, const char *format, va_list val) {
    if (level <= GetLevel()) {  // omit the message with low level
130
131
132
133
134
135
136
137
138
139
140
141
      // R code should write back to R's output stream,
      // otherwise to stdout
      #ifndef LGB_R_BUILD
        printf("[LightGBM] [%s] ", level_str);
        vprintf(format, val);
        printf("\n");
        fflush(stdout);
      #else
        Rprintf("[LightGBM] [%s] ", level_str);
        Rvprintf(format, val);
        Rprintf("\n");
      #endif
Guolin Ke's avatar
Guolin Ke committed
142
143
144
    }
  }

145
  // a trick to use static variable in header file.
Guolin Ke's avatar
Guolin Ke committed
146
  // May be not good, but avoid to use an additional cpp file
147
  static LogLevel& GetLevel() { static THREAD_LOCAL LogLevel level = LogLevel::Info; return level; }
Qiwei Ye's avatar
Qiwei Ye committed
148
};
Guolin Ke's avatar
Guolin Ke committed
149
150

}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
151
#endif   // LightGBM_UTILS_LOG_H_