forked from facebook/watchman
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLogging.h
140 lines (112 loc) · 3.99 KB
/
Logging.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* Copyright 2016-present Facebook, Inc.
* Licensed under the Apache License, Version 2.0 */
#pragma once
#include "watchman_string.h"
#include "PubSub.h"
#include "watchman_preprocessor.h"
namespace watchman {
enum LogLevel { ABORT = -2, FATAL = -1, OFF = 0, ERR = 1, DBG = 2 };
const w_string& logLevelToLabel(LogLevel level);
LogLevel logLabelToLevel(const w_string& label);
class Log {
public:
std::shared_ptr<Publisher::Subscriber> subscribe(
LogLevel level,
Publisher::Notifier notify) {
return levelToPub(level).subscribe(notify);
}
static char* currentTimeString(char* buf, size_t bufsize);
static char* timeString(char* buf, size_t bufsize, timeval tv);
static const char* getThreadName();
static const char* setThreadName(std::string&& name);
void setStdErrLoggingLevel(LogLevel level);
// Build a string and log it
template <typename... Args>
void log(LogLevel level, Args&&... args) {
auto& pub = levelToPub(level);
// Avoid building the string if there are no subscribers
if (!pub.hasSubscribers()) {
return;
}
char timebuf[64];
auto payload =
json_object({{"log",
typed_string_to_json(w_string::build(
currentTimeString(timebuf, sizeof(timebuf)),
": [",
getThreadName(),
"] ",
std::forward<Args>(args)...))},
{"unilateral", json_true()},
{"level", typed_string_to_json(logLevelToLabel(level))}});
pub.enqueue(std::move(payload));
}
// Format a string and log it
template <typename... Args>
void logf(LogLevel level, fmt::string_view format_str, Args&&... args) {
auto& pub = levelToPub(level);
// Avoid building the string if there are no subscribers
if (!pub.hasSubscribers()) {
return;
}
char timebuf[64];
auto payload = json_object(
{{"log",
typed_string_to_json(w_string::build(
currentTimeString(timebuf, sizeof(timebuf)),
": [",
getThreadName(),
"] ",
fmt::format(format_str, std::forward<Args>(args)...)))},
{"unilateral", json_true()},
{"level", typed_string_to_json(logLevelToLabel(level))}});
pub.enqueue(std::move(payload));
}
Log();
private:
std::shared_ptr<Publisher> errorPub_;
std::shared_ptr<Publisher> debugPub_;
std::shared_ptr<Publisher::Subscriber> errorSub_;
std::shared_ptr<Publisher::Subscriber> debugSub_;
std::mutex stdErrPrintMutex_;
inline Publisher& levelToPub(LogLevel level) {
return level == DBG ? *debugPub_ : *errorPub_;
}
void doLogToStdErr();
};
// Get the logger singleton
Log& getLog();
template <typename... Args>
void log(LogLevel level, Args&&... args) {
getLog().log(level, std::forward<Args>(args)...);
}
template <typename... Args>
void logf(LogLevel level, fmt::string_view format_str, Args&&... args) {
getLog().logf(level, format_str, std::forward<Args>(args)...);
}
#ifdef _WIN32
LONG WINAPI exception_filter(LPEXCEPTION_POINTERS excep);
#endif
} // namespace watchman
template <typename... Args>
const char* w_set_thread_name(Args&&... args) {
auto name = folly::to<std::string>(std::forward<Args>(args)...);
return watchman::Log::setThreadName(std::move(name));
}
#define w_check(e, ...) \
if (!(e)) { \
watchman::logf( \
watchman::ERR, \
"{}:{} failed assertion `{}'\n", \
__FILE__, \
__LINE__, \
#e); \
watchman::log(watchman::FATAL, __VA_ARGS__); \
}
// Similar to assert(), but uses W_LOG_FATAL to log the stack trace
// before giving up the ghost
#ifdef NDEBUG
#define w_assert(e, ...) ((void)0)
#else
#define w_assert(e, ...) w_check(e, __VA_ARGS__)
#endif