source: mainline/uspace/srv/logger/namespace.c@ 793cce15

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

Add logging contexts

  • Property mode set to 100644
File size: 7.7 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 return LVL_FATAL;
74 }
75 log_level_t level = namespace->context[context].level;
76 fibril_mutex_unlock(&namespace->guard);
77
78 if (level == LOG_LEVEL_USE_DEFAULT)
79 level = get_default_logging_level();
80
81 return level;
82}
83
84static logging_namespace_t *namespace_find_no_lock(const char *name)
85{
86 list_foreach(namespace_list, it) {
87 logging_namespace_t *namespace = list_get_instance(it, logging_namespace_t, link);
88 if (str_cmp(namespace->name, name) == 0) {
89 return namespace;
90 }
91 }
92
93 return NULL;
94}
95
96static logging_namespace_t *namespace_create_no_lock(const char *name)
97{
98 logging_namespace_t *existing = namespace_find_no_lock(name);
99 if (existing != NULL) {
100 return NULL;
101 }
102
103 logging_namespace_t *namespace = malloc(sizeof(logging_namespace_t));
104 if (namespace == NULL) {
105 return NULL;
106 }
107
108 namespace->name = str_dup(name);
109 if (namespace->name == NULL) {
110 free(namespace);
111 return NULL;
112 }
113
114 char *logfilename;
115 int rc = asprintf(&logfilename, "/log/%s", name);
116 if (rc < 0) {
117 free(namespace->name);
118 free(namespace);
119 return NULL;
120 }
121 namespace->logfile = fopen(logfilename, "a");
122 free(logfilename);
123 if (namespace->logfile == NULL) {
124 free(namespace->name);
125 free(namespace);
126 return NULL;
127 }
128
129 namespace->level = LOG_LEVEL_USE_DEFAULT;
130
131 namespace->context_count = 1;
132 namespace->context[0].name = "";
133 namespace->context[0].level = LOG_LEVEL_USE_DEFAULT;
134
135 fibril_mutex_initialize(&namespace->guard);
136 fibril_condvar_initialize(&namespace->level_changed_cv);
137 namespace->writers_count = 0;
138 link_initialize(&namespace->link);
139
140 list_append(&namespace->link, &namespace_list);
141
142 return namespace;
143}
144
145
146logging_namespace_t *namespace_create(const char *name)
147{
148 fibril_mutex_lock(&namespace_list_guard);
149 logging_namespace_t *result = namespace_create_no_lock(name);
150 fibril_mutex_unlock(&namespace_list_guard);
151 return result;
152}
153
154const char *namespace_get_name(logging_namespace_t *namespace)
155{
156 assert(namespace);
157 return namespace->name;
158}
159
160static void namespace_destroy_careful(logging_namespace_t *namespace)
161{
162 assert(namespace);
163 fibril_mutex_lock(&namespace_list_guard);
164
165 fibril_mutex_lock(&namespace->guard);
166 if (namespace->writers_count > 0) {
167 fibril_mutex_unlock(&namespace->guard);
168 fibril_mutex_unlock(&namespace_list_guard);
169 return;
170 }
171
172 list_remove(&namespace->link);
173
174 fibril_mutex_unlock(&namespace->guard);
175 fibril_mutex_unlock(&namespace_list_guard);
176
177 // TODO - destroy pending messages
178 fclose(namespace->logfile);
179 free(namespace->name);
180 free(namespace);
181}
182
183void namespace_destroy(logging_namespace_t *namespace)
184{
185 namespace_destroy_careful(namespace);
186}
187
188logging_namespace_t *namespace_writer_attach(const char *name)
189{
190 logging_namespace_t *namespace = NULL;
191
192 fibril_mutex_lock(&namespace_list_guard);
193
194 namespace = namespace_find_no_lock(name);
195
196 if (namespace == NULL) {
197 namespace = namespace_create_no_lock(name);
198 }
199
200 fibril_mutex_lock(&namespace->guard);
201 namespace->writers_count++;
202 fibril_mutex_unlock(&namespace->guard);
203
204 fibril_mutex_unlock(&namespace_list_guard);
205
206 return namespace;
207}
208
209void namespace_writer_detach(logging_namespace_t *namespace)
210{
211 fibril_mutex_lock(&namespace->guard);
212 assert(namespace->writers_count > 0);
213 namespace->writers_count--;
214 fibril_mutex_unlock(&namespace->guard);
215
216 namespace_destroy_careful(namespace);
217}
218
219int namespace_change_level(logging_namespace_t *namespace, log_level_t level)
220{
221 if (level >= LVL_LIMIT)
222 return ERANGE;
223
224 fibril_mutex_lock(&namespace->guard);
225 namespace->level = level;
226 for (size_t i = 0; i < namespace->context_count; i++) {
227 namespace->context[i].level = level;
228 }
229 fibril_condvar_broadcast(&namespace->level_changed_cv);
230 fibril_mutex_unlock(&namespace->guard);
231
232 return EOK;
233}
234
235
236bool namespace_has_reader(logging_namespace_t *namespace, sysarg_t context, log_level_t level)
237{
238 return level <= namespace_get_actual_log_level(namespace, context);
239}
240
241int namespace_create_context(logging_namespace_t *namespace, const char *name)
242{
243 int rc;
244 fibril_mutex_lock(&namespace->guard);
245 if (namespace->context_count >= CONTEXT_SIZE) {
246 rc = ELIMIT;
247 goto leave;
248 }
249
250 namespace->context[namespace->context_count].level
251 = LOG_LEVEL_USE_DEFAULT;
252 namespace->context[namespace->context_count].name
253 = str_dup(name);
254 if (namespace->context[namespace->context_count].name == NULL) {
255 rc = ENOMEM;
256 goto leave;
257 }
258 rc = (int) namespace->context_count;
259 namespace->context_count++;
260
261
262leave:
263 fibril_mutex_unlock(&namespace->guard);
264 return rc;
265}
266
267void namespace_wait_for_reader_change(logging_namespace_t *namespace, bool *has_reader_now)
268{
269 fibril_mutex_lock(&namespace->guard);
270 log_level_t previous_level = namespace->level;
271 while (previous_level == namespace->level) {
272 fibril_condvar_wait(&namespace->level_changed_cv, &namespace->guard);
273 }
274 *has_reader_now = true;
275 fibril_mutex_unlock(&namespace->guard);
276}
277
278
279void namespace_add_message(logging_namespace_t *namespace, const char *message, sysarg_t context, log_level_t level)
280{
281 if (level <= namespace_get_actual_log_level(namespace, context)) {
282 const char *level_name = log_level_str(level);
283 if (context == 0) {
284 printf("[%s %s]: %s\n",
285 namespace->name, level_name, message);
286 fprintf(namespace->logfile, "%s: %s\n",
287 level_name, message);
288 } else {
289 const char *context_name = namespace->context[context].name;
290 printf("[%s/%s %s]: %s\n",
291 namespace->name, context_name, level_name, message);
292 fprintf(namespace->logfile, "[%s] %s: %s\n",
293 context_name, level_name, message);
294 }
295 fflush(namespace->logfile);
296 fflush(stdout);
297 }
298}
299
300
301/**
302 * @}
303 */
Note: See TracBrowser for help on using the repository browser.