Review Board 1.7.16


Add ability for modules to dynamically register/unregister logger levels

Review Request #244 - Created May 4, 2009 and submitted

Kevin Fleming
trunk
Reviewers
asterisk-dev
Asterisk
This patch adds the ability for modules to dynamically create logger levels for their own use; these are named levels just like the built-in levels, and can be directed to any destination that the logger can send any level to, by including their names in logger.conf.
Tested using included test_logger module.

Diff revision 3

This is not the most recent revision of the diff. The latest diff is revision 4. See what's changed.

1 2 3 4
1 2 3 4

  1. /trunk/include/asterisk/logger.h: Loading...
  2. /trunk/main/logger.c: Loading...
  3. /trunk/tests/test_logger.c: Loading...
/trunk/include/asterisk/logger.h
Revision 192404 New Change
1
/*
1
/*
2
 * Asterisk -- An open source telephony toolkit.
2
 * Asterisk -- An open source telephony toolkit.
3
 *
3
 *
4
 * Copyright (C) 1999 - 2005, Digium, Inc.
4
 * Copyright (C) 1999 - 2005, Digium, Inc.
5
 *
5
 *
6
 * Mark Spencer <markster@digium.com>
6
 * Mark Spencer <markster@digium.com>
7
 *
7
 *
8
 * See http://www.asterisk.org for more information about
8
 * See http://www.asterisk.org for more information about
9
 * the Asterisk project. Please do not directly contact
9
 * the Asterisk project. Please do not directly contact
10
 * any of the maintainers of this project for assistance;
10
 * any of the maintainers of this project for assistance;
11
 * the project provides a web site, mailing lists and IRC
11
 * the project provides a web site, mailing lists and IRC
12
 * channels for your use.
12
 * channels for your use.
13
 *
13
 *
14
 * This program is free software, distributed under the terms of
14
 * This program is free software, distributed under the terms of
15
 * the GNU General Public License Version 2. See the LICENSE file
15
 * the GNU General Public License Version 2. See the LICENSE file
16
 * at the top of the source tree.
16
 * at the top of the source tree.
17
 */
17
 */
18

    
   
18

   
19
/*!
19
/*!
20
  \file logger.h
20
  \file logger.h
21
  \brief Support for logging to various files, console and syslog
21
  \brief Support for logging to various files, console and syslog
22
	Configuration in file logger.conf
22
	Configuration in file logger.conf
23
*/
23
*/
24

    
   
24

   
25
#ifndef _ASTERISK_LOGGER_H
25
#ifndef _ASTERISK_LOGGER_H
26
#define _ASTERISK_LOGGER_H
26
#define _ASTERISK_LOGGER_H
27

    
   
27

   
28
#include "asterisk/options.h"	/* need option_debug */
28
#include "asterisk/options.h"	/* need option_debug */
29

    
   
29

   
30
#if defined(__cplusplus) || defined(c_plusplus)
30
#if defined(__cplusplus) || defined(c_plusplus)
31
extern "C" {
31
extern "C" {
32
#endif
32
#endif
33

    
   
33

   
34
#define EVENTLOG "event_log"
34
#define EVENTLOG "event_log"
35
#define	QUEUELOG	"queue_log"
35
#define	QUEUELOG	"queue_log"
36

    
   
36

   
37
#define DEBUG_M(a) { \
37
#define DEBUG_M(a) { \
38
	a; \
38
	a; \
39
}
39
}
40

    
   
40

   
41
#define VERBOSE_PREFIX_1 " "
41
#define VERBOSE_PREFIX_1 " "
42
#define VERBOSE_PREFIX_2 "  == "
42
#define VERBOSE_PREFIX_2 "  == "
43
#define VERBOSE_PREFIX_3 "    -- "
43
#define VERBOSE_PREFIX_3 "    -- "
44
#define VERBOSE_PREFIX_4 "       > "
44
#define VERBOSE_PREFIX_4 "       > "
45

    
   
