Merge "Rename dynamic filters to dynamic config" into tizen
[platform/core/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 <pthread.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23
24 #include <dynamic_config.h>
25 #include <logcommon.h>
26 #include "loglimiter.h"
27 #include "logconfig.h"
28 #include <assert.h>
29 #include <unistd.h>
30
31 #define DEFAULT_CONFIG_LIMITER 0
32 #define DEFAULT_CONFIG_PLOG 1
33 #define DEFAULT_CONFIG_DEBUGMODE 0
34 #define DEFAULT_CONFIG_LIMITER_APPLY_TO_ALL_BUFFERS 0
35
36 static int __write_to_log_null(log_id_t, log_priority, const char *, const char *);
37
38 /**
39  * @brief Points to a function which writes a log message
40  * @details The function pointed to depends on the backend used
41  * @param[in] log_id ID of the buffer to log to. Belongs to (LOG_ID_INVALID, LOG_ID_MAX) non-inclusive
42  * @param[in] prio Priority of the message.
43  * @param[in] tag The message tag, identifies the sender.
44  * @param[in] msg The contents of the message.
45  * @return Returns the number of bytes written on success and a negative error value on error.
46  * @see __dlog_init_backend
47  */
48 int (*write_to_log)(log_id_t log_id, log_priority prio, const char *tag, const char *msg) = __write_to_log_null;
49 pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
50 extern void __dlog_init_pipe();
51 extern void __dlog_init_android();
52
53 static int limiter;
54 static int plog;
55 static int debugmode;
56 static int fatal_assert;
57 static int limiter_apply_to_all_buffers;
58
59 /**
60  * @brief Null handler
61  * @details Ignores a log
62  * @param[in] log_id ID of the buffer to log to. Belongs to (LOG_ID_INVALID, LOG_ID_MAX) non-inclusive
63  * @param[in] prio Priority of the message.
64  * @param[in] tag The message tag, identifies the sender.
65  * @param[in] msg The contents of the message.
66  * @return DLOG_ERROR_NOT_PERMITTED
67  */
68 static int __write_to_log_null(log_id_t log_id, log_priority prio, const char *tag, const char *msg)// LCOV_EXCL_LINE
69 {
70         return DLOG_ERROR_NOT_PERMITTED; // LCOV_EXCL_LINE
71 }
72
73 static void __configure_limiter(struct log_config *config)
74 {
75         assert(config);
76
77         if (!limiter)
78                 return;
79
80         __dynamic_config_create(config);
81         limiter = __log_limiter_create(config);
82
83         if (!limiter)
84                 __dynamic_config_destroy(); // LCOV_EXCL_LINE
85 }
86
87 static int __configure_backend(struct log_config *config)
88 {
89         assert(config);
90
91         const char *const backend = log_config_get(config, "backend");
92         if (!backend)
93                 return 0;
94
95         if (!strcmp(backend, "pipe"))
96                 __dlog_init_pipe();
97         else if (!strcmp(backend, "logger"))
98                 __dlog_init_android();
99         else
100                 return 0;
101
102         return 1;
103 }
104
105 static void __configure_parameters(struct log_config *config)
106 {
107         assert(config);
108
109         plog = log_config_get_int(config, "plog", DEFAULT_CONFIG_PLOG);
110         debugmode = log_config_get_int(config, "debugmode", DEFAULT_CONFIG_DEBUGMODE);
111         fatal_assert = access(DEBUGMODE_FILE, F_OK) != -1;
112         limiter = log_config_get_int(config, "limiter", DEFAULT_CONFIG_LIMITER);
113         limiter_apply_to_all_buffers = log_config_get_int(config,
114                                                                         "limiter_apply_to_all_buffers",
115                                                                         DEFAULT_CONFIG_LIMITER_APPLY_TO_ALL_BUFFERS);
116 }
117
118 /**
119  * @brief Configure the library
120  * @details Reads relevant config values
121  */
122 static void __configure(void)
123 {
124         struct log_config config;
125
126         if (log_config_read(&config) < 0)
127                 goto failure;
128
129         __configure_parameters(&config);
130
131         if (!__configure_backend(&config))
132                 goto failure;
133
134         __configure_limiter(&config);
135
136         log_config_free(&config);
137         return;
138
139 failure:
140         log_config_free(&config); // LCOV_EXCL_LINE
141         return;
142 }
143
144 /**
145  * @brief DLog init
146  * @details Initializes the library
147  */
148 static inline void __dlog_init(void)
149 {
150         static int is_initialized = 0;
151
152         if (is_initialized)
153                 return;
154
155         pthread_mutex_lock(&log_init_lock);
156
157         if (!is_initialized) {
158                 __configure();
159                 is_initialized = 1;
160         }
161
162         pthread_mutex_unlock(&log_init_lock);
163 }
164
165 /**
166  * @brief Fatal assertion
167  * @details Conditionally crash the sucka who sent the log
168  * @param[in] prio Priority of the log
169  */
170 static void __dlog_fatal_assert(int prio)
171 {
172         assert(!fatal_assert || (prio != DLOG_FATAL));
173 }
174
175 /**
176  * @brief Check log validity
177  * @details Checks whether the log is valid and eligible for printing
178  * @param[in] log_id The target buffer ID
179  * @param[in] prio The log's priority
180  * @param[in] tag The log's tag
181  * @return 0 on success, else an error code.
182  * @retval DLOG_ERROR_INVALID_PARAMETER Invalid parameter
183  * @retval DLOG_ERROR_NOT_PERMITTED Not permitted
184  */
185 static int dlog_should_log(log_id_t log_id, int prio, const char *tag)
186 {
187         if (!debugmode && prio <= DLOG_DEBUG)
188                 return DLOG_ERROR_INVALID_PARAMETER;
189
190         if (!tag)
191                 return DLOG_ERROR_INVALID_PARAMETER;
192
193         if (log_id == LOG_ID_INVALID || LOG_ID_MAX <= log_id)
194                 return DLOG_ERROR_INVALID_PARAMETER;
195
196         if (log_id != LOG_ID_APPS && !plog)
197                 return DLOG_ERROR_NOT_PERMITTED;
198
199         if (limiter) {
200                 __dynamic_config_update();
201
202                 // LCOV_EXCL_START : disabled feature (limiter)
203                 pthread_mutex_lock(&log_init_lock);
204                 int should_log = __log_limiter_pass_log(tag, prio);
205                 pthread_mutex_unlock(&log_init_lock);
206
207                 if (!should_log) {
208                         return DLOG_ERROR_NOT_PERMITTED;
209                 } else if (should_log < 0) {
210                         write_to_log(log_id, prio, tag,
211                                         "Your log has been blocked due to limit of log lines per minute.");
212                         return DLOG_ERROR_NOT_PERMITTED;
213                 }
214                 // LCOV_EXCL_STOP
215         }
216
217         return DLOG_ERROR_NONE;
218 }
219
220 static int __write_to_log(log_id_t log_id, int prio, const char *tag, const char *fmt, va_list ap, bool check_should_log)
221 {
222         char buf[LOG_MAX_PAYLOAD_SIZE];
223
224         __dlog_init();
225
226         /* if limiter_apply_to_all_buffers config variable is set to 1,
227          * check_should_log value does not matter and the entry is always
228          * tested against all conditions, i.e. limiter rules
229          */
230         int ret = (limiter_apply_to_all_buffers ? true : check_should_log) ? dlog_should_log(log_id, prio, tag) : 0;
231         if (ret < 0)
232                 return ret;
233
234         vsnprintf(buf, sizeof buf, fmt, ap);
235
236         return write_to_log(log_id, prio, tag, buf);
237 }
238
239 /**
240  * @brief Print log
241  * @details Print a log line
242  * @param[in] log_id The target buffer ID
243  * @param[in] prio Priority
244  * @param[in] tag tag
245  * @param[in] fmt Format (same as printf)
246  * @param[in] ap Argument list
247  * @return Bytes written, or negative error
248  */
249 int __dlog_vprint(log_id_t log_id, int prio, const char *tag, const char *fmt, va_list ap)
250 {
251         int ret = __write_to_log(log_id, prio, tag, fmt, ap, true);
252         __dlog_fatal_assert(prio);
253
254         return ret;
255 }
256
257 /**
258  * @brief Print log
259  * @details Print a log line
260  * @param[in] log_id The target buffer ID
261  * @param[in] prio Priority
262  * @param[in] tag tag
263  * @param[in] fmt Format (same as printf)
264  * @return Bytes written, or negative error
265  */
266 int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...)
267 {
268         va_list ap;
269
270         va_start(ap, fmt);
271         int ret = __dlog_vprint(log_id, prio, tag, fmt, ap);
272         va_end(ap);
273
274         return ret;
275 }
276
277 int dlog_vprint(log_priority prio, const char *tag, const char *fmt, va_list ap)
278 {
279         return __write_to_log(LOG_ID_APPS, prio, tag, fmt, ap, false);
280 }
281
282 int dlog_print(log_priority prio, const char *tag, const char *fmt, ...)
283 {
284         va_list ap;
285
286         va_start(ap, fmt);
287         int ret = dlog_vprint(prio, tag, fmt, ap);
288         va_end(ap);
289
290         return ret;
291 }
292
293 /**
294  * @brief Finalize DLog
295  * @details Finalizes and deallocates the library
296  * @notes Assumes it has exclusive thread access,
297  *        i.e. no other library function can run in parallel
298  */
299 void __attribute__((destructor)) __dlog_fini(void)
300 {
301         __log_limiter_destroy();
302         __dynamic_config_destroy();
303 }