libdlog: isolate limiter creation
[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 static void __configure_limiter(struct log_config *config)
71 {
72         assert(config);
73
74         if (!limiter)
75                 return;
76
77         limiter = __log_limiter_create(config);
78 }
79
80 static int __configure_backend(struct log_config *config)
81 {
82         assert(config);
83
84         const char *const backend = log_config_get(config, "backend");
85         if (!backend)
86                 return 0;
87
88         if (!strcmp(backend, "pipe"))
89                 __dlog_init_pipe();
90         else if (!strcmp(backend, "logger"))
91                 __dlog_init_android();
92         else
93                 return 0;
94
95         return 1;
96 }
97
98 static void __configure_parameters(struct log_config *config)
99 {
100         assert(config);
101
102         plog = log_config_get_int(config, "plog", DEFAULT_CONFIG_PLOG);
103         debugmode = log_config_get_int(config, "debugmode", DEFAULT_CONFIG_DEBUGMODE);
104         fatal_assert = access(DEBUGMODE_FILE, F_OK) != -1;
105         limiter = log_config_get_int(config, "limiter", DEFAULT_CONFIG_LIMITER);
106 }
107
108 /**
109  * @brief Configure the library
110  * @details Reads relevant config values
111  */
112 static void __configure(void)
113 {
114         struct log_config config;
115
116         if (log_config_read(&config) < 0)
117                 goto failure;
118
119         __configure_parameters(&config);
120
121         if (!__configure_backend(&config))
122                 goto failure;
123
124         __configure_limiter(&config);
125
126         log_config_free(&config);
127         return;
128
129 failure:
130         log_config_free(&config); // LCOV_EXCL_LINE
131         return;
132 }
133
134 /**
135  * @brief DLog init
136  * @details Initializes the library
137  */
138 static inline void __dlog_init(void)
139 {
140         static int is_initialized = 0;
141
142         if (is_initialized)
143                 return;
144
145         pthread_mutex_lock(&log_init_lock);
146
147         if (!is_initialized) {
148                 __configure();
149                 is_initialized = 1;
150         }
151
152         pthread_mutex_unlock(&log_init_lock);
153 }
154
155 /**
156  * @brief Fatal assertion
157  * @details Conditionally crash the sucka who sent the log
158  * @param[in] prio Priority of the log
159  */
160 static void __dlog_fatal_assert(int prio)
161 {
162         assert(!fatal_assert || (prio != DLOG_FATAL));
163 }
164
165 /**
166  * @brief Check log validity
167  * @details Checks whether the log is valid and eligible for printing
168  * @param[in] log_id The target buffer ID
169  * @param[in] prio The log's priority
170  * @param[in] tag The log's tag
171  * @return 0 on success, else an error code.
172  * @retval DLOG_ERROR_INVALID_PARAMETER Invalid parameter
173  * @retval DLOG_ERROR_NOT_PERMITTED Not permitted
174  */
175 static int dlog_should_log(log_id_t log_id, int prio, const char *tag)
176 {
177         if (!debugmode && prio <= DLOG_DEBUG)
178                 return DLOG_ERROR_INVALID_PARAMETER;
179
180         if (!tag)
181                 return DLOG_ERROR_INVALID_PARAMETER;
182
183         if (log_id == LOG_ID_INVALID || LOG_ID_MAX <= log_id)
184                 return DLOG_ERROR_INVALID_PARAMETER;
185
186         if (log_id != LOG_ID_APPS && !plog)
187                 return DLOG_ERROR_NOT_PERMITTED;
188
189         if (limiter) {
190                 // LCOV_EXCL_START : disabled feature (limiter)
191                 int should_log = __log_limiter_pass_log(tag, prio);
192
193                 if (!should_log) {
194                         return DLOG_ERROR_NOT_PERMITTED;
195                 } else if (should_log < 0) {
196                         write_to_log(log_id, prio, tag,
197                                         "Your log has been blocked due to limit of log lines per minute.");
198                         return DLOG_ERROR_NOT_PERMITTED;
199                 }
200                 // LCOV_EXCL_STOP
201         }
202
203         return DLOG_ERROR_NONE;
204 }
205
206 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)
207 {
208         char buf[LOG_MAX_PAYLOAD_SIZE];
209
210         __dlog_init();
211
212         int ret = check_should_log ? dlog_should_log(log_id, prio, tag) : 0;
213         if (ret < 0)
214                 return ret;
215
216         vsnprintf(buf, sizeof buf, fmt, ap);
217
218         return write_to_log(log_id, prio, tag, buf);
219 }
220
221 /**
222  * @brief Print log
223  * @details Print a log line
224  * @param[in] log_id The target buffer ID
225  * @param[in] prio Priority
226  * @param[in] tag tag
227  * @param[in] fmt Format (same as printf)
228  * @param[in] ap Argument list
229  * @return Bytes written, or negative error
230  */
231 int __dlog_vprint(log_id_t log_id, int prio, const char *tag, const char *fmt, va_list ap)
232 {
233         int ret = __write_to_log(log_id, prio, tag, fmt, ap, true);
234         __dlog_fatal_assert(prio);
235
236         return ret;
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  * @return Bytes written, or negative error
247  */
248 int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...)
249 {
250         va_list ap;
251
252         va_start(ap, fmt);
253         int ret = __dlog_vprint(log_id, prio, tag, fmt, ap);
254         va_end(ap);
255
256         return ret;
257 }
258
259 int dlog_vprint(log_priority prio, const char *tag, const char *fmt, va_list ap)
260 {
261         return __write_to_log(LOG_ID_APPS, prio, tag, fmt, ap, false);
262 }
263
264 int dlog_print(log_priority prio, const char *tag, const char *fmt, ...)
265 {
266         va_list ap;
267
268         va_start(ap, fmt);
269         int ret = dlog_vprint(prio, tag, fmt, ap);
270         va_end(ap);
271
272         return ret;
273 }
274
275 /**
276  * @brief Finalize DLog
277  * @details Finalizes and deallocates the library
278  */
279 void __attribute__((destructor)) __dlog_fini(void)
280 {
281         __log_limiter_destroy();
282 }