45

   
46
/*! \brief Used for sending a log message
46
/*! \brief Used for sending a log message
47
	This is the standard logger function.  Probably the only way you will invoke it would be something like this:
47
	This is the standard logger function.  Probably the only way you will invoke it would be something like this:
48
	ast_log(AST_LOG_WHATEVER, "Problem with the %s Captain.  We should get some more.  Will %d be enough?\n", "flux capacitor", 10);
48
	ast_log(AST_LOG_WHATEVER, "Problem with the %s Captain.  We should get some more.  Will %d be enough?\n", "flux capacitor", 10);
49
	where WHATEVER is one of ERROR, DEBUG, EVENT, NOTICE, or WARNING depending
49
	where WHATEVER is one of ERROR, DEBUG, EVENT, NOTICE, or WARNING depending
50
	on which log you wish to output to. These are implemented as macros, that
50
	on which log you wish to output to. These are implemented as macros, that
51
	will provide the function with the needed arguments.
51
	will provide the function with the needed arguments.
52

    
   
52

   
53
 	\param level	Type of log event
53
 	\param level	Type of log event
54
	\param file	Will be provided by the AST_LOG_* macro
54
	\param file	Will be provided by the AST_LOG_* macro
55
	\param line	Will be provided by the AST_LOG_* macro
55
	\param line	Will be provided by the AST_LOG_* macro
56
	\param function	Will be provided by the AST_LOG_* macro
56
	\param function	Will be provided by the AST_LOG_* macro
57
	\param fmt	This is what is important.  The format is the same as your favorite breed of printf.  You know how that works, right? :-)
57
	\param fmt	This is what is important.  The format is the same as your favorite breed of printf.  You know how that works, right? :-)
58
 */
58
 */
59

    
   
59

   
60
void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
60
void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
61
	__attribute__((format(printf, 5, 6)));
61
	__attribute__((format(printf, 5, 6)));
62

    
   
62

   
63
void ast_backtrace(void);
63
void ast_backtrace(void);
64

    
   
64

   
65
/*! \brief Reload logger without rotating log files */
65
/*! \brief Reload logger without rotating log files */
66
int logger_reload(void);
66
int logger_reload(void);
67

    
   
67

   
68
void __attribute__((format(printf, 5, 6))) ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...);
68
void __attribute__((format(printf, 5, 6))) ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...);
69

    
   
69

   
70
/*! Send a verbose message (based on verbose level)
70
/*! Send a verbose message (based on verbose level)
71
 	\brief This works like ast_log, but prints verbose messages to the console depending on verbosity level set.
71
 	\brief This works like ast_log, but prints verbose messages to the console depending on verbosity level set.
72
 	ast_verbose(VERBOSE_PREFIX_3 "Whatever %s is happening\n", "nothing");
72
 	ast_verbose(VERBOSE_PREFIX_3 "Whatever %s is happening\n", "nothing");
73
 	This will print the message to the console if the verbose level is set to a level >= 3
73
 	This will print the message to the console if the verbose level is set to a level >= 3
74
 	Note the abscence of a comma after the VERBOSE_PREFIX_3.  This is important.
74
 	Note the abscence of a comma after the VERBOSE_PREFIX_3.  This is important.
75
 	VERBOSE_PREFIX_1 through VERBOSE_PREFIX_3 are defined.
75
 	VERBOSE_PREFIX_1 through VERBOSE_PREFIX_3 are defined.
76
 */
76
 */
77
void __attribute__((format(printf, 4, 5))) __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...);
77
void __attribute__((format(printf, 4, 5))) __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...);
78

    
   
78

   
79
#define ast_verbose(...) __ast_verbose(__FILE__, __LINE__, __PRETTY_FUNCTION__,  __VA_ARGS__)
79
#define ast_verbose(...) __ast_verbose(__FILE__, __LINE__, __PRETTY_FUNCTION__,  __VA_ARGS__)
80

    
   
80

   
81
void __attribute__((format(printf, 4, 0))) __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap);
81
void __attribute__((format(printf, 4, 0))) __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap);
82

    
   
