tizen 2.3 release
[framework/system/dlog.git] / src / libdlog / log.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*-
2  * DLOG
3  * Copyright (c) 2005-2008, The Android Open Source Project
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
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 "config.h"
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <fcntl.h>
25 #include <sys/uio.h>
26 #include <sys/syscall.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <dlog.h>
31 #include "loglimiter.h"
32 #include "logconfig.h"
33 #ifdef HAVE_SYSTEMD_JOURNAL
34 #define SD_JOURNAL_SUPPRESS_LOCATION 1
35 #include <syslog.h>
36 #include <systemd/sd-journal.h>
37 #endif
38 #ifdef FATAL_ON
39 #include <assert.h>
40 #endif
41
42 #define LOG_BUF_SIZE    1024
43
44 #define LOG_MAIN        "log_main"
45 #define LOG_RADIO       "log_radio"
46 #define LOG_SYSTEM      "log_system"
47 #define LOG_APPS        "log_apps"
48
49 #define VALUE_MAX 2
50 #define LOG_CONFIG_FILE "/opt/etc/dlog.conf"
51
52 #ifndef HAVE_SYSTEMD_JOURNAL
53 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
54 #endif
55 static int (*write_to_log)(log_id_t, log_priority, const char *tag, const char *msg) = NULL;
56 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
57 static struct log_config config;
58
59 #ifdef HAVE_SYSTEMD_JOURNAL
60 static inline int dlog_pri_to_journal_pri(log_priority prio)
61 {
62         static int pri_table[DLOG_PRIO_MAX] = {
63                 [DLOG_UNKNOWN] = LOG_DEBUG,
64                 [DLOG_DEFAULT] = LOG_DEBUG,
65                 [DLOG_VERBOSE] = LOG_DEBUG,
66                 [DLOG_DEBUG] = LOG_DEBUG,
67                 [DLOG_INFO] = LOG_INFO,
68                 [DLOG_WARN] = LOG_WARNING,
69                 [DLOG_ERROR] = LOG_ERR,
70                 [DLOG_FATAL] = LOG_CRIT,
71                 [DLOG_SILENT] = -1,
72         };
73
74         if (prio < 0 || prio >= DLOG_PRIO_MAX)
75                 return DLOG_ERROR_INVALID_PARAMETER;
76
77         return pri_table[prio];
78 }
79
80 static inline const char* dlog_id_to_string(log_id_t log_id)
81 {
82         static const char* id_table[LOG_ID_MAX] = {
83                 [LOG_ID_MAIN]   = LOG_MAIN,
84                 [LOG_ID_RADIO]  = LOG_RADIO,
85                 [LOG_ID_SYSTEM] = LOG_SYSTEM,
86                 [LOG_ID_APPS]   = LOG_APPS,
87         };
88
89         if (log_id < 0 || log_id >= LOG_ID_MAX || !id_table[log_id])
90                 return "UNKNOWN";
91
92         return id_table[log_id];
93 }
94
95 static int __write_to_log_sd_journal(log_id_t log_id, log_priority prio, const char *tag, const char *msg)
96 {
97         pid_t tid = (pid_t)syscall(SYS_gettid);
98         /* XXX: sd_journal_sendv() with manually filed iov-s might be faster */
99         return sd_journal_send("MESSAGE=%s", msg,
100                                "PRIORITY=%i", dlog_pri_to_journal_pri(prio),
101                                "LOG_TAG=%s", tag,
102                                "LOG_ID=%s", dlog_id_to_string(log_id),
103                                "TID=%d", tid,
104                                NULL);
105 }
106
107 #else
108 static int __write_to_log_null(log_id_t log_id, log_priority prio, const char *tag, const char *msg)
109 {
110         return DLOG_ERROR_NOT_PERMITTED;
111 }
112
113 static int __write_to_log_kernel(log_id_t log_id, log_priority prio, const char *tag, const char *msg)
114 {
115         ssize_t ret;
116         int log_fd;
117         struct iovec vec[3];
118
119         if (log_id < LOG_ID_MAX)
120                 log_fd = log_fds[log_id];
121         else
122                 return DLOG_ERROR_INVALID_PARAMETER;
123
124         if (prio < DLOG_VERBOSE || prio >= DLOG_PRIO_MAX)
125                 return DLOG_ERROR_INVALID_PARAMETER;
126
127         if (!tag)
128                 tag = "";
129
130         if (!msg)
131                 return DLOG_ERROR_INVALID_PARAMETER;
132
133         vec[0].iov_base = (unsigned char *) &prio;
134         vec[0].iov_len  = 1;
135         vec[1].iov_base = (void *) tag;
136         vec[1].iov_len  = strlen(tag) + 1;
137         vec[2].iov_base = (void *) msg;
138         vec[2].iov_len  = strlen(msg) + 1;
139
140         ret = writev(log_fd, vec, 3);
141         if (ret < 0)
142             ret = errno;
143
144         return ret;
145 }
146 #endif
147
148 static void __configure(void)
149 {
150         if (0 > __log_config_read(LOG_CONFIG_FILE, &config)) {
151                 config.lc_limiter = 0;
152                 config.lc_plog = 0;
153         }
154
155         if (config.lc_limiter) {
156                 if (0 > __log_limiter_initialize()) {
157                         config.lc_limiter = 0;
158                 }
159         }
160 }
161
162 static void __dlog_init(void)
163 {
164         pthread_mutex_lock(&log_init_lock);
165         /* configuration */
166         __configure();
167 #ifdef HAVE_SYSTEMD_JOURNAL
168         write_to_log = __write_to_log_sd_journal;
169 #else
170         /* open device */
171         log_fds[LOG_ID_MAIN] = open("/dev/"LOG_MAIN, O_WRONLY);
172         log_fds[LOG_ID_SYSTEM] = open("/dev/"LOG_SYSTEM, O_WRONLY);
173         log_fds[LOG_ID_RADIO] = open("/dev/"LOG_RADIO, O_WRONLY);
174         log_fds[LOG_ID_APPS] = open("/dev/"LOG_APPS, O_WRONLY);
175         if (log_fds[LOG_ID_MAIN] < 0) {
176                 write_to_log = __write_to_log_null;
177         } else {
178                 write_to_log = __write_to_log_kernel;
179         }
180         if (log_fds[LOG_ID_RADIO] < 0)
181                 log_fds[LOG_ID_RADIO] = log_fds[LOG_ID_MAIN];
182         if (log_fds[LOG_ID_SYSTEM] < 0)
183                 log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
184         if (log_fds[LOG_ID_APPS] < 0)
185                 log_fds[LOG_ID_APPS] = log_fds[LOG_ID_MAIN];
186 #endif
187         pthread_mutex_unlock(&log_init_lock);
188 }
189
190 void __dlog_fatal_assert(int prio)
191 {
192 #ifdef FATAL_ON
193         assert(!(prio == DLOG_FATAL));
194 #endif
195 }
196
197 static int dlog_should_log(log_id_t log_id, const char* tag, int prio)
198 {
199         int should_log;
200
201 #ifndef TIZEN_DEBUG_ENABLE
202         if (prio <= DLOG_DEBUG)
203                 return DLOG_ERROR_INVALID_PARAMETER;
204 #endif
205         if (!tag)
206                 return DLOG_ERROR_INVALID_PARAMETER;
207
208         if (log_id < 0 || LOG_ID_MAX <= log_id)
209                 return DLOG_ERROR_INVALID_PARAMETER;
210
211         if (log_id != LOG_ID_APPS && !config.lc_plog)
212                 return DLOG_ERROR_NOT_PERMITTED;
213
214         if (config.lc_limiter) {
215                 should_log = __log_limiter_pass_log(tag, prio);
216
217                 if (!should_log) {
218                         return DLOG_ERROR_NOT_PERMITTED;
219                 } else if (should_log < 0) {
220                         write_to_log(log_id, prio, tag,
221                                      "Your log has been blocked due to limit of log lines per minute.");
222                         return DLOG_ERROR_NOT_PERMITTED;
223                 }
224         }
225
226         return DLOG_ERROR_NONE;
227 }
228
229 int __dlog_vprint(log_id_t log_id, int prio, const char *tag, const char *fmt, va_list ap)
230 {
231         int ret;
232         char buf[LOG_BUF_SIZE];
233
234         if (write_to_log == NULL)
235                 __dlog_init();
236
237         ret = dlog_should_log(log_id, tag, prio);
238
239         if (ret < 0)
240                 return ret;
241
242         vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
243         ret = write_to_log(log_id, prio, tag, buf);
244 #ifdef FATAL_ON
245         __dlog_fatal_assert(prio);
246 #endif
247         return ret;
248 }
249
250 int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...)
251 {
252         int ret;
253         va_list ap;
254         char buf[LOG_BUF_SIZE];
255
256         if (write_to_log == NULL)
257                 __dlog_init();
258
259         ret = dlog_should_log(log_id, tag, prio);
260
261         if (ret < 0)
262                 return ret;
263
264         va_start(ap, fmt);
265         vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
266         va_end(ap);
267
268         ret = write_to_log(log_id, prio, tag, buf);
269 #ifdef FATAL_ON
270         __dlog_fatal_assert(prio);
271 #endif
272         return ret;
273 }
274
275 int dlog_vprint(log_priority prio, const char *tag, const char *fmt, va_list ap)
276 {
277         char buf[LOG_BUF_SIZE];
278
279         if (write_to_log == NULL)
280                 __dlog_init();
281
282         vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
283
284         return write_to_log(LOG_ID_APPS, prio, tag, buf);
285 }
286
287 int dlog_print(log_priority prio, const char *tag, const char *fmt, ...)
288 {
289         va_list ap;
290         char buf[LOG_BUF_SIZE];
291
292         if (write_to_log == NULL)
293                 __dlog_init();
294
295         va_start(ap, fmt);
296         vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
297         va_end(ap);
298
299         return write_to_log(LOG_ID_APPS, prio, tag, buf);
300 }
301
302 void __attribute__((destructor)) __dlog_fini(void)
303 {
304         __log_limiter_destroy();
305 }