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