82

   
83
#define ast_verbose_ap(fmt, ap)	__ast_verbose_ap(__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ap)
83
#define ast_verbose_ap(fmt, ap)	__ast_verbose_ap(__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ap)
84

    
   
84

   
85
void __attribute__((format(printf, 2, 3))) ast_child_verbose(int level, const char *fmt, ...);
85
void __attribute__((format(printf, 2, 3))) ast_child_verbose(int level, const char *fmt, ...);
86

    
   
86

   
87
int ast_register_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
87
int ast_register_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
88
int ast_unregister_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
88
int ast_unregister_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
89

    
   
89

   
90
void ast_console_puts(const char *string);
90
void ast_console_puts(const char *string);
91

    
   
91

   
92
/*!
92
/*!
93
 * \brief log the string to the console, and all attached
93
 * \brief log the string to the console, and all attached
94
 * console clients
94
 * console clients
95
 * \version 1.6.1 added level parameter
95
 * \version 1.6.1 added level parameter
96
 */
96
 */
97
void ast_console_puts_mutable(const char *string, int level);
97
void ast_console_puts_mutable(const char *string, int level);
98
void ast_console_toggle_mute(int fd, int silent);
98
void ast_console_toggle_mute(int fd, int silent);
99

    
   
99

   
100
/*!
100
/*!
101
 * \since 1.6.1
101
 * \since 1.6.1
102
 */
102
 */
103
void ast_console_toggle_loglevel(int fd, int level, int state);
103
void ast_console_toggle_loglevel(int fd, int level, int state);
104

    
   
104

   
105
/* Note: The AST_LOG_* macros below are the same as
105
/* Note: The AST_LOG_* macros below are the same as
106
 * the LOG_* macros and are intended to eventually replace
106
 * the LOG_* macros and are intended to eventually replace
107
 * the LOG_* macros to avoid name collisions as has been
107
 * the LOG_* macros to avoid name collisions as has been
108
 * seen in app_voicemail. However, please do NOT remove
108
 * seen in app_voicemail. However, please do NOT remove
109
 * the LOG_* macros from the source since these may be still
109
 * the LOG_* macros from the source since these may be still
110
 * needed for third-party modules
110
 * needed for third-party modules
111
 */
111
 */
112

    
   
112

   
113
#define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
113
#define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
114

    
   
114

   
115
#ifdef LOG_DEBUG
115
#ifdef LOG_DEBUG
116
#undef LOG_DEBUG
116
#undef LOG_DEBUG
117
#endif
117
#endif
118
#define __LOG_DEBUG    0
118
#define __LOG_DEBUG    0
119
#define LOG_DEBUG      __LOG_DEBUG, _A_
119
#define LOG_DEBUG      __LOG_DEBUG, _A_
120

    
   
120

   
121
#ifdef AST_LOG_DEBUG
121
#ifdef AST_LOG_DEBUG
122
#undef AST_LOG_DEBUG
122
#undef AST_LOG_DEBUG
123
#endif
123
#endif
124
#define AST_LOG_DEBUG      __LOG_DEBUG, _A_
124
#define AST_LOG_DEBUG      __LOG_DEBUG, _A_
125

    
   
125

   
126
#ifdef LOG_NOTICE
126
#ifdef LOG_NOTICE
127
#undef LOG_NOTICE
127
#undef LOG_NOTICE
128
#endif
128
#endif
129
#define __LOG_NOTICE   2
129
#define __LOG_NOTICE   2
130
#define LOG_NOTICE     __LOG_NOTICE, _A_
130
#define LOG_NOTICE     __LOG_NOTICE, _A_
131

    
   
131

   
132
#ifdef AST_LOG_NOTICE
132
#ifdef AST_LOG_NOTICE
133
#undef AST_LOG_NOTICE
133
#undef AST_LOG_NOTICE
134
#endif
134
#endif
135
#define AST_LOG_NOTICE     __LOG_NOTICE, _A_
135
#define AST_LOG_NOTICE     __LOG_NOTICE, _A_
136

    
   
