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