1 static const char version[] = "$Id: category.c,v 1.13 2013/09/29 17:37:04 valtri Exp $";
2
3 /*
4 * category.c
5 *
6 * Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
7 *
8 * See the COPYING file for the terms of usage and distribution.
9 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <stdlib.h>
15 #include <string.h>
16 #if defined(HAVE_ALLOCA_H)
17 #include <alloca.h>
18 #elif defined(HAVE_MALLOC_H)
19 #include <malloc.h>
20 #endif
21 #include <sd/sprintf.h>
22 #include <sd/malloc.h>
23 #include <sd/factory.h>
24 #include <log4c/appender.h>
25 #include <log4c/priority.h>
26 #include <log4c/logging_event.h>
27 #include <log4c/category.h>
28 #include <log4c/rc.h>
29 #include <sd/error.h>
30 #include <sd/sd_xplatform.h>
31
32 struct __log4c_category {
33 char* cat_name;
34 int cat_priority;
35 int cat_additive;
36 const log4c_category_t* cat_parent;
37 log4c_appender_t* cat_appender;
38 };
39
40 sd_factory_t* log4c_category_factory = NULL;
41
42 static const char LOG4C_CATEGORY_DEFAULT[] = "root";
43
44
45 /**
46 * @bug the root category name should be "" not "root". *
47 */
48
49 /*******************************************************************************/
log4c_category_get(const char * a_name)50 extern log4c_category_t* log4c_category_get(const char* a_name)
51 {
52 static const sd_factory_ops_t log4c_category_factory_ops = {
53 (void*) log4c_category_new,
54 (void*) log4c_category_delete,
55 (void*) log4c_category_print,
56 };
57
58 if (!log4c_category_factory) {
59 log4c_category_factory = sd_factory_new("log4c_category_factory",
60 &log4c_category_factory_ops);
61 }
62
63 return sd_factory_get(log4c_category_factory, a_name);
64 }
65
66 /*******************************************************************************/
log4c_category_list(log4c_category_t ** a_cats,int a_ncats)67 extern int log4c_category_list(log4c_category_t** a_cats, int a_ncats)
68 {
69 return sd_factory_list(log4c_category_factory, (void**) a_cats, a_ncats);
70 }
71
72 /*******************************************************************************/
73 static const char* dot_dirname(char* a_string);
74
log4c_category_new(const char * a_name)75 extern log4c_category_t* log4c_category_new(const char* a_name)
76 {
77 log4c_category_t* this;
78
79 if (!a_name)
80 return NULL;
81
82 this = sd_calloc(1, sizeof(log4c_category_t));
83 this->cat_name = sd_strdup(a_name);
84 this->cat_priority = LOG4C_PRIORITY_NOTSET;
85 this->cat_additive = 1;
86 this->cat_appender = NULL;
87 this->cat_parent = NULL;
88
89 /* skip root category because it has a NULL parent */
90 if (strcmp(LOG4C_CATEGORY_DEFAULT, a_name)) {
91 char* tmp = sd_strdup(this->cat_name);
92
93 this->cat_parent = log4c_category_get(dot_dirname(tmp));
94 free(tmp);
95 }
96 return this;
97 }
98
99 /*******************************************************************************/
log4c_category_delete(log4c_category_t * this)100 extern void log4c_category_delete(log4c_category_t* this)
101 {
102 if (!this)
103 return;
104
105 free(this->cat_name);
106 free(this);
107 }
108
109 /*******************************************************************************/
log4c_category_get_name(const log4c_category_t * this)110 extern const char* log4c_category_get_name(const log4c_category_t* this)
111 {
112 return (this ? this->cat_name : "(nil)");
113 }
114
115 /*******************************************************************************/
log4c_category_get_priority(const log4c_category_t * this)116 extern int log4c_category_get_priority(const log4c_category_t* this)
117 {
118 return (this ? this->cat_priority : LOG4C_PRIORITY_UNKNOWN);
119 }
120
121 /*******************************************************************************/
log4c_category_get_chainedpriority(const log4c_category_t * this)122 extern int log4c_category_get_chainedpriority(const log4c_category_t* this)
123 {
124 const log4c_category_t* cat = this;
125
126 if (!this)
127 return LOG4C_PRIORITY_UNKNOWN;
128
129 while (cat->cat_priority == LOG4C_PRIORITY_NOTSET && cat->cat_parent)
130 cat = cat->cat_parent;
131
132 return cat->cat_priority;
133 }
134
135 /*******************************************************************************/
log4c_category_get_appender(const log4c_category_t * this)136 extern const log4c_appender_t* log4c_category_get_appender(const log4c_category_t* this)
137 {
138 return (this ? this->cat_appender : NULL);
139 }
140
141 /*******************************************************************************/
log4c_category_get_additivity(const log4c_category_t * this)142 extern int log4c_category_get_additivity(const log4c_category_t* this)
143 {
144 return (this ? this->cat_additive : -1);
145 }
146
147 /*******************************************************************************/
log4c_category_set_priority(log4c_category_t * this,int a_priority)148 extern int log4c_category_set_priority(log4c_category_t* this, int a_priority)
149 {
150 int previous;
151
152 if (!this)
153 return LOG4C_PRIORITY_UNKNOWN;
154
155 previous = this->cat_priority;
156 this->cat_priority = a_priority;
157 return previous;
158 }
159
160 /**
161 * @todo need multiple appenders per category
162 */
163
164 /*******************************************************************************/
log4c_category_set_appender(log4c_category_t * this,log4c_appender_t * a_appender)165 extern const log4c_appender_t* log4c_category_set_appender(
166 log4c_category_t* this,
167 log4c_appender_t* a_appender)
168 {
169 log4c_appender_t* previous;
170
171 if (!this)
172 return NULL;
173
174 previous = this->cat_appender;
175 this->cat_appender = a_appender;
176 return previous;
177 }
178
179 /*******************************************************************************/
log4c_category_set_additivity(log4c_category_t * this,int a_additivity)180 extern int log4c_category_set_additivity(log4c_category_t* this, int a_additivity)
181 {
182 int previous;
183
184 if (!this)
185 return -1;
186
187 previous = this->cat_additive;
188 this->cat_additive = a_additivity;
189 return previous;
190 }
191
192 /*******************************************************************************/
log4c_category_print(const log4c_category_t * this,FILE * a_stream)193 extern void log4c_category_print(const log4c_category_t* this, FILE* a_stream)
194 {
195 if (!this)
196 return;
197
198 fprintf(a_stream, "{ name:'%s' priority:%s additive:%d appender:'%s' parent:'%s' }",
199 this->cat_name,
200 log4c_priority_to_string(this->cat_priority),
201 this->cat_additive,
202 log4c_appender_get_name(this->cat_appender),
203 log4c_category_get_name(this->cat_parent)
204 );
205 }
206
207 /*******************************************************************************/
__log4c_category_vlog(const log4c_category_t * this,const log4c_location_info_t * a_locinfo,int a_priority,const char * a_format,va_list a_args)208 extern void __log4c_category_vlog(const log4c_category_t* this,
209 const log4c_location_info_t* a_locinfo,
210 int a_priority,
211 const char* a_format,
212 va_list a_args)
213 {
214 char* message;
215 log4c_logging_event_t evt;
216 const log4c_category_t* cat;
217 int yes = 0;
218
219 if (!this)
220 return;
221
222 /* check if an appender is defined in the category hierarchy */
223 for (cat = this; cat; cat = cat->cat_parent) {
224 if (cat->cat_appender)
225 yes++;
226 }
227
228 if (!yes)
229 return;
230
231 log4c_reread();
232
233 /* when there is no limit on the buffer size, we use malloc() to
234 * give the user the possiblity to reallocate if necessary. When
235 * the buffer is limited in size, we use alloca() for more
236 * efficiency.
237 */
238 evt.evt_buffer.buf_maxsize = log4c_rc->config.bufsize;
239
240 if (!evt.evt_buffer.buf_maxsize) {
241 evt.evt_buffer.buf_size = LOG4C_BUFFER_SIZE_DEFAULT;
242 evt.evt_buffer.buf_data = sd_malloc(evt.evt_buffer.buf_size);
243 message = sd_vsprintf(a_format, a_args);
244 }
245 else {
246 size_t n;
247
248 evt.evt_buffer.buf_size = evt.evt_buffer.buf_maxsize;
249 evt.evt_buffer.buf_data = alloca(evt.evt_buffer.buf_size);
250 message = alloca(evt.evt_buffer.buf_size);
251
252 if ( (n = (size_t)vsnprintf(message, evt.evt_buffer.buf_size, a_format, a_args))
253 >= evt.evt_buffer.buf_size)
254 sd_error("truncating message of %d bytes (bufsize = %d)", n,
255 evt.evt_buffer.buf_size);
256 }
257
258 evt.evt_category = this->cat_name;
259 evt.evt_priority = a_priority;
260 evt.evt_msg = message;
261 evt.evt_loc = a_locinfo;
262 SD_GETTIMEOFDAY(&evt.evt_timestamp, NULL);
263
264 for (cat = this; cat; cat = cat->cat_parent) {
265 if (cat->cat_appender)
266 log4c_appender_append(cat->cat_appender, &evt);
267
268 if (!cat->cat_additive) break;
269 }
270
271 if (!evt.evt_buffer.buf_maxsize) {
272 free(message);
273 free(evt.evt_buffer.buf_data);
274 }
275 }
276
277 /*******************************************************************************/
dot_dirname(char * a_string)278 static const char* dot_dirname(char* a_string)
279 {
280 char* p;
281
282 if (!a_string)
283 return NULL;
284
285 if ( (p = strrchr(a_string, '.')) == NULL)
286 return LOG4C_CATEGORY_DEFAULT;
287
288 *p = '\0';
289 return a_string;
290 }
291
292