source: mainline/uspace/srv/logger/namespace.c@ 669f5cae

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

Allow setting default log level

Currently, it does not affect existing clients.

  • Property mode set to 100644
File size: 7.5 KB
RevLine 
[1f2dd20]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 "logger.h"
37
38/** @file
39 * Logging namespaces.
40 */
41
[76d92db1]42
[1f2dd20]43struct logging_namespace {
44 fibril_mutex_t guard;
[ef5be68]45 size_t writers_count;
[2e39656]46 fibril_condvar_t reader_appeared_cv;
[1f2dd20]47 bool has_reader;
[76d92db1]48 FILE *logfile;
49 log_level_t logfile_level;
[1f2dd20]50 const char *name;
51 link_t link;
52 prodcons_t messages;
53};
54
55static FIBRIL_MUTEX_INITIALIZE(namespace_list_guard);
56static LIST_INITIALIZE(namespace_list);
57
58log_message_t *message_create(const char *name, log_level_t level)
59{
60 log_message_t *message = malloc(sizeof(log_message_t));
61 if (message == NULL)
62 return NULL;
63
64 message->message = str_dup(name);
65 if (message->message == NULL) {
66 free(message);
67 return NULL;
68 }
69
70 message->level = level;
71 link_initialize(&message->link);
72
73 return message;
74}
75
76void message_destroy(log_message_t *message)
77{
78 assert(message);
79 free(message->message);
80 free(message);
81}
82
83static logging_namespace_t *namespace_find_no_lock(const char *name)
84{
85 list_foreach(namespace_list, it) {
86 logging_namespace_t *namespace = list_get_instance(it, logging_namespace_t, link);
87 if (str_cmp(namespace->name, name) == 0) {
88 return namespace;
89 }
90 }
91
92 return NULL;
93}
94
[01b8c2e4]95static logging_namespace_t *namespace_create_no_lock(const char *name)
[1f2dd20]96{
97 logging_namespace_t *existing = namespace_find_no_lock(name);
98 if (existing != NULL) {
99 return NULL;
100 }
101
102 logging_namespace_t *namespace = malloc(sizeof(logging_namespace_t));
103 if (namespace == NULL) {
104 return NULL;
105 }
106
107 namespace->name = str_dup(name);
108 if (namespace->name == NULL) {
109 free(namespace);
110 return NULL;
111 }
112
[76d92db1]113 char *logfilename;
114 int rc = asprintf(&logfilename, "/log/%s", name);
115 if (rc < 0) {
116 free(namespace->name);
117 free(namespace);
118 return NULL;
119 }
120 namespace->logfile = fopen(logfilename, "a");
121 free(logfilename);
122 if (namespace->logfile == NULL) {
123 free(namespace->name);
124 free(namespace);
125 return NULL;
126 }
127
[669f5cae]128 namespace->logfile_level = get_default_logging_level();
[76d92db1]129
[1f2dd20]130 fibril_mutex_initialize(&namespace->guard);
[be73793]131 fibril_condvar_initialize(&namespace->reader_appeared_cv);
[1f2dd20]132 prodcons_initialize(&namespace->messages);
133 namespace->has_reader = false;
[ef5be68]134 namespace->writers_count = 0;
[1f2dd20]135 link_initialize(&namespace->link);
136
137 list_append(&namespace->link, &namespace_list);
138
139 return namespace;
140}
141
[01b8c2e4]142
143logging_namespace_t *namespace_create(const char *name)
144{
145 fibril_mutex_lock(&namespace_list_guard);
146 logging_namespace_t *result = namespace_create_no_lock(name);
147 fibril_mutex_unlock(&namespace_list_guard);
148 return result;
149}
150
[1f2dd20]151const char *namespace_get_name(logging_namespace_t *namespace)
152{
153 assert(namespace);
154 return namespace->name;
155}
156
157static void namespace_destroy_careful(logging_namespace_t *namespace)
158{
159 assert(namespace);
160 fibril_mutex_lock(&namespace_list_guard);
161
162 fibril_mutex_lock(&namespace->guard);
[ef5be68]163 if (namespace->has_reader || (namespace->writers_count > 0)) {
[1f2dd20]164 fibril_mutex_unlock(&namespace->guard);
165 fibril_mutex_unlock(&namespace_list_guard);
166 return;
167 }
168
169 list_remove(&namespace->link);
170
171 fibril_mutex_unlock(&namespace->guard);
172 fibril_mutex_unlock(&namespace_list_guard);
173
174 // TODO - destroy pending messages
[76d92db1]175 fclose(namespace->logfile);
[1f2dd20]176 free(namespace->name);
177 free(namespace);
178}
179
180void namespace_destroy(logging_namespace_t *namespace)
181{
182 namespace_destroy_careful(namespace);
183}
184
185logging_namespace_t *namespace_reader_attach(const char *name)
186{
187 logging_namespace_t *namespace = NULL;
188
189 fibril_mutex_lock(&namespace_list_guard);
190
191 namespace = namespace_find_no_lock(name);
192
193 if (namespace != NULL) {
194 fibril_mutex_lock(&namespace->guard);
195 namespace->has_reader = true;
[2e39656]196 fibril_condvar_broadcast(&namespace->reader_appeared_cv);
[1f2dd20]197 fibril_mutex_unlock(&namespace->guard);
198 }
199
200 fibril_mutex_unlock(&namespace_list_guard);
201
202 return namespace;
203}
204
[ef5be68]205logging_namespace_t *namespace_writer_attach(const char *name)
206{
207 logging_namespace_t *namespace = NULL;
208
209 fibril_mutex_lock(&namespace_list_guard);
210
211 namespace = namespace_find_no_lock(name);
212
213 if (namespace == NULL) {
[01b8c2e4]214 namespace = namespace_create_no_lock(name);
[ef5be68]215 }
216
217 fibril_mutex_lock(&namespace->guard);
218 namespace->writers_count++;
219 fibril_mutex_unlock(&namespace->guard);
220
221 fibril_mutex_unlock(&namespace_list_guard);
222
223 return namespace;
224}
225
[1f2dd20]226void namespace_reader_detach(logging_namespace_t *namespace)
227{
228 fibril_mutex_lock(&namespace->guard);
229 namespace->has_reader = false;
[2e39656]230 fibril_condvar_broadcast(&namespace->reader_appeared_cv);
[1f2dd20]231 fibril_mutex_unlock(&namespace->guard);
232
233 namespace_destroy_careful(namespace);
234}
235
236void namespace_writer_detach(logging_namespace_t *namespace)
237{
238 fibril_mutex_lock(&namespace->guard);
[ef5be68]239 assert(namespace->writers_count > 0);
240 namespace->writers_count--;
[1f2dd20]241 fibril_mutex_unlock(&namespace->guard);
242
243 namespace_destroy_careful(namespace);
244}
245
[76d92db1]246bool namespace_has_reader(logging_namespace_t *namespace, log_level_t level)
[f6bc83a]247{
248 fibril_mutex_lock(&namespace->guard);
[76d92db1]249 bool has_reader = namespace->has_reader
250 || level <= namespace->logfile_level;
[f6bc83a]251 fibril_mutex_unlock(&namespace->guard);
252 return has_reader;
253}
[1f2dd20]254
[2e39656]255void namespace_wait_for_reader_change(logging_namespace_t *namespace, bool *has_reader_now)
256{
257 fibril_mutex_lock(&namespace->guard);
258 bool had_reader = namespace->has_reader;
259 while (had_reader == namespace->has_reader) {
260 fibril_condvar_wait(&namespace->reader_appeared_cv, &namespace->guard);
261 }
262 *has_reader_now = namespace->has_reader;
263 fibril_mutex_unlock(&namespace->guard);
264}
265
[1f2dd20]266
267void namespace_add_message(logging_namespace_t *namespace, const char *message, log_level_t level)
268{
[669f5cae]269 if (level <= get_default_logging_level()) {
[1f2dd20]270 printf("[%s %d]: %s\n", namespace->name, level, message);
271 }
[76d92db1]272 if (level <= namespace->logfile_level) {
273 fprintf(namespace->logfile, "[%d]: %s\n", level, message);
274 fflush(namespace->logfile);
275 }
[1f2dd20]276
277 fibril_mutex_lock(&namespace->guard);
278 if (namespace->has_reader) {
279 log_message_t *msg = message_create(message, level);
280 if (msg != NULL) {
281 prodcons_produce(&namespace->messages, &msg->link);
282 }
283 }
284 fibril_mutex_unlock(&namespace->guard);
285}
286
287log_message_t *namespace_get_next_message(logging_namespace_t *namespace)
288{
289 link_t *message = prodcons_consume(&namespace->messages);
290
291 return list_get_instance(message, log_message_t, link);
292}
293
294
295/**
296 * @}
297 */
Note: See TracBrowser for help on using the repository browser.