Asterisk - The Open Source Telephony Project GIT-master-7921072
logger_category.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2020, Sangoma Technologies Corporation
5 *
6 * Kevin Harwell <kharwell@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#include "asterisk.h"
20
21#include "asterisk/cli.h"
24#include "asterisk/vector.h"
25
26struct category_t {
28 uintmax_t id;
29 char name[0];
30};
31
32AST_VECTOR_RW(categories_t, struct category_t *);
33
35 int type;
37 uintmax_t id_pool;
38 uintmax_t state;
39 struct categories_t categories;
40};
41
42/*! \brief Retrieve the next available id.
43 *
44 * Ids must be a power of 2. This allows for fast lookup, and "or'ing" of ids
45 * in order to permit multiple categories in a log statement.
46 */
47static uintmax_t get_next_id(struct categories_level_t *level)
48{
49 if (level->id_pool == 0) {
50 level->id_pool = 1;
51 } else if (level->id_pool >= (UINTMAX_MAX / 2)) {
52 /* No more ids left*/
53 return 0;
54 } else {
55 level->id_pool <<= 1;
56 }
57
58 return level->id_pool;
59}
60
61static int cmp_by_name(const struct category_t *category, const char *name)
62{
63 return !strcmp(category->name, name);
64}
65
66static uintmax_t category_register(struct categories_level_t *level, const char *name)
67{
68 int i;
69 struct category_t *category;
70
72
74 if (i >= 0) {
76 ast_log(LOG_ERROR, "Cannot register logger category '%s'. "
77 "Name already used for type.\n", name);
78 return 0;
79 }
80
81 category = ast_calloc(1, sizeof(*category) + strlen(name) + 1);
82 if (!category) {
84 return 0;
85 }
86
87 category->id = get_next_id(level);
89 strcpy(category->name, name); /* Safe */
90
91 if (AST_VECTOR_APPEND(&level->categories, category)) {
93 ast_log(LOG_ERROR, "Cannot register logger category '%s'. "
94 "Unable to append.\n", name);
95 return 0;
96 }
97
99 return category->id;
100}
101
102static int category_unregister(struct categories_level_t *level, const char *name)
103{
104 int res;
105
109
110 return res;
111}
112
113static int casecmp_by_name(const struct category_t *category, const char *name)
114{
115 return !strcasecmp(category->name, name);
116}
117
118static int category_set_sublevel(struct category_t *category, struct categories_level_t *level,
119 const char *name, int sublevel)
120{
121 int locked = 0;
122
123 if (!category) {
124 struct category_t **obj;
125
126 if (!name) {
127 return -1;
128 }
129
130 locked = !AST_VECTOR_RW_WRLOCK(&level->categories);
131 if (!locked) {
132 return -1;
133 }
134
136 if (!obj) {
138 return -1;
139 }
140
141 category = *obj;
142 }
143
144 category->sublevel = sublevel;
145
146 if (category->sublevel == AST_LOG_CATEGORY_DISABLED) {
147 level->state &= ~category->id;
148 } else {
149 level->state |= category->id;
150 }
151
152 if (locked) {
154 }
155
156 return 0;
157}
158
160 const char * const *names, size_t size, int default_sublevel)
161{
162 int i;
163
164 if (!names || !size) {
165 level->state = default_sublevel;
168 level, NULL, default_sublevel);
170 return 0;
171 }
172
173 for (i = 0; i < size; ++i) {
174 const char *sublevel;
175 int num = default_sublevel;
176
177 sublevel = strchr(names[i], ':');
178 if (sublevel) {
179 size_t len = ++sublevel - names[i];
180 char name[len];
181
182 if (*sublevel && ast_str_to_int(sublevel, &num)) {
183 continue;
184 }
185
186 ast_copy_string(name, names[i], len);
187 category_set_sublevel(NULL, level, name, num);
188 } else {
189 category_set_sublevel(NULL, level, names[i], num);
190 }
191 }
192
193 return 0;
194}
195
196static char *category_complete(struct categories_level_t *level, const char * const *argv,
197 int argc, const char *word, int state)
198{
199 int wordlen = strlen(word);
200 int which = 0;
201 int i, j;
202
204
205 if (argc == AST_VECTOR_SIZE(&level->categories)) {
207 return NULL;
208 }
209
210 for (i = 0; i < AST_VECTOR_SIZE(&level->categories); ++i) {
211 struct category_t *category = AST_VECTOR_GET(&level->categories, i);
212
213 if (!strncasecmp(word, category->name, wordlen) && (++which > state)) {
214 /* Check to see if one is already been included */
215 for (j = 0; j < argc; ++j) {
216 if (!strncasecmp(category->name, argv[j], strlen(category->name))) {
217 break;
218 }
219 }
220
221 if (j != argc) {
222 continue;
223 }
224
225 if (state != -1) {
227 return ast_strdup(category->name);
228 }
229
230 if (ast_cli_completion_add(ast_strdup(category->name))) {
232 return NULL;
233 }
234 }
235 }
236
238 return NULL;
239}
240
241static int category_is_allowed(int sublevel, struct categories_level_t *level, uintmax_t ids)
242{
243 /* Check level, and potentially allow but only if there is a matching state enabled */
244 if (ids & level->state) {
245 int i;
246
248 /* If at least one id is enabled then always allow these sublevels */
249 return 1;
250 }
251
253 for (i = 0; i < AST_VECTOR_SIZE(&level->categories); ++i) {
254 struct category_t *category = AST_VECTOR_GET(&level->categories, i);
255
256 /*
257 * If there is at least one matching category, and that category is enabled
258 * or its sub-level is at or above the given sub-level then allow.
259 */
260 if ((category->id & ids) && category->sublevel != AST_LOG_CATEGORY_DISABLED &&
261 (category->sublevel == AST_LOG_CATEGORY_ENABLED || category->sublevel >= sublevel)) {
263 return 1;
264 }
265 }
267 }
268
269 return 0;
270}
271
273 .type = __LOG_DEBUG,
274 .sublevel = 0,
275 .id_pool = 0,
276 .state = 0,
277};
278
279uintmax_t ast_debug_category_register(const char *name)
280{
282}
283
285{
287}
288
290{
292}
293
294int ast_debug_category_set_sublevels(const char * const *names,
295 size_t size, int default_sublevel)
296{
297 return category_set_sublevels(&debug_categories, names, size, default_sublevel);
298}
299
300char *ast_debug_category_complete(const char * const *argv, int argc,
301 const char *word, int state)
302{
303 return category_complete(&debug_categories, argv, argc, word, state);
304}
305
307{
309}
310
312{
314 return 0;
315}
316
318{
320 return -1;
321 }
322
323 return 0;
324}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
Standard Command Line Interface.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2756
short word
Conversion utility functions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define __LOG_DEBUG
#define LOG_ERROR
static char * category_complete(struct categories_level_t *level, const char *const *argv, int argc, const char *word, int state)
uintmax_t ast_debug_category_register(const char *name)
Register a debug level logger category.
static uintmax_t get_next_id(struct categories_level_t *level)
Retrieve the next available id.
AST_VECTOR_RW(categories_t, struct category_t *)
static int category_is_allowed(int sublevel, struct categories_level_t *level, uintmax_t ids)
int ast_logger_category_load(void)
Load/Initialize system wide logger category functionality.
int ast_logger_category_unload(void)
Unload system wide logger category functionality.
char * ast_debug_category_complete(const char *const *argv, int argc, const char *word, int state)
Add a unique (no duplicates) result to a request for completion for debug categories.
int ast_debug_category_is_allowed(int sublevel, uintmax_t ids)
Check if a debug category is enabled, and allowed to output.
static int category_set_sublevels(struct categories_level_t *level, const char *const *names, size_t size, int default_sublevel)
static int casecmp_by_name(const struct category_t *category, const char *name)
int ast_debug_category_unregister(const char *name)
Un-register a debug level logger category.
static uintmax_t category_register(struct categories_level_t *level, const char *name)
static int cmp_by_name(const struct category_t *category, const char *name)
static int category_unregister(struct categories_level_t *level, const char *name)
int ast_debug_category_set_sublevel(const char *name, int sublevel)
Set the debug category's sublevel.
static int category_set_sublevel(struct category_t *category, struct categories_level_t *level, const char *name, int sublevel)
int ast_debug_category_set_sublevels(const char *const *names, size_t size, int default_sublevel)
Set one or more debug category's sublevel.
static struct categories_level_t debug_categories
#define AST_LOG_CATEGORY_DISABLED
#define AST_LOG_CATEGORY_ENABLED
#define NULL
Definition: resample.c:96
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct categories_t categories
uintmax_t id
char name[0]
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET_INDEX(vec, value, cmp)
Get the 1st index from a vector that matches the given comparison.
Definition: vector.h:719
#define AST_VECTOR_RW_WRLOCK(vec)
Obtain write lock on vector.
Definition: vector.h:887
#define AST_VECTOR_RW_UNLOCK(vec)
Unlock vector.
Definition: vector.h:897
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition: vector.h:488
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
#define AST_VECTOR_RW_FREE(vec)
Deallocates this locked vector.
Definition: vector.h:202
#define AST_VECTOR_RW_RDLOCK(vec)
Obtain read lock on vector.
Definition: vector.h:877
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
#define AST_VECTOR_RW_INIT(vec, size)
Initialize a vector with a read/write lock.
Definition: vector.h:158