136

   
137
#ifdef LOG_WARNING
137
#ifdef LOG_WARNING
138
#undef LOG_WARNING
138
#undef LOG_WARNING
139
#endif
139
#endif
140
#define __LOG_WARNING  3
140
#define __LOG_WARNING  3
141
#define LOG_WARNING    __LOG_WARNING, _A_
141
#define LOG_WARNING    __LOG_WARNING, _A_
142

    
   
142

   
143
#ifdef AST_LOG_WARNING
143
#ifdef AST_LOG_WARNING
144
#undef AST_LOG_WARNING
144
#undef AST_LOG_WARNING
145
#endif
145
#endif
146
#define AST_LOG_WARNING    __LOG_WARNING, _A_
146
#define AST_LOG_WARNING    __LOG_WARNING, _A_
147

    
   
147

   
148
#ifdef LOG_ERROR
148
#ifdef LOG_ERROR
149
#undef LOG_ERROR
149
#undef LOG_ERROR
150
#endif
150
#endif
151
#define __LOG_ERROR    4
151
#define __LOG_ERROR    4
152
#define LOG_ERROR      __LOG_ERROR, _A_
152
#define LOG_ERROR      __LOG_ERROR, _A_
153

    
   
153

   
154
#ifdef AST_LOG_ERROR
154
#ifdef AST_LOG_ERROR
155
#undef AST_LOG_ERROR
155
#undef AST_LOG_ERROR
156
#endif
156
#endif
157
#define AST_LOG_ERROR      __LOG_ERROR, _A_
157
#define AST_LOG_ERROR      __LOG_ERROR, _A_
158

    
   
158

   
159
#ifdef LOG_VERBOSE
159
#ifdef LOG_VERBOSE
160
#undef LOG_VERBOSE
160
#undef LOG_VERBOSE
161
#endif
161
#endif
162
#define __LOG_VERBOSE  5
162
#define __LOG_VERBOSE  5
163
#define LOG_VERBOSE    __LOG_VERBOSE, _A_
163
#define LOG_VERBOSE    __LOG_VERBOSE, _A_
164

    
   
164

   
165
#ifdef AST_LOG_VERBOSE
165
#ifdef AST_LOG_VERBOSE
166
#undef AST_LOG_VERBOSE
166
#undef AST_LOG_VERBOSE
167
#endif
167
#endif
168
#define LOG_VERBOSE    __LOG_VERBOSE, _A_
168
#define LOG_VERBOSE    __LOG_VERBOSE, _A_
169

    
   
169

   
170
#ifdef LOG_DTMF
170
#ifdef LOG_DTMF
171
#undef LOG_DTMF
171
#undef LOG_DTMF
172
#endif
172
#endif
173
#define __LOG_DTMF  6
173
#define __LOG_DTMF  6
174
#define LOG_DTMF    __LOG_DTMF, _A_
174
#define LOG_DTMF    __LOG_DTMF, _A_
175

    
   
175

   
176
#ifdef AST_LOG_DTMF
176
#ifdef AST_LOG_DTMF
177
#undef AST_LOG_DTMF
177
#undef AST_LOG_DTMF
178
#endif
178
#endif
179
#define AST_LOG_DTMF    __LOG_DTMF, _A_
179
#define AST_LOG_DTMF    __LOG_DTMF, _A_
180

    
   
180

   
181
#define NUMLOGLEVELS 6
181
#define NUMLOGLEVELS 6
182

    
   
182

   
183
/*!
183
/*!
184
 * \brief Get the debug level for a file
184
 * \brief Get the debug level for a file
185
 * \param file the filename
185
 * \param file the filename
186
 * \return the debug level
186
 * \return the debug level
187
 */
187
 */
188
unsigned int ast_debug_get_by_file(const char *file);
188
unsigned int ast_debug_get_by_file(const char *file);
189

    
   
189

   
190
/*!
190
/*!
191
 * \brief Get the debug level for a file
191
 * \brief Get the debug level for a file
192
 * \param file the filename
192
 * \param file the filename
193
 * \return the debug level
193
 * \return the debug level
194
 */
194
 */
