2 Copyright (C) 2016-2019 "IoT.bzh"
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
24 #define MASKOF(x) (1 << (x))
26 #if !defined(DEFAULT_LOGLEVEL)
27 # define DEFAULT_LOGLEVEL Log_Level_Warning
30 #if !defined(DEFAULT_LOGMASK)
31 # define DEFAULT_LOGMASK (MASKOF((DEFAULT_LOGLEVEL) + 1) - 1)
34 #if !defined(MINIMAL_LOGLEVEL)
35 # define MINIMAL_LOGLEVEL Log_Level_Error
38 #if !defined(MINIMAL_LOGMASK)
39 # define MINIMAL_LOGMASK (MASKOF((MINIMAL_LOGLEVEL) + 1) - 1)
42 static const char *names[] = {
53 static const char asort[] = { 1, 2, 7, 0, 3, 6, 5, 4 };
55 int logmask = DEFAULT_LOGMASK | MINIMAL_LOGMASK;
57 void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args);
59 #define CROP_LOGLEVEL(x) \
60 ((x) < Log_Level_Emergency ? Log_Level_Emergency \
61 : (x) > Log_Level_Debug ? Log_Level_Debug : (x))
63 #if defined(VERBOSE_WITH_SYSLOG)
67 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
71 if (file == NULL || vasprintf(&p, fmt, args) < 0)
72 vsyslog(loglevel, fmt, args);
74 syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, %s]", p, file, line, function?:"?");
79 void verbose_set_name(const char *name, int authority)
81 openlog(name, LOG_PERROR, authority ? LOG_AUTH : LOG_USER);
84 #elif defined(VERBOSE_WITH_SYSTEMD)
86 #define SD_JOURNAL_SUPPRESS_LOCATION
88 #include <systemd/sd-journal.h>
90 static const char *appname;
92 static int appauthority;
94 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
99 sd_journal_printv(loglevel, fmt, args);
101 sprintf(lino, "%d", line);
102 sd_journal_printv_with_location(loglevel, file, lino, function, fmt, args);
106 void verbose_set_name(const char *name, int authority)
109 appauthority = authority;
120 static const char *appname;
122 static int appauthority;
124 static const char *prefixes[] = {
135 static const char *prefixes_colorized[] = {
136 "<0> " COLOR_EMERGENCY "EMERGENCY" COLOR_DEFAULT,
137 "<1> " COLOR_ALERT "ALERT" COLOR_DEFAULT,
138 "<2> " COLOR_CRITICAL "CRITICAL" COLOR_DEFAULT,
139 "<3> " COLOR_ERROR "ERROR" COLOR_DEFAULT,
140 "<4> " COLOR_WARNING "WARNING" COLOR_DEFAULT,
141 "<5> " COLOR_NOTICE "NOTICE" COLOR_DEFAULT,
142 "<6> " COLOR_INFO "INFO" COLOR_DEFAULT,
143 "<7> " COLOR_DEBUG "DEBUG" COLOR_DEFAULT
146 static int colorize = 0;
150 static const char chars[] = { '\n', '?', ':', ' ', '[', ',', ']' };
152 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
154 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
159 struct iovec iov[20];
164 /* check if tty (2) or not (1) */
166 tty = 1 + isatty(STDERR_FILENO);
170 iov[0].iov_base = (void*)prefixes_colorized[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
172 iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
173 iov[0].iov_len = strlen(iov[0].iov_base);
176 iov[1].iov_base = (void*)&chars[2];
181 iov[n].iov_base = buffer;
183 rc = vsnprintf(buffer, sizeof buffer, fmt, args);
186 else if ((size_t)rc > sizeof buffer) {
187 /* if too long, ellipsis the end with ... */
188 rc = (int)sizeof buffer;
189 buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.';
191 iov[n++].iov_len = (size_t)rc;
193 if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) {
197 iov[n].iov_base = (void*)COLOR_FILE;
198 iov[n++].iov_len = strlen(COLOR_FILE);
201 /* "[" (!fmt) or " [" (fmt) */
202 iov[n].iov_base = (void*)&chars[3 + !fmt];
203 iov[n++].iov_len = 2 - !fmt;
205 iov[n].iov_base = (void*)file;
206 iov[n++].iov_len = strlen(file);
208 iov[n].iov_base = (void*)&chars[2];
209 iov[n++].iov_len = 1;
212 iov[n].iov_base = lino;
213 iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line);
216 iov[n].iov_base = (void*)&chars[1];
217 iov[n++].iov_len = 1;
220 iov[n].iov_base = (void*)&chars[5];
221 iov[n++].iov_len = 1;
224 iov[n].iov_base = (void*)function;
225 iov[n++].iov_len = strlen(function);
228 iov[n].iov_base = (void*)&chars[1];
229 iov[n++].iov_len = 1;
231 iov[n].iov_base = (void*)&chars[6];
232 iov[n++].iov_len = 1;
236 iov[n].iov_base = (void*)COLOR_DEFAULT;
237 iov[n++].iov_len = strlen(COLOR_DEFAULT);
242 iov[n].iov_base = (void*)&chars[1];
243 iov[n++].iov_len = 1;
246 iov[n].iov_base = (void*)&chars[0];
247 iov[n++].iov_len = 1;
249 /* emit the message */
250 pthread_mutex_lock(&mutex);
251 writev(STDERR_FILENO, iov, n);
252 pthread_mutex_unlock(&mutex);
258 void verbose_set_name(const char *name, int authority)
261 appauthority = authority;
266 void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
268 void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
271 _vverbose_(loglevel, file, line, function, fmt, args);
275 _vverbose_(loglevel, file, line, function, fmt, args);
276 observer(loglevel, file, line, function, fmt, ap);
281 void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
286 vverbose(loglevel, file, line, function, fmt, ap);
290 void set_logmask(int lvl)
292 logmask = lvl | MINIMAL_LOGMASK;
295 void verbose_add(int level)
297 set_logmask(logmask | MASKOF(level));
300 void verbose_sub(int level)
302 set_logmask(logmask & ~MASKOF(level));
312 verbosity_set(verbosity_get() - 1);
317 verbosity_set(verbosity_get() + 1);
320 int verbosity_to_mask(int verbo)
322 int x = verbo + Log_Level_Error;
323 int l = CROP_LOGLEVEL(x);
324 return (1 << (l + 1)) - 1;
327 int verbosity_from_mask(int mask)
330 while (mask > verbosity_to_mask(v))
335 void verbosity_set(int verbo)
337 set_logmask(verbosity_to_mask(verbo));
342 return verbosity_from_mask(logmask);
345 int verbose_level_of_name(const char *name)
347 int c, i, r, l = 0, u = sizeof names / sizeof * names;
351 c = strcasecmp(names[r], name);
362 const char *verbose_name_of_level(int level)
364 return level == CROP_LOGLEVEL(level) ? names[level] : NULL;
367 void verbose_colorize()
372 int verbose_is_colorized()