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

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

Remove premature optimizations

  • 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 FILE *logfile;
54 log_level_t level;
55 const char *name;
56
57 // FIXME: make dynamic
58 size_t context_count;
59 logging_context_t context[CONTEXT_SIZE];
60
61 link_t link;
62};
63
64static FIBRIL_MUTEX_INITIALIZE(namespace_list_guard);
65static LIST_INITIALIZE(namespace_list);
66
67static log_level_t namespace_get_actual_log_level(logging_namespace_t *namespace, sysarg_t context)
68{
69 fibril_mutex_lock(&namespace->guard);
70 if (context >= namespace->context_count) {
71 fibril_mutex_unlock(&namespace->guard);
72 fprintf(stderr, "Invalid context!\n");
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 namespace->writers_count = 0;
137 link_initialize(&namespace->link);
138
139 list_append(&namespace->link, &namespace_list);
140
141 return namespace;
142}
143
144
145logging_namespace_t *namespace_create(const char *name)
146{
147 fibril_mutex_lock(&namespace_list_guard);
148 logging_namespace_t *result = namespace_create_no_lock(name);
149 fibril_mutex_unlock(&namespace_list_guard);
150 return result;
151}
152
153const char *namespace_get_name(logging_namespace_t *namespace)
154{
155 assert(namespace);
156 return namespace->name;
157}
158
159static void namespace_destroy_careful(logging_namespace_t *namespace)
160{
161 assert(namespace);
162 fibril_mutex_lock(&namespace_list_guard);
163
164 fibril_mutex_lock(&namespace->guard);
165 if (namespace->writers_count > 0) {
166 fibril_mutex_unlock(&namespace->guard);
167 fibril_mutex_unlock(&namespace_list_guard);
168 return;
169 }
170
171 list_remove(&namespace->link);
172
173 fibril_mutex_unlock(&namespace->guard);
174 fibril_mutex_unlock(&namespace_list_guard);
175
176 // TODO - destroy pending messages
177 fclose(namespace->logfile);
178 free(namespace->name);
179 free(namespace);
180}
181
182void namespace_destroy(logging_namespace_t *namespace)
183{
184 namespace_destroy_careful(namespace);
185}
186
187logging_namespace_t *namespace_writer_attach(const char *name)
188{
189 logging_namespace_t *namespace = NULL;
190
191 fibril_mutex_lock(&namespace_list_guard);
192
193 namespace = namespace_find_no_lock(name);
194
195 if (namespace == NULL) {
196 namespace = namespace_create_no_lock(name);
197 }
198
199 fibril_mutex_lock(&namespace->guard);
200 namespace->writers_count++;
201 fibril_mutex_unlock(&namespace->guard);
202
203 fibril_mutex_unlock(&namespace_list_guard);
204
205 return namespace;
206}
207
208void namespace_writer_detach(logging_namespace_t *namespace)
209{
210 fibril_mutex_lock(&namespace->guard);
211 assert(namespace->writers_count > 0);
212 namespace->writers_count--;
213 fibril_mutex_unlock(&namespace->guard);
214
215 namespace_destroy_careful(namespace);
216}
217
218int namespace_change_level(logging_namespace_t *namespace, log_level_t level)
219{
220 if (level >= LVL_LIMIT)
221 return ERANGE;
222
223 fibril_mutex_lock(&namespace->guard);
224 namespace->level = level;
225 for (size_t i = 0; i < namespace->context_count; i++) {
226 namespace->context[i].level = level;
227 }
228 fibril_mutex_unlock(&namespace->guard);
229
230 return EOK;
231}
232
233
234bool namespace_has_reader(logging_namespace_t *namespace, sysarg_t context, log_level_t level)
235{
236 return level <= namespace_get_actual_log_level(namespace, context);
237}
238
239int namespace_create_context(logging_namespace_t *namespace, const char *name)
240{
241 int rc;
242 fibril_mutex_lock(&namespace->guard);
243 if (namespace->context_count >= CONTEXT_SIZE) {
244 rc = ELIMIT;
245 goto leave;
246 }
247
248 namespace->context[namespace->context_count].level
249 = LOG_LEVEL_USE_DEFAULT;
250 namespace->context[namespace->context_count].name
251 = str_dup(name);
252 if (namespace->context[namespace->context_count].name == NULL) {
253 rc = ENOMEM;
254 goto leave;
255 }
256 rc = (int) namespace->context_count;
257 namespace->context_count++;
258
259
260leave:
261 fibril_mutex_unlock(&namespace->guard);
262 return rc;
263}
264
265int namespace_change_context_level(logging_namespace_t *namespace, const char *context, log_level_t new_level)
266{
267 if (new_level >= LVL_LIMIT)
268 return ERANGE;
269
270 int rc;
271 fibril_mutex_lock(&namespace->guard);
272 for (size_t i = 0; i < namespace->context_count; i++) {
273 if (str_cmp(namespace->context[i].name, context) == 0) {
274 namespace->context[i].level = new_level;
275 rc = EOK;
276 goto leave;
277 }
278 }
279 rc = ENOENT;
280
281leave:
282 fibril_mutex_unlock(&namespace->guard);
283 return rc;
284}
285
286void namespace_add_message(logging_namespace_t *namespace, const char *message, sysarg_t context, log_level_t level)
287{
288 if (level <= namespace_get_actual_log_level(namespace, context)) {
289 const char *level_name = log_level_str(level);
290 if (context == 0) {
291 printf("[%s %s]: %s\n",
292 namespace->name, level_name, message);
293 fprintf(namespace->logfile, "%s: %s\n",
294 level_name, message);
295 } else {
296 const char *context_name = namespace->context[context].name;
297 printf("[%s/%s %s]: %s\n",
298 namespace->name, context_name, level_name, message);
299 fprintf(namespace->logfile, "[%s] %s: %s\n",
300 context_name, level_name, message);
301 }
302 fflush(namespace->logfile);
303 fflush(stdout);
304 }
305}
306
307
308/**
309 * @}
310 */
Note: See TracBrowser for help on using the repository browser.