/src/openvswitch/include/openvswitch/vlog.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2016 Nicira, 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 | | |
17 | | #ifndef OPENVSWITCH_VLOG_H |
18 | | #define OPENVSWITCH_VLOG_H 1 |
19 | | |
20 | | /* Logging. |
21 | | * |
22 | | * |
23 | | * Thread-safety |
24 | | * ============= |
25 | | * |
26 | | * Fully thread safe. |
27 | | */ |
28 | | |
29 | | #include <limits.h> |
30 | | #include <stdarg.h> |
31 | | #include <stdbool.h> |
32 | | #include <time.h> |
33 | | #include <openvswitch/compiler.h> |
34 | | #include <openvswitch/list.h> |
35 | | #include <openvswitch/thread.h> |
36 | | #include <openvswitch/token-bucket.h> |
37 | | #include <openvswitch/util.h> |
38 | | |
39 | | #ifdef __cplusplus |
40 | | extern "C" { |
41 | | #endif |
42 | | |
43 | | /* Logging severity levels. |
44 | | * |
45 | | * ovs-appctl(8) defines each of the log levels. */ |
46 | | #define VLOG_LEVELS \ |
47 | | VLOG_LEVEL(OFF, LOG_ALERT, 1) \ |
48 | | VLOG_LEVEL(EMER, LOG_ALERT, 1) \ |
49 | | VLOG_LEVEL(ERR, LOG_ERR, 3) \ |
50 | | VLOG_LEVEL(WARN, LOG_WARNING, 4) \ |
51 | | VLOG_LEVEL(INFO, LOG_NOTICE, 5) \ |
52 | | VLOG_LEVEL(DBG, LOG_DEBUG, 7) |
53 | | enum vlog_level { |
54 | | #define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424_LEVEL) VLL_##NAME, |
55 | | VLOG_LEVELS |
56 | | #undef VLOG_LEVEL |
57 | | VLL_N_LEVELS |
58 | | }; |
59 | | |
60 | | const char *vlog_get_level_name(enum vlog_level); |
61 | | enum vlog_level vlog_get_level_val(const char *name); |
62 | | |
63 | | /* Destinations that we can log to. */ |
64 | | #define VLOG_DESTINATIONS \ |
65 | | VLOG_DESTINATION(SYSLOG, "ovs|%05N|%c%T|%p|%m") \ |
66 | | VLOG_DESTINATION(CONSOLE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m") \ |
67 | | VLOG_DESTINATION(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m") |
68 | | enum vlog_destination { |
69 | | #define VLOG_DESTINATION(NAME, PATTERN) VLF_##NAME, |
70 | | VLOG_DESTINATIONS |
71 | | #undef VLOG_DESTINATION |
72 | | VLF_N_DESTINATIONS, |
73 | | VLF_ANY_DESTINATION = -1 |
74 | | }; |
75 | | |
76 | | const char *vlog_get_destination_name(enum vlog_destination); |
77 | | enum vlog_destination vlog_get_destination_val(const char *name); |
78 | | |
79 | | /* A log module. */ |
80 | | struct vlog_module { |
81 | | struct ovs_list list; |
82 | | const char *name; /* User-visible name. */ |
83 | | int levels[VLF_N_DESTINATIONS]; /* Minimum log level for each |
84 | | destination. */ |
85 | | int min_level; /* Minimum log level for any destination. */ |
86 | | bool honor_rate_limits; /* Set false to ignore rate limits. */ |
87 | | }; |
88 | | |
89 | | void vlog_insert_module(struct ovs_list *); |
90 | | |
91 | | const char *vlog_get_module_name(const struct vlog_module *); |
92 | | struct vlog_module *vlog_module_from_name(const char *name); |
93 | | |
94 | | /* Rate-limiter for log messages. */ |
95 | | struct vlog_rate_limit { |
96 | | struct token_bucket token_bucket; |
97 | | time_t first_dropped; /* Time first message was dropped. */ |
98 | | time_t last_dropped; /* Time of most recent message drop. */ |
99 | | unsigned int n_dropped; /* Number of messages dropped. */ |
100 | | struct ovs_mutex mutex; /* Mutual exclusion for rate limit. */ |
101 | | }; |
102 | | |
103 | | /* Number of tokens to emit a message. We add 'rate' tokens per millisecond, |
104 | | * thus 60,000 tokens are required to emit one message per minute. */ |
105 | 0 | #define VLOG_MSG_TOKENS (60 * 1000) |
106 | | |
107 | | /* Initializer for a struct vlog_rate_limit, to set up a maximum rate of RATE |
108 | | * messages per minute and a maximum burst size of BURST messages. */ |
109 | | #define VLOG_RATE_LIMIT_INIT(RATE, BURST) \ |
110 | 0 | { \ |
111 | 0 | TOKEN_BUCKET_INIT(RATE, OVS_SAT_MUL(BURST, VLOG_MSG_TOKENS)), \ |
112 | 0 | 0, /* first_dropped */ \ |
113 | 0 | 0, /* last_dropped */ \ |
114 | 0 | 0, /* n_dropped */ \ |
115 | 0 | OVS_MUTEX_INITIALIZER /* mutex */ \ |
116 | 0 | } |
117 | | |
118 | | /* Configuring how each module logs messages. */ |
119 | | enum vlog_level vlog_get_level(const struct vlog_module *, |
120 | | enum vlog_destination); |
121 | | void vlog_set_levels(struct vlog_module *, |
122 | | enum vlog_destination, enum vlog_level); |
123 | | char *vlog_set_levels_from_string(const char *) OVS_WARN_UNUSED_RESULT; |
124 | | void vlog_set_levels_from_string_assert(const char *); |
125 | | char *vlog_get_levels(void); |
126 | | char *vlog_get_patterns(void); |
127 | | bool vlog_is_enabled(const struct vlog_module *, enum vlog_level); |
128 | | bool vlog_should_drop(const struct vlog_module *, enum vlog_level, |
129 | | struct vlog_rate_limit *); |
130 | | void vlog_set_verbosity(const char *arg); |
131 | | |
132 | | /* Configuring log destinations. */ |
133 | | void vlog_set_pattern(enum vlog_destination, const char *pattern); |
134 | | char *vlog_get_log_file(void); |
135 | | int vlog_set_log_file(const char *file_name); |
136 | | void vlog_close_log_file(void); |
137 | | int vlog_reopen_log_file(void); |
138 | | #ifndef _WIN32 |
139 | | void vlog_change_owner_unix(uid_t, gid_t); |
140 | | #endif |
141 | | |
142 | | /* Configure method how vlog should send messages to syslog server. */ |
143 | | void vlog_set_syslog_method(const char *method); |
144 | | |
145 | | /* Configure syslog target. */ |
146 | | void vlog_set_syslog_target(const char *target); |
147 | | |
148 | | /* Write directly to log file. */ |
149 | | void vlog_direct_write_to_log_file_unsafe(const char *s); |
150 | | |
151 | | /* Return the current log file descriptor. */ |
152 | | int vlog_get_log_file_fd_unsafe(void); |
153 | | |
154 | | /* Initialization. */ |
155 | | void vlog_init(void); |
156 | | void vlog_enable_async(void); |
157 | | void vlog_disable_async(void); |
158 | | |
159 | | /* Functions for actual logging. */ |
160 | | void vlog(const struct vlog_module *, enum vlog_level, const char *format, ...) |
161 | | OVS_PRINTF_FORMAT (3, 4); |
162 | | void vlog_valist(const struct vlog_module *, enum vlog_level, |
163 | | const char *, va_list) |
164 | | OVS_PRINTF_FORMAT (3, 0); |
165 | | |
166 | | OVS_NO_RETURN void vlog_fatal(const struct vlog_module *, const char *format, ...) |
167 | | OVS_PRINTF_FORMAT (2, 3); |
168 | | OVS_NO_RETURN void vlog_fatal_valist(const struct vlog_module *, |
169 | | const char *format, va_list) |
170 | | OVS_PRINTF_FORMAT (2, 0); |
171 | | |
172 | | OVS_NO_RETURN void vlog_abort(const struct vlog_module *, const char *format, ...) |
173 | | OVS_PRINTF_FORMAT (2, 3); |
174 | | OVS_NO_RETURN void vlog_abort_valist(const struct vlog_module *, |
175 | | const char *format, va_list) |
176 | | OVS_PRINTF_FORMAT (2, 0); |
177 | | |
178 | | void vlog_rate_limit(const struct vlog_module *, enum vlog_level, |
179 | | struct vlog_rate_limit *, const char *, ...) |
180 | | OVS_PRINTF_FORMAT (4, 5); |
181 | | |
182 | | /* Defines a logging module whose name is MODULE, which should generally be |
183 | | * roughly the name of the source file, and makes it the module used by the |
184 | | * logging convenience macros defined below. */ |
185 | | #define VLOG_DEFINE_THIS_MODULE(MODULE) \ |
186 | | static struct vlog_module this_module = { \ |
187 | | OVS_LIST_INITIALIZER(&this_module.list), \ |
188 | | #MODULE, /* name */ \ |
189 | | { VLL_INFO, VLL_INFO, VLL_INFO }, /* levels */ \ |
190 | | VLL_INFO, /* min_level */ \ |
191 | | true /* honor_rate_limits */ \ |
192 | | }; \ |
193 | 31 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ |
194 | 31 | vlog_insert_module(&this_module.list); \ |
195 | 31 | } \ jsonrpc.c:init_this_module_jsonrpc Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
ovs-replay.c:init_this_module_ovs_replay Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
ovs-thread.c:init_this_module_ovs_thread Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
poll-loop.c:init_this_module_poll_loop Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
reconnect.c:init_this_module_reconnect Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
socket-util.c:init_this_module_socket_util Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream.c:init_this_module_stream Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
svec.c:init_this_module_svec Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
timeval.c:init_this_module_timeval Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
unixctl.c:init_this_module_unixctl Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
util.c:init_this_module_util Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
vlog.c:init_this_module_vlog Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
socket-util-unix.c:init_this_module_socket_util_unix Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream-unix.c:init_this_module_stream_unix Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream-ssl.c:init_this_module_stream_ssl Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
backtrace.c:init_this_module_backtrace Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
command-line.c:init_this_module_command_line Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
cooperative-multitasking.c:init_this_module_cooperative_multitasking Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
coverage.c:init_this_module_coverage Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
entropy.c:init_this_module_entropy Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
fatal-signal.c:init_this_module_fatal_signal Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
hmap.c:init_this_module_hmap Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
ovs-rcu.c:init_this_module_ovs_rcu Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream-fd.c:init_this_module_stream_fd Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream-replay.c:init_this_module_stream_replay Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
stream-tcp.c:init_this_module_stream_tcp Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
daemon-unix.c:init_this_module_daemon_unix Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
signals.c:init_this_module_signals Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
daemon.c:init_this_module_daemon Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
lockfile.c:init_this_module_lockfile Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
process.c:init_this_module_process Line | Count | Source | 193 | 1 | OVS_CONSTRUCTOR(init_this_module_##MODULE) { \ | 194 | 1 | vlog_insert_module(&this_module.list); \ | 195 | 1 | } \ |
|
196 | | \ |
197 | | /* Prevent duplicate module names, via linker error. \ |
198 | | * The extra "extern" declaration makes sparse happy. */ \ |
199 | | extern struct vlog_module *VLM_##MODULE; \ |
200 | | struct vlog_module *VLM_##MODULE = &this_module; |
201 | | |
202 | | /* Macros for the current module as set up by VLOG_DEFINE_THIS_MODULE. |
203 | | * These are usually what you want to use. |
204 | | * |
205 | | * Guaranteed to preserve errno. |
206 | | */ |
207 | 0 | #define VLOG_FATAL(...) vlog_fatal(&this_module, __VA_ARGS__) |
208 | 0 | #define VLOG_ABORT(...) vlog_abort(&this_module, __VA_ARGS__) |
209 | | #define VLOG_EMER(...) VLOG(VLL_EMER, __VA_ARGS__) |
210 | 0 | #define VLOG_ERR(...) VLOG(VLL_ERR, __VA_ARGS__) |
211 | 0 | #define VLOG_WARN(...) VLOG(VLL_WARN, __VA_ARGS__) |
212 | 0 | #define VLOG_INFO(...) VLOG(VLL_INFO, __VA_ARGS__) |
213 | 0 | #define VLOG_DBG(...) VLOG(VLL_DBG, __VA_ARGS__) |
214 | | |
215 | | /* More convenience macros, for testing whether a given level is enabled. When |
216 | | * constructing a log message is expensive, this enables it to be skipped. */ |
217 | | #define VLOG_IS_ERR_ENABLED() vlog_is_enabled(&this_module, VLL_ERR) |
218 | | #define VLOG_IS_WARN_ENABLED() vlog_is_enabled(&this_module, VLL_WARN) |
219 | | #define VLOG_IS_INFO_ENABLED() vlog_is_enabled(&this_module, VLL_INFO) |
220 | 0 | #define VLOG_IS_DBG_ENABLED() vlog_is_enabled(&this_module, VLL_DBG) |
221 | | |
222 | | /* Convenience macros for rate-limiting. |
223 | | * Guaranteed to preserve errno. |
224 | | */ |
225 | 0 | #define VLOG_ERR_RL(RL, ...) VLOG_RL(RL, VLL_ERR, __VA_ARGS__) |
226 | 0 | #define VLOG_WARN_RL(RL, ...) VLOG_RL(RL, VLL_WARN, __VA_ARGS__) |
227 | 0 | #define VLOG_INFO_RL(RL, ...) VLOG_RL(RL, VLL_INFO, __VA_ARGS__) |
228 | 0 | #define VLOG_DBG_RL(RL, ...) VLOG_RL(RL, VLL_DBG, __VA_ARGS__) |
229 | | |
230 | | /* Convenience macros to additionally store log message in buffer |
231 | | * Caller is responsible for freeing *ERRP afterwards */ |
232 | | #define VLOG_ERR_BUF(ERRP, ...) VLOG_ERRP(ERRP, VLL_ERR, __VA_ARGS__) |
233 | | #define VLOG_WARN_BUF(ERRP, ...) VLOG_ERRP(ERRP, VLL_WARN, __VA_ARGS__) |
234 | | |
235 | | #define VLOG_DROP_ERR(RL) vlog_should_drop(&this_module, VLL_ERR, RL) |
236 | | #define VLOG_DROP_WARN(RL) vlog_should_drop(&this_module, VLL_WARN, RL) |
237 | 0 | #define VLOG_DROP_INFO(RL) vlog_should_drop(&this_module, VLL_INFO, RL) |
238 | | #define VLOG_DROP_DBG(RL) vlog_should_drop(&this_module, VLL_DBG, RL) |
239 | | |
240 | | /* Macros for logging at most once per execution. */ |
241 | 0 | #define VLOG_ERR_ONCE(...) VLOG_ONCE(VLL_ERR, __VA_ARGS__) |
242 | 0 | #define VLOG_WARN_ONCE(...) VLOG_ONCE(VLL_WARN, __VA_ARGS__) |
243 | | #define VLOG_INFO_ONCE(...) VLOG_ONCE(VLL_INFO, __VA_ARGS__) |
244 | | #define VLOG_DBG_ONCE(...) VLOG_ONCE(VLL_DBG, __VA_ARGS__) |
245 | | |
246 | | /* Command line processing. */ |
247 | | #define VLOG_OPTION_ENUMS \ |
248 | | OPT_LOG_FILE, \ |
249 | | OPT_SYSLOG_IMPL, \ |
250 | | OPT_SYSLOG_TARGET |
251 | | |
252 | | #define VLOG_LONG_OPTIONS \ |
253 | | {"verbose", optional_argument, NULL, 'v'}, \ |
254 | | {"log-file", optional_argument, NULL, OPT_LOG_FILE}, \ |
255 | | {"syslog-method", required_argument, NULL, OPT_SYSLOG_IMPL}, \ |
256 | | {"syslog-target", required_argument, NULL, OPT_SYSLOG_TARGET} |
257 | | |
258 | | #define VLOG_OPTION_HANDLERS \ |
259 | | case 'v': \ |
260 | | vlog_set_verbosity(optarg); \ |
261 | | break; \ |
262 | | case OPT_LOG_FILE: { \ |
263 | | int err = vlog_set_log_file(optarg);\ |
264 | | /* Exit if logfile explicitly given \ |
265 | | * but cannot be opened. */ \ |
266 | | if (err && optarg) { \ |
267 | | exit(EXIT_FAILURE); \ |
268 | | } \ |
269 | | break; \ |
270 | | } \ |
271 | | case OPT_SYSLOG_IMPL: \ |
272 | | vlog_set_syslog_method(optarg); \ |
273 | | break; \ |
274 | | case OPT_SYSLOG_TARGET: \ |
275 | | vlog_set_syslog_target(optarg); \ |
276 | | break; |
277 | | |
278 | | void vlog_usage(void); |
279 | | |
280 | | /* Implementation details. */ |
281 | | #define VLOG(LEVEL, ...) \ |
282 | 0 | do { \ |
283 | 0 | enum vlog_level level__ = LEVEL; \ |
284 | 0 | if (this_module.min_level >= level__) { \ |
285 | 0 | vlog(&this_module, level__, __VA_ARGS__); \ |
286 | 0 | } \ |
287 | 0 | } while (0) |
288 | | #define VLOG_RL(RL, LEVEL, ...) \ |
289 | 0 | do { \ |
290 | 0 | enum vlog_level level__ = LEVEL; \ |
291 | 0 | if (this_module.min_level >= level__) { \ |
292 | 0 | vlog_rate_limit(&this_module, level__, RL, __VA_ARGS__); \ |
293 | 0 | } \ |
294 | 0 | } while (0) |
295 | | #define VLOG_ONCE(LEVEL, ...) \ |
296 | 0 | do { \ |
297 | 0 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; \ |
298 | 0 | if (ovsthread_once_start(&once)) { \ |
299 | 0 | vlog(&this_module, LEVEL, __VA_ARGS__); \ |
300 | 0 | ovsthread_once_done(&once); \ |
301 | 0 | } \ |
302 | 0 | } while (0) |
303 | | #define VLOG_ERRP(ERRP, LEVEL, ...) \ |
304 | | do { \ |
305 | | VLOG(LEVEL, __VA_ARGS__); \ |
306 | | if (ERRP) { \ |
307 | | *(ERRP) = xasprintf(__VA_ARGS__); \ |
308 | | } \ |
309 | | } while (0) |
310 | | |
311 | | #ifdef __cplusplus |
312 | | } |
313 | | #endif |
314 | | |
315 | | #endif /* vlog.h */ |