1/*
2 * Copyright 2017-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include <folly/Conv.h>
19#include <folly/Format.h>
20#include <folly/logging/LogCategory.h>
21#include <folly/logging/LogLevel.h>
22#include <folly/logging/LogStream.h>
23#include <folly/logging/LogStreamProcessor.h>
24
25/**
26 * Log a message to the specified logger.
27 *
28 * This macro avoids evaluating the log arguments unless the log level check
29 * succeeds.
30 *
31 * Beware that the logger argument is evaluated twice, so this argument should
32 * be an expression with no side-effects.
33 */
34#define FB_LOG(logger, level, ...) \
35 FB_LOG_IMPL( \
36 logger, \
37 ::folly::LogLevel::level, \
38 ::folly::LogStreamProcessor::APPEND, \
39 ##__VA_ARGS__)
40
41/**
42 * Log a message to the specified logger, using a folly::format() string.
43 *
44 * The arguments will be processed using folly::format(). The format syntax
45 * is similar to Python format strings.
46 *
47 * This macro avoids evaluating the log arguments unless the log level check
48 * succeeds.
49 *
50 * Beware that the logger argument is evaluated twice, so this argument should
51 * be an expression with no side-effects.
52 */
53#define FB_LOGF(logger, level, fmt, arg1, ...) \
54 FB_LOG_IMPL( \
55 logger, \
56 ::folly::LogLevel::level, \
57 ::folly::LogStreamProcessor::FORMAT, \
58 fmt, \
59 arg1, \
60 ##__VA_ARGS__)
61
62/**
63 * FB_LOG_RAW() can be used by callers that want to pass in the log level as a
64 * variable, and/or who want to explicitly specify the filename and line
65 * number.
66 *
67 * This is useful for callers implementing their own log wrapper functions
68 * that want to pass in their caller's filename and line number rather than
69 * their own.
70 *
71 * The log level parameter must be an explicitly qualified LogLevel value, or a
72 * LogLevel variable. (This differs from FB_LOG() and FB_LOGF() which accept
73 * an unqualified LogLevel name.)
74 */
75#define FB_LOG_RAW(logger, level, filename, linenumber, functionName, ...) \
76 FB_LOG_RAW_IMPL( \
77 logger, \
78 level, \
79 filename, \
80 linenumber, \
81 functionName, \
82 ::folly::LogStreamProcessor::APPEND, \
83 ##__VA_ARGS__)
84
85/**
86 * FB_LOGF_RAW() is similar to FB_LOG_RAW(), but formats the log arguments
87 * using folly::format().
88 */
89#define FB_LOGF_RAW( \
90 logger, level, filename, linenumber, functionName, fmt, arg1, ...) \
91 FB_LOG_RAW_IMPL( \
92 logger, \
93 level, \
94 filename, \
95 linenumber, \
96 functionName, \
97 ::folly::LogStreamProcessor::FORMAT, \
98 fmt, \
99 arg1, \
100 ##__VA_ARGS__)
101
102/**
103 * Helper macro for implementing FB_LOG() and FB_LOGF().
104 *
105 * This macro generally should not be used directly by end users.
106 */
107#define FB_LOG_IMPL(logger, level, type, ...) \
108 (!(logger).getCategory()->logCheck(level)) \
109 ? ::folly::logDisabledHelper( \
110 ::folly::bool_constant<::folly::isLogLevelFatal(level)>{}) \
111 : ::folly::LogStreamVoidify<::folly::isLogLevelFatal(level)>{} & \
112 ::folly::LogStreamProcessor{(logger).getCategory(), \
113 (level), \
114 __FILE__, \
115 __LINE__, \
116 __func__, \
117 (type), \
118 ##__VA_ARGS__} \
119 .stream()
120
121/**
122 * Helper macro for implementing FB_LOG_RAW() and FB_LOGF_RAW().
123 *
124 * This macro generally should not be used directly by end users.
125 *
126 * This is very similar to FB_LOG_IMPL(), but since the level may be a variable
127 * instead of a compile-time constant, we cannot detect at compile time if this
128 * is a fatal log message or not.
129 */
130#define FB_LOG_RAW_IMPL( \
131 logger, level, filename, line, functionName, type, ...) \
132 (!(logger).getCategory()->logCheck(level)) \
133 ? static_cast<void>(0) \
134 : ::folly::LogStreamVoidify<false>{} & \
135 ::folly::LogStreamProcessor{(logger).getCategory(), \
136 (level), \
137 (filename), \
138 (line), \
139 (functionName), \
140 (type), \
141 ##__VA_ARGS__} \
142 .stream()
143
144namespace folly {
145
146class LoggerDB;
147class LogMessage;
148
149/**
150 * Logger is the class you will use to specify the log category when logging
151 * messages with FB_LOG().
152 *
153 * Logger is really just a small wrapper class that contains a pointer to the
154 * appropriate LogCategory object. It primarily exists as syntactic sugar to
155 * allow for easily looking up LogCategory objects.
156 */
157class Logger {
158 public:
159 /**
160 * Construct a Logger for the given category name.
161 *
162 * A LogCategory object for this category will be created if one does not
163 * already exist.
164 */
165 explicit Logger(folly::StringPiece name);
166
167 /**
168 * Construct a Logger pointing to an existing LogCategory object.
169 */
170 explicit Logger(LogCategory* cat);
171
172 /**
173 * Construct a Logger for a specific LoggerDB object, rather than the main
174 * singleton.
175 *
176 * This is primarily intended for use in unit tests.
177 */
178 Logger(LoggerDB* db, folly::StringPiece name);
179
180 /**
181 * Get the LogCategory that this Logger refers to.
182 */
183 LogCategory* getCategory() const {
184 return category_;
185 }
186
187 private:
188 LogCategory* const category_{nullptr};
189};
190} // namespace folly
191