75ece93551aef4e049280ea552d7671b24623075
[protos/libecoli.git] / lib / ecoli_log.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #define _GNU_SOURCE /* for vasprintf */
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include <ecoli_malloc.h>
35 #include <ecoli_string.h>
36 #include <ecoli_log.h>
37
38 static ec_log_t ec_log_fct = ec_log_default_cb;
39 static void *ec_log_opaque;
40
41 struct ec_log_type {
42         char *name;
43         enum ec_log_level level;
44 };
45
46 static struct ec_log_type *log_types;
47 static size_t log_types_len;
48 static enum ec_log_level global_level = EC_LOG_WARNING;
49
50 int ec_log_level_set(enum ec_log_level level)
51 {
52         if (level < 0 || level > EC_LOG_DEBUG)
53                 return -1;
54         global_level = level;
55
56         return 0;
57 }
58
59 enum ec_log_level ec_log_level_get(void)
60 {
61         return global_level;
62 }
63
64 int ec_log_default_cb(int type, enum ec_log_level level, void *opaque,
65                 const char *str)
66 {
67         (void)opaque;
68
69         if (level > ec_log_level_get())
70                 return 0;
71
72         if (fprintf(stderr, "[%d] %-12s %s", level, ec_log_name(type), str) < 0)
73                 return -1;
74
75         return 0;
76 }
77
78 int ec_log_fct_register(ec_log_t usr_log, void *opaque)
79 {
80         errno = 0;
81
82         if (usr_log == NULL) {
83                 ec_log_fct = ec_log_default_cb;
84                 ec_log_opaque = NULL;
85         } else {
86                 ec_log_fct = usr_log;
87                 ec_log_opaque = opaque;
88         }
89
90         return 0;
91 }
92
93 static int
94 ec_log_lookup(const char *name)
95 {
96         size_t i;
97
98         for (i = 0; i < log_types_len; i++) {
99                 if (log_types[i].name == NULL)
100                         continue;
101                 if (strcmp(name, log_types[i].name) == 0)
102                         return i;
103         }
104
105         return -1;
106 }
107
108 int
109 ec_log_type_register(const char *name)
110 {
111         struct ec_log_type *new_types;
112         char *copy;
113         int id;
114
115         id = ec_log_lookup(name);
116         if (id >= 0)
117                 return id;
118
119         new_types = ec_realloc(log_types,
120                 sizeof(*new_types) * (log_types_len + 1));
121         if (new_types == NULL)
122                 return -1; /* errno is set */
123         log_types = new_types;
124
125         copy = ec_strdup(name);
126         if (copy == NULL)
127                 return -1; /* errno is set */
128
129         id = log_types_len++;
130         log_types[id].name = copy;
131         log_types[id].level = EC_LOG_DEBUG;
132
133         return id;
134 }
135
136 const char *
137 ec_log_name(int type)
138 {
139         if (type < 0 || (unsigned int)type >= log_types_len)
140                 return "unknown";
141         return log_types[type].name;
142 }
143
144 int ec_vlog(int type, enum ec_log_level level, const char *format, va_list ap)
145 {
146         char *s;
147         int ret;
148
149         /* don't use ec_vasprintf here, because it will call
150          * ec_malloc(), then ec_log(), ec_vasprintf()...
151          * -> stack overflow */
152         ret = vasprintf(&s, format, ap);
153         if (ret < 0)
154                 return ret;
155
156         ret = ec_log_fct(type, level, ec_log_opaque, s);
157         free(s);
158
159         return ret;
160 }
161
162 int ec_log(int type, enum ec_log_level level, const char *format, ...)
163 {
164         va_list ap;
165         int ret;
166
167         va_start(ap, format);
168         ret = ec_vlog(type, level, format, ap);
169         va_end(ap);
170
171         return ret;
172 }