2 Copyright (C) 2016, 2017, 2018 "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[] = {
137 static const char chars[] = { '\n', '?', ':', ' ', '[', ',', ']' };
139 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
141 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
146 struct iovec iov[20];
151 /* check if tty (2) or not (1) */
153 tty = 1 + isatty(STDERR_FILENO);
156 iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
157 iov[0].iov_len = strlen(iov[0].iov_base);
160 iov[1].iov_base = (void*)&chars[2];
165 iov[n].iov_base = buffer;
167 rc = vsnprintf(buffer, sizeof buffer, fmt, args);
170 else if ((size_t)rc > sizeof buffer) {
171 /* if too long, ellipsis the end with ... */
172 rc = (int)sizeof buffer;
173 buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.';
175 iov[n++].iov_len = (size_t)rc;
177 if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) {
178 /* "[" (!fmt) or " [" (fmt) */
179 iov[n].iov_base = (void*)&chars[3 + !fmt];
180 iov[n++].iov_len = 2 - !fmt;
182 iov[n].iov_base = (void*)file;
183 iov[n++].iov_len = strlen(file);
185 iov[n].iov_base = (void*)&chars[2];
186 iov[n++].iov_len = 1;
189 iov[n].iov_base = lino;
190 iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line);
193 iov[n].iov_base = (void*)&chars[1];
194 iov[n++].iov_len = 1;
197 iov[n].iov_base = (void*)&chars[5];
198 iov[n++].iov_len = 1;
201 iov[n].iov_base = (void*)function;
202 iov[n++].iov_len = strlen(function);
205 iov[n].iov_base = (void*)&chars[1];
206 iov[n++].iov_len = 1;
208 iov[n].iov_base = (void*)&chars[6];
209 iov[n++].iov_len = 1;
213 iov[n].iov_base = (void*)&chars[1];
214 iov[n++].iov_len = 1;
217 iov[n].iov_base = (void*)&chars[0];
218 iov[n++].iov_len = 1;
220 /* emit the message */
221 pthread_mutex_lock(&mutex);
222 writev(STDERR_FILENO, iov, n);
223 pthread_mutex_unlock(&mutex);
229 void verbose_set_name(const char *name, int authority)
232 appauthority = authority;
237 void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
239 void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
242 _vverbose_(loglevel, file, line, function, fmt, args);
246 _vverbose_(loglevel, file, line, function, fmt, args);
247 observer(loglevel, file, line, function, fmt, ap);
252 void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
257 vverbose(loglevel, file, line, function, fmt, ap);
261 void set_logmask(int lvl)
263 logmask = lvl | MINIMAL_LOGMASK;
266 void verbose_add(int level)
268 set_logmask(logmask | MASKOF(level));
271 void verbose_sub(int level)
273 set_logmask(logmask & ~MASKOF(level));
283 verbosity_set(verbosity_get() - 1);
288 verbosity_set(verbosity_get() + 1);
291 int verbosity_to_mask(int verbo)
293 int x = verbo + Log_Level_Error;
294 int l = CROP_LOGLEVEL(x);
295 return (1 << (l + 1)) - 1;
298 int verbosity_from_mask(int mask)
301 while (mask > verbosity_to_mask(v))
306 void verbosity_set(int verbo)
308 set_logmask(verbosity_to_mask(verbo));
313 return verbosity_from_mask(logmask);
316 int verbose_level_of_name(const char *name)
318 int c, i, r, l = 0, u = sizeof names / sizeof * names;
322 c = strcasecmp(names[r], name);
333 const char *verbose_name_of_level(int level)
335 return level == CROP_LOGLEVEL(level) ? names[level] : NULL;