195
unsigned int ast_verbose_get_by_file(const char *file);
195
unsigned int ast_verbose_get_by_file(const char *file);
196

    
   
196

   
197
/*!
197
/*!

    
   
198
 * \brief Register a new logger level

    
   
199
 * \param name The name of the level to be registered

    
   
200
 * \retval -1 if an error occurs

    
   
201
 * \retval non-zero level to be used with ast_log for sending messages to this level

    
   
202
 * \since 1.6.3

    
   
203
 */

    
   
204
int ast_logger_register_level(const char *name);

    
   
205

   

    
   
206
/*!

    
   
207
 * \brief Unregister a previously registered logger level

    
   
208
 * \param name The name of the level to be unregistered

    
   
209
 * \return nothing

    
   
210
 * \since 1.6.3

    
   
211
 */

    
   
212
void ast_logger_unregister_level(const char *name);

    
   
213

   

    
   
214
/*!

    
   
215
 * \brief Send a log message to a dynamically registered log level

    
   
216
 * \param level The log level to send the message to

    
   
217
 *

    
   
218
 * Like ast_log, the log message may include printf-style formats, and

    
   
219
 * the data for these must be provided as additional parameters after

    
   
220
 * the log message.

    
   
221
 *

    
   
222
 * \return nothing

    
   
223
 * \since 1.6.3

    
   
224
 */

    
   
225

   

    
   
226
#define ast_log_dynamic_level(level, ...) ast_log(level, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__)

    
   
227

   

    
   
228
/*!
198
 * \brief Log a DEBUG message
229
 * \brief Log a DEBUG message
199
 * \param level The minimum value of option_debug for this message
230
 * \param level The minimum value of option_debug for this message
200
 *        to get logged
231
 *        to get logged
201
 */
232
 */
202
#define ast_debug(level, ...) do {       \
233
#define ast_debug(level, ...) do {       \
203
	if (option_debug >= (level) || (ast_opt_dbg_file && ast_debug_get_by_file(__FILE__) >= (level)) ) \
234
	if (option_debug >= (level) || (ast_opt_dbg_file && ast_debug_get_by_file(__FILE__) >= (level)) ) \
204
		ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
235
		ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
205
} while (0)
236
} while (0)
206

    
   
237

   
207
#define VERBOSITY_ATLEAST(level) (option_verbose >= (level) || (ast_opt_verb_file && ast_verbose_get_by_file(__FILE__) >= (level)))
238
#define VERBOSITY_ATLEAST(level) (option_verbose >= (level) || (ast_opt_verb_file && ast_verbose_get_by_file(__FILE__) >= (level)))
208

    
   
239

   
209
#define ast_verb(level, ...) do { \
240
#define ast_verb(level, ...) do { \
210
	if (VERBOSITY_ATLEAST((level)) ) { \
241
	if (VERBOSITY_ATLEAST((level)) ) { \
211
		if (level >= 4) \
242
		if (level >= 4) \
212
			ast_verbose(VERBOSE_PREFIX_4 __VA_ARGS__); \
243
			ast_verbose(VERBOSE_PREFIX_4 __VA_ARGS__); \
213
		else if (level == 3) \
244
		else if (level == 3) \
214
			ast_verbose(VERBOSE_PREFIX_3 __VA_ARGS__); \
245
			ast_verbose(VERBOSE_PREFIX_3 __VA_ARGS__); \
215
		else if (level == 2) \
246
		else if (level == 2) \
216
			ast_verbose(VERBOSE_PREFIX_2 __VA_ARGS__); \
247
			ast_verbose(VERBOSE_PREFIX_2 __VA_ARGS__); \
217
		else if (level == 1) \
248
		else if (level == 1) \
218
			ast_verbose(VERBOSE_PREFIX_1 __VA_ARGS__); \
249
			ast_verbose(VERBOSE_PREFIX_1 __VA_ARGS__); \
219
		else \
250
		else \
220
			ast_verbose(__VA_ARGS__); \
251
			ast_verbose(__VA_ARGS__); \
221
	} \
252
	} \
222
} while (0)
253
} while (0)
223

    
   
