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