verbose: Fix wrong error report
[src/app-framework-binder.git] / src / verbose.c
1 /*
2  Copyright (C) 2016, 2017 "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
89 static const char *appname;
90
91 static int appauthority;
92
93 static const char *prefixes[] = {
94         "<0> EMERGENCY",
95         "<1> ALERT",
96         "<2> CRITICAL",
97         "<3> ERROR",
98         "<4> WARNING",
99         "<5> NOTICE",
100         "<6> INFO",
101         "<7> DEBUG"
102 };
103
104 static int tty;
105
106 static const char chars[] = { '\n', '?', ':', ' ', '[', ',', ']' };
107
108 static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
109 {
110         char buffer[4000];
111         char lino[40];
112         int saverr, n, rc;
113         struct iovec iov[20];
114
115         saverr = errno;
116
117         if (!tty)
118                 tty = 1 + isatty(STDERR_FILENO);
119
120         iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0);
121         iov[0].iov_len = strlen(iov[0].iov_base);
122
123         iov[1].iov_base = (void*)&chars[2];
124         iov[1].iov_len = 2;
125
126         n = 2;
127         if (fmt) {
128                 iov[n].iov_base = buffer;
129                 errno = saverr;
130                 rc = vsnprintf(buffer, sizeof buffer, fmt, args);
131                 if (rc < 0)
132                         rc = 0;
133                 else if ((size_t)rc > sizeof buffer) {
134                         rc = (int)sizeof buffer;
135                         buffer[rc - 1] = buffer[rc - 2]  = buffer[rc - 3] = '.';
136                 }
137                 iov[n++].iov_len = (size_t)rc;
138         }
139         if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) {
140                 iov[n].iov_base = (void*)&chars[3 + !fmt];
141                 iov[n++].iov_len = 2 - !fmt;
142                 iov[n].iov_base = (void*)file;
143                 iov[n++].iov_len = strlen(file);
144                 iov[n].iov_base = (void*)&chars[2];
145                 iov[n++].iov_len = 1;
146                 if (line) {
147                         iov[n].iov_base = lino;
148                         iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line);
149                 } else {
150                         iov[n].iov_base = (void*)&chars[1];
151                         iov[n++].iov_len = 1;
152                 }
153                 iov[n].iov_base = (void*)&chars[5];
154                 iov[n++].iov_len = 1;
155                 if (function) {
156                         iov[n].iov_base = (void*)function;
157                         iov[n++].iov_len = strlen(function);
158                 } else {
159                         iov[n].iov_base = (void*)&chars[1];
160                         iov[n++].iov_len = 1;
161                 }
162                 iov[n].iov_base = (void*)&chars[6];
163                 iov[n++].iov_len = 1;
164         }
165         if (n == 2) {
166                 iov[n].iov_base = (void*)&chars[1];
167                 iov[n++].iov_len = 1;
168         }
169         iov[n].iov_base = (void*)&chars[0];
170         iov[n++].iov_len = 1;
171
172         writev(STDERR_FILENO, iov, n);
173
174         errno = saverr;
175 }
176
177 void verbose_set_name(const char *name, int authority)
178 {
179         appname = name;
180         appauthority = authority;
181 }
182
183 #endif
184
185 void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...)
186 {
187         va_list ap;
188
189         va_start(ap, fmt);
190         vverbose(loglevel, file, line, function, fmt, ap);
191         va_end(ap);
192 }
193
194 void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args)
195 {
196         void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer;
197
198         if (!observer)
199                 _vverbose_(loglevel, file, line, function, fmt, args);
200         else {
201                 va_list ap;
202                 va_copy(ap, args);
203                 _vverbose_(loglevel, file, line, function, fmt, args);
204                 observer(loglevel, file, line, function, fmt, ap);
205                 va_end(ap);
206         }
207 }
208