iotivity 0.9.0
[platform/upstream/iotivity.git] / service / protocol-plugin / lib / cpluff / libcpluff / logging.c
1 /*-------------------------------------------------------------------------
2  * C-Pluff, a plug-in framework for C
3  * Copyright 2007 Johannes Lehtinen
4  * 
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *-----------------------------------------------------------------------*/
23
24 /** @file
25  * Logging functions
26  */ 
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <assert.h>
33 #include "cpluff.h"
34 #include "defines.h"
35 #include "util.h"
36 #include "internal.h"
37
38
39 /* ------------------------------------------------------------------------
40  * Data types
41  * ----------------------------------------------------------------------*/
42
43 /// Contains information about installed loggers
44 typedef struct logger_t {
45         
46         /// Pointer to logger
47         cp_logger_func_t logger;
48         
49         /// Pointer to registering plug-in or NULL for the main program
50         cp_plugin_t *plugin;
51         
52         /// User data pointer
53         void *user_data;
54         
55         /// Minimum severity
56         cp_log_severity_t min_severity;
57         
58         /// Selected environment or NULL
59         cp_plugin_env_t *env_selection;
60 } logger_t;
61
62
63 /* ------------------------------------------------------------------------
64  * Function definitions
65  * ----------------------------------------------------------------------*/
66
67 /**
68  * Updates the context logging limits. The caller must have locked the
69  * context.
70  */
71 static void update_logging_limits(cp_context_t *context) {
72         lnode_t *node;
73         int nms = CP_LOG_NONE;
74         
75         node = list_first(context->env->loggers);
76         while (node != NULL) {
77                 logger_t *lh = lnode_get(node);
78                 if (lh->min_severity < nms) {
79                         nms = lh->min_severity;
80                 }
81                 node = list_next(context->env->loggers, node);
82         }
83         context->env->log_min_severity = nms;
84 }
85
86 static int comp_logger(const void *p1, const void *p2) {
87         const logger_t *l1 = p1;
88         const logger_t *l2 = p2;
89         return l1->logger != l2->logger;
90 }
91
92 CP_C_API cp_status_t cp_register_logger(cp_context_t *context, cp_logger_func_t logger, void *user_data, cp_log_severity_t min_severity) {
93         logger_t l;
94         logger_t *lh = NULL;
95         lnode_t *node = NULL;
96         cp_status_t status = CP_OK;
97
98         CHECK_NOT_NULL(context);
99         CHECK_NOT_NULL(logger);
100         cpi_lock_context(context);
101         cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
102         do {
103         
104                 // Check if logger already exists and allocate new holder if necessary
105                 l.logger = logger;
106                 if ((node = list_find(context->env->loggers, &l, comp_logger)) == NULL) {
107                         lh = malloc(sizeof(logger_t));
108                         node = lnode_create(lh);
109                         if (lh == NULL || node == NULL) {
110                                 status = CP_ERR_RESOURCE;
111                                 break;
112                         }
113                         lh->logger = logger;
114                         lh->plugin = context->plugin;
115                         list_append(context->env->loggers, node);
116                 } else {
117                         lh = lnode_get(node);
118                 }
119                 
120                 // Initialize or update the logger holder
121                 lh->user_data = user_data;
122                 lh->min_severity = min_severity;
123                 
124                 // Update global limits
125                 update_logging_limits(context);
126                 
127         } while (0);
128
129         // Report error
130         if (status == CP_ERR_RESOURCE) {
131                 cpi_error(context, N_("Logger could not be registered due to insufficient memory."));           
132         } else if (cpi_is_logged(context, CP_LOG_DEBUG)) {
133                 char owner[64];
134                 /* TRANSLATORS: %s is the context owner */
135                 cpi_debugf(context, N_("%s registered a logger."), cpi_context_owner(context, owner, sizeof(owner)));
136         }
137         cpi_unlock_context(context);
138
139         // Release resources on error
140         if (status != CP_OK) {
141                 if (node != NULL) {
142                         lnode_destroy(node);
143                 }
144                 if (lh != NULL) {
145                         free(lh);
146                 }
147         }
148
149         return status;
150 }
151
152 CP_C_API void cp_unregister_logger(cp_context_t *context, cp_logger_func_t logger) {
153         logger_t l;
154         lnode_t *node;
155         
156         CHECK_NOT_NULL(context);
157         CHECK_NOT_NULL(logger);
158         cpi_lock_context(context);
159         cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
160         
161         l.logger = logger;
162         if ((node = list_find(context->env->loggers, &l, comp_logger)) != NULL) {
163                 logger_t *lh = lnode_get(node);
164                 list_delete(context->env->loggers, node);
165                 lnode_destroy(node);
166                 free(lh);
167                 update_logging_limits(context);
168         }
169         if (cpi_is_logged(context, CP_LOG_DEBUG)) {
170                 char owner[64];
171                 /* TRANSLATORS: %s is the context owner */
172                 cpi_debugf(context, N_("%s unregistered a logger."), cpi_context_owner(context, owner, sizeof(owner)));
173         }
174         cpi_unlock_context(context);
175 }
176
177 static void do_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
178         lnode_t *node;
179         const char *apid = NULL;
180
181         assert(cpi_is_context_locked(context)); 
182         if (context->env->in_logger_invocation) {
183                 cpi_fatalf(_("Encountered a recursive logging request within a logger invocation."));
184         }
185         if (context->plugin != NULL) {
186                 apid = context->plugin->plugin->identifier;
187         }
188         context->env->in_logger_invocation++;
189         node = list_first(context->env->loggers);
190         while (node != NULL) {
191                 logger_t *lh = lnode_get(node);
192                 if (severity >= lh->min_severity) {
193                         lh->logger(severity, msg, apid, lh->user_data);
194                 }
195                 node = list_next(context->env->loggers, node);
196         }
197         context->env->in_logger_invocation--;
198 }
199
200 CP_HIDDEN void cpi_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
201         assert(context != NULL);
202         assert(msg != NULL);
203         assert(severity >= CP_LOG_DEBUG && severity <= CP_LOG_ERROR);
204         do_log(context, severity, _(msg));
205 }
206
207 CP_HIDDEN void cpi_logf(cp_context_t *context, cp_log_severity_t severity, const char *msg, ...) {
208         char buffer[256];
209         va_list va;
210         
211         assert(context != NULL);
212         assert(msg != NULL);
213         assert(severity >= CP_LOG_DEBUG && severity <= CP_LOG_ERROR);
214                 
215         va_start(va, msg);
216         vsnprintf(buffer, sizeof(buffer), _(msg), va);
217         va_end(va);
218         strcpy(buffer + sizeof(buffer)/sizeof(char) - 4, "...");
219         do_log(context, severity, buffer);
220 }
221
222 static void process_unregister_logger(list_t *list, lnode_t *node, void *plugin) {
223         logger_t *lh = lnode_get(node);
224         if (plugin == NULL || lh->plugin == plugin) {
225                 list_delete(list, node);
226                 lnode_destroy(node);
227                 free(lh);
228         }
229 }
230
231 CP_HIDDEN void cpi_unregister_loggers(list_t *loggers, cp_plugin_t *plugin) {
232         list_process(loggers, plugin, process_unregister_logger);
233 }
234
235 CP_C_API void cp_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
236         CHECK_NOT_NULL(context);
237         CHECK_NOT_NULL(msg);
238         cpi_lock_context(context);
239         cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
240         if (severity < CP_LOG_DEBUG || severity > CP_LOG_ERROR) {
241                 cpi_fatalf(_("Illegal severity value in call to %s."), __func__);
242         }
243         if (cpi_is_logged(context, severity)) {
244                 do_log(context, severity, msg);
245         }
246         cpi_unlock_context(context);
247 }
248
249 CP_C_API int cp_is_logged(cp_context_t *context, cp_log_severity_t severity) {
250         int is_logged;
251         
252         CHECK_NOT_NULL(context);
253         cpi_lock_context(context);
254         cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
255         is_logged = cpi_is_logged(context, severity);
256         cpi_unlock_context(context);
257         return is_logged;
258 }