Update date of copyright notices
[src/app-framework-binder.git] / src / verbose.c
1 /*
2  Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
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
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
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.
17 */
18
19 #include <stdio.h>
20 #include <stdarg.h>
21
22 #include "verbose.h"
23
24 #if !defined(DEFAULT_VERBOSITY)
25 # define DEFAULT_VERBOSITY Verbosity_Level_Warning
26 #endif
27
28 int verbosity = 1;
29 void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args);
30
31 #define CROP_LOGLEVEL(x) ((x) < Log_Level_Emergency ? Log_Level_Emergency : (x) > Log_Level_Debug ? Log_Level_Debug : (x))
32
33 #if defined(VERBOSE_WITH_SYSLOG)
34
35 #include <syslog.h>
36
37 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
38 {
39         char *p;
40
41         if (file == NULL || vasprintf(&p, fmt, args) < 0)
42                 vsyslog(loglevel, fmt, args);
43         else {
44                 syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, function]", p, file, line, function);
45                 free(p);
46         }
47 }
48
49 void verbose_set_name(const char *name, int authority)
50 {
51         openlog(name, LOG_PERROR, authority ? LOG_AUTH : LOG_USER);
52 }
53
54 #elif defined(VERBOSE_WITH_SYSTEMD)
55
56 #define SD_JOURNAL_SUPPRESS_LOCATION
57
58 #include <systemd/sd-journal.h>
59
60 static const char *appname;
61
62 static int appauthority;
63
64 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
65 {
66         char lino[20];
67
68         if (file == NULL) {
69                 sd_journal_printv(loglevel, fmt, args);
70         } else {
71                 sprintf(lino, "%d", line);
72                 sd_journal_printv_with_location(loglevel, file, lino, function, fmt, args);
73         }
74 }
75
76 void verbose_set_name(const char *name, int authority)
77 {
78         appname = name;
79         appauthority = authority;
80 }
81
82 #else
83
84 #include <unistd.h>
85 #include <errno.h>
86 #include <string.h>
87 #include <sys/uio.h>
88 #include <pthread.h>
89
90 static const char *appname;
91
92 static int appauthority;
93
94 static const char *prefixes[] = {
95         "<0> EMERGENCY",
96         "<1> ALERT",
97         "<2> CRITICAL",
98         "<3> ERROR",
99         "<4> WARNING",
100         "<5> NOTICE",
101         "<6> INFO",
102         "<7> DEBUG"
103 };
104
105 static int tty;
106
107 static const char chars[] = { '\n', '?', ':', ' ', '[', ',', ']' };
108
109 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
110
111 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
112 {
113         char buffer[4000];
114         char lino[40];
115         int saverr, n, rc;
116         struct iovec iov[20];
117
118         saverr = errno;
119
120         if (!tty)
121                 tty = 1 + isatty(STDERR_FILENO);
122
123         iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
124         iov[0].iov_len = strlen(iov[0].iov_base);
125
126         iov[1].iov_base = (void*)&chars[2];
127         iov[1].iov_len = 2;
128
129         n = 2;
130         if (fmt) {
131                 iov[n].iov_base = buffer;
132                 errno = saverr;
133                 rc = vsnprintf(buffer, sizeof buffer, fmt, args);
134                 if (rc < 0)
135                         rc = 0;
136                 else if ((size_t)rc > sizeof buffer) {
137                         rc = (int)sizeof buffer;
138                         buffer[rc - 1] = buffer[rc - 2]  = buffer[rc - 3] = '.';
139                 }
140                 iov[n++].iov_len = (size_t)rc;
141         }
142         if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) {
143                 iov[n].iov_base = (void*)&chars[3 + !fmt];
144                 iov[n++].iov_len = 2 - !fmt;
145                 iov[n].iov_base = (void*)file;
146                 iov[n++].iov_len = strlen(file);
147                 iov[n].iov_base = (void*)&chars[2];
148                 iov[n++].iov_len = 1;
149                 if (line) {
150                         iov[n].iov_base = lino;
151                         iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line);
152                 } else {
153                         iov[n].iov_base = (void*)&chars[1];
154                         iov[n++].iov_len = 1;
155                 }
156                 iov[n].iov_base = (void*)&chars[5];
157                 iov[n++].iov_len = 1;
158                 if (function) {
159                         iov[n].iov_base = (void*)function;
160                         iov[n++].iov_len = strlen(function);
161                 } else {
162                         iov[n].iov_base = (void*)&chars[1];
163                         iov[n++].iov_len = 1;
164                 }
165                 iov[n].iov_base = (void*)&chars[6];
166                 iov[n++].iov_len = 1;
167         }
168         if (n == 2) {
169                 iov[n].iov_base = (void*)&chars[1];
170                 iov[n++].iov_len = 1;
171         }
172         iov[n].iov_base = (void*)&chars[0];
173         iov[n++].iov_len = 1;
174
175         pthread_mutex_lock(&mutex);
176         writev(STDERR_FILENO, iov, n);
177         pthread_mutex_unlock(&mutex);
178
179         errno = saverr;
180 }
181
182 void verbose_set_name(const char *name, int authority)
183 {
184         appname = name;
185         appauthority = authority;
186 }
187
188 #endif
189
190 void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
191 {
192         va_list ap;
193
194         va_start(ap, fmt);
195         vverbose(loglevel, file, line, function, fmt, ap);
196         va_end(ap);
197 }
198
199 void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
200 {
201         void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
202
203         if (!observer)
204                 _vverbose_(loglevel, file, line, function, fmt, args);
205         else {
206                 va_list ap;
207                 va_copy(ap, args);
208                 _vverbose_(loglevel, file, line, function, fmt, args);
209                 observer(loglevel, file, line, function, fmt, ap);
210                 va_end(ap);
211         }
212 }
213