254

   
224
#ifndef _LOGGER_BACKTRACE_H
255
#ifndef _LOGGER_BACKTRACE_H
225
#define _LOGGER_BACKTRACE_H
256
#define _LOGGER_BACKTRACE_H
226
#ifdef HAVE_BKTR
257
#ifdef HAVE_BKTR
227
#define AST_MAX_BT_FRAMES 32
258
#define AST_MAX_BT_FRAMES 32
228
/* \brief
259
/* \brief
229
 *
260
 *
230
 * A structure to hold backtrace information. This structure provides an easy means to
261
 * A structure to hold backtrace information. This structure provides an easy means to
231
 * store backtrace information or pass backtraces to other functions.
262
 * store backtrace information or pass backtraces to other functions.
232
 */
263
 */
233
struct ast_bt {
264
struct ast_bt {
234
	/*! The addresses of the stack frames. This is filled in by calling the glibc backtrace() function */
265
	/*! The addresses of the stack frames. This is filled in by calling the glibc backtrace() function */
235
	void *addresses[AST_MAX_BT_FRAMES];
266
	void *addresses[AST_MAX_BT_FRAMES];
236
	/*! The number of stack frames in the backtrace */
267
	/*! The number of stack frames in the backtrace */
237
	int num_frames;
268
	int num_frames;
238
	/*! Tells if the ast_bt structure was dynamically allocated */
269
	/*! Tells if the ast_bt structure was dynamically allocated */
239
	unsigned int alloced:1;
270
	unsigned int alloced:1;
240
};
271
};
241

    
   
272

   
242
/* \brief
273
/* \brief
243
 * Allocates memory for an ast_bt and stores addresses and symbols.
274
 * Allocates memory for an ast_bt and stores addresses and symbols.
244
 *
275
 *
245
 * \return Returns NULL on failure, or the allocated ast_bt on success
276
 * \return Returns NULL on failure, or the allocated ast_bt on success
246
 * \since 1.6.1
277
 * \since 1.6.1
247
 */
278
 */
248
struct ast_bt *ast_bt_create(void);
279
struct ast_bt *ast_bt_create(void);
249

    
   
280

   
250
/* \brief
281
/* \brief
251
 * Fill an allocated ast_bt with addresses
282
 * Fill an allocated ast_bt with addresses
252
 *
283
 *
253
 * \retval 0 Success
284
 * \retval 0 Success
254
 * \retval -1 Failure
285
 * \retval -1 Failure
255
 * \since 1.6.1
286
 * \since 1.6.1
256
 */
287
 */
257
int ast_bt_get_addresses(struct ast_bt *bt);
288
int ast_bt_get_addresses(struct ast_bt *bt);
258

    
   
289

   
259
/* \brief
290
/* \brief
260
 *
291
 *
261
 * Free dynamically allocated portions of an ast_bt
292
 * Free dynamically allocated portions of an ast_bt
262
 *
293
 *
263
 * \retval NULL.
294
 * \retval NULL.
264
 * \since 1.6.1
295
 * \since 1.6.1
265
 */
296
 */
266
void *ast_bt_destroy(struct ast_bt *bt);
297
void *ast_bt_destroy(struct ast_bt *bt);
267

    
   
298

   
268
#endif /* HAVE_BKTR */
299
#endif /* HAVE_BKTR */
269
#endif /* _LOGGER_BACKTRACE_H */
300
#endif /* _LOGGER_BACKTRACE_H */
270

    
   
301

   
271
#if defined(__cplusplus) || defined(c_plusplus)
302
#if defined(__cplusplus) || defined(c_plusplus)
272
}
303
}
273
#endif
304
#endif
274

    
   
305

   
275
#endif /* _ASTERISK_LOGGER_H */
306
#endif /* _ASTERISK_LOGGER_H */
/trunk/main/logger.c
Revision 192404 New Change
 
/trunk/tests/test_logger.c
New File
 
  1. /trunk/include/asterisk/logger.h: Loading...
  2. /trunk/main/logger.c: Loading...
  3. /trunk/tests/test_logger.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.