source: mainline/uspace/srv/logger/namespace.c@ dc5aa568

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dc5aa568 was 80d8885, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

Set levels for individual contexts

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * Copyright (c) 2012 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup logger
30 * @{
31 */
32#include <assert.h>
33#include <malloc.h>
34#include <str.h>
35#include <stdio.h>
36#include <errno.h>
37#include "logger.h"
38
39/** @file
40 * Logging namespaces.
41 */
42
43#define CONTEXT_SIZE 16
44
45typedef struct {
46 const char *name;
47 log_level_t level;
48} logging_context_t;
49
50struct logging_namespace {
51 fibril_mutex_t guard;
52 size_t writers_count;
53 fibril_condvar_t level_changed_cv;
54 FILE *logfile;
55 log_level_t level;
56 const char *name;
57
58 // FIXME: make dynamic
59 size_t context_count;
60 logging_context_t context[CONTEXT_SIZE];
61
62 link_t link;
63};
64
65static FIBRIL_MUTEX_INITIALIZE(namespace_list_guard);
66static LIST_INITIALIZE(namespace_list);
67
68static log_level_t namespace_get_actual_log_level(logging_namespace_t *namespace, sysarg_t context)
69{
70 fibril_mutex_lock(&namespace->guard);
71 if (context >= namespace->context_count) {
72 fibril_mutex_unlock(&namespace->guard);
73 fprintf(stderr, "Invalid context!\n");
74 return LVL_FATAL;
75 }
76 log_level_t level = namespace->context[context].level;
77 fibril_mutex_unlock(&namespace->guard);
78
79 if (level == LOG_LEVEL_USE_DEFAULT)
80 level = get_default_logging_level();
81
82 return level;
83}
84
85static logging_namespace_t *namespace_find_no_lock(const char *name)
86{
87 list_foreach(namespace_list, it) {
88 logging_namespace_t *namespace = list_get_instance(it, logging_namespace_t, link);
89 if (str_cmp(namespace->name, name) == 0) {
90 return namespace;
91 }
92 }
93
94 return NULL;
95}
96
97static logging_namespace_t *namespace_create_no_lock(const char *name)
98{
99 logging_namespace_t *existing = namespace_find_no_lock(name);
100 if (existing != NULL) {
101 return NULL;
102 }
103
104 logging_namespace_t *namespace = malloc(sizeof(logging_namespace_t));
105 if (namespace == NULL) {
106 return NULL;
107 }
108
109 namespace->name = str_dup(name);
110 if (namespace->name == NULL) {
111 free(namespace);
112 return NULL;
113 }
114
115 char *logfilename;
116 int rc = asprintf(&logfilename, "/log/%s", name);
117 if (rc < 0) {
118 free(namespace->name);
119 free(namespace);
120 return NULL;
121 }
122 namespace->logfile = fopen(logfilename, "a");
123 free(logfilename);
124 if (namespace->logfile == NULL) {
125 free(namespace->name);
126 free(namespace);
127 return NULL;
128 }
129
130 namespace->level = LOG_LEVEL_USE_DEFAULT;
131
132 namespace->context_count = 1;
133 namespace->context[0].name = "";
134 namespace->context[0].level = LOG_LEVEL_USE_DEFAULT;
135
136 fibril_mutex_initialize(&namespace->guard);
137 fibril_condvar_initialize(&namespace->level_changed_cv);
138 namespace->writers_count = 0;
139 link_initialize(&namespace->link);
140
141 list_append(&namespace->link, &namespace_list);
142
143 return namespace;
144}
145
146
147logging_namespace_t *namespace_create(const char *name)
148{
149 fibril_mutex_lock(&namespace_list_guard);
150 logging_namespace_t *result = namespace_create_no_lock(name);
151 fibril_mutex_unlock(&namespace_list_guard);
152 return result;
153}
154
155const char *namespace_get_name(logging_namespace_t *namespace)
156{
157 assert(namespace);
158 return namespace->name;
159}
160
161static void namespace_destroy_careful(logging_namespace_t *namespace)
162{
163 assert(namespace);
164 fibril_mutex_lock(&namespace_list_guard);
165
166 fibril_mutex_lock(&namespace->guard);
167 if (namespace->writers_count > 0) {
168 fibril_mutex_unlock(&namespace->guard);
169 fibril_mutex_unlock(&namespace_list_guard);
170 return;
171 }
172
173 list_remove(&namespace->link);
174
175 fibril_mutex_unlock(&namespace->guard);
176 fibril_mutex_unlock(&namespace_list_guard);
177
178 // TODO - destroy pending messages
179 fclose(namespace->logfile);
180 free(namespace->name);
181 free(namespace);
182}
183
184void namespace_destroy(logging_namespace_t *namespace)
185{
186 namespace_destroy_careful(namespace);
187}
188
189logging_namespace_t *namespace_writer_attach(const char *name)
190{
191 logging_namespace_t *namespace = NULL;
192
193 fibril_mutex_lock(&namespace_list_guard);
194
195 namespace = namespace_find_no_lock(name);
196
197 if (namespace == NULL) {
198 namespace = namespace_create_no_lock(name);
199 }
200
201 fibril_mutex_lock(&namespace->guard);
202 namespace->writers_count++;
203 fibril_mutex_unlock(&namespace->guard);
204
205 fibril_mutex_unlock(&namespace_list_guard);
206
207 return namespace;
208}
209
210void namespace_writer_detach(logging_namespace_t *namespace)
211{
212 fibril_mutex_lock(&namespace->guard);
213 assert(namespace->writers_count > 0);
214 namespace->writers_count--;
215 fibril_mutex_unlock(&namespace->guard);
216
217 namespace_destroy_careful(namespace);
218}
219
220int namespace_change_level(logging_namespace_t *namespace, log_level_t level)
221{
222 if (level >= LVL_LIMIT)
223 return ERANGE;
224
225 fibril_mutex_lock(&namespace->guard);
226 namespace->level = level;
227 for (size_t i = 0; i < namespace->context_count; i++) {
228 namespace->context[i].level = level;
229 }
230 fibril_condvar_broadcast(&namespace->level_changed_cv);
231 fibril_mutex_unlock(&namespace->guard);
232
233 return EOK;
234}
235
236
237bool namespace_has_reader(logging_namespace_t *namespace, sysarg_t context, log_level_t level)
238{
239 return level <= namespace_get_actual_log_level(namespace, context);
240}
241
242int namespace_create_context(logging_namespace_t *namespace, const char *name)
243{
244 int rc;
245 fibril_mutex_lock(&namespace->guard);
246 if (namespace->context_count >= CONTEXT_SIZE) {
247 rc = ELIMIT;
248 goto leave;
249 }
250
251 namespace->context[namespace->context_count].level
252 = LOG_LEVEL_USE_DEFAULT;
253 namespace->context[namespace->context_count].name
254 = str_dup(name);
255 if (namespace->context[namespace->context_count].name == NULL) {
256 rc = ENOMEM;
257 goto leave;
258 }
259 rc = (int) namespace->context_count;
260 namespace->context_count++;
261
262
263leave:
264 fibril_mutex_unlock(&namespace->guard);
265 return rc;
266}
267
268int namespace_change_context_level(logging_namespace_t *namespace, const char *context, log_level_t new_level)
269{
270 if (new_level >= LVL_LIMIT)
271 return ERANGE;
272
273 int rc;
274 fibril_mutex_lock(&namespace->guard);
275 for (size_t i = 0; i < namespace->context_count; i++) {
276 if (str_cmp(namespace->context[i].name, context) == 0) {
277 namespace->context[i].level = new_level;
278 rc = EOK;
279 fibril_condvar_broadcast(&namespace->level_changed_cv);
280 goto leave;
281 }
282 }
283 rc = ENOENT;
284
285leave:
286 fibril_mutex_unlock(&namespace->guard);
287 return rc;
288}
289
290void namespace_wait_for_reader_change(logging_namespace_t *namespace, bool *has_reader_now)
291{
292 fibril_mutex_lock(&namespace->guard);
293 // FIXME: properly watch for state change
294 fibril_condvar_wait(&namespace->level_changed_cv, &namespace->guard);
295 *has_reader_now = true;
296 fibril_mutex_unlock(&namespace->guard);
297}
298
299
300void namespace_add_message(logging_namespace_t *namespace, const char *message, sysarg_t context, log_level_t level)
301{
302 if (level <= namespace_get_actual_log_level(namespace, context)) {
303 const char *level_name = log_level_str(level);
304 if (context == 0) {
305 printf("[%s %s]: %s\n",
306 namespace->name, level_name, message);
307 fprintf(namespace->logfile, "%s: %s\n",
308 level_name, message);
309 } else {
310 const char *context_name = namespace->context[context].name;
311 printf("[%s/%s %s]: %s\n",
312 namespace->name, context_name, level_name, message);
313 fprintf(namespace->logfile, "[%s] %s: %s\n",
314 context_name, level_name, message);
315 }
316 fflush(namespace->logfile);
317 fflush(stdout);
318 }
319}
320
321
322/**
323 * @}
324 */
Note: See TracBrowser for help on using the repository browser.