34 #include "asterisk/statsd.h"
74 static const char app[] =
"StatsD";
87 static int value_in_range(
const char *value) {
88 double numerical_value = strtod(value, NULL);
90 if (numerical_value < pow(-2, 63) || numerical_value > pow(2, 63)) {
91 ast_log(AST_LOG_WARNING,
"Value %lf out of range!\n", numerical_value);
109 static int non_neg_value_range(
const char *value) {
110 double numerical_value = strtod(value, NULL);
112 if (numerical_value < 0 || numerical_value > pow(2, 64)) {
113 ast_log(AST_LOG_WARNING,
"Value %lf out of range!\n", numerical_value);
131 static int validate_metric(
const char *metric)
133 const char *valid_metrics[] = {
"g",
"s",
"ms",
"c"};
136 if (ast_strlen_zero(metric)) {
137 ast_log(AST_LOG_ERROR,
"Missing metric type argument.\n");
141 for (i = 0; i < ARRAY_LEN(valid_metrics); i++) {
142 if (!strcmp(valid_metrics[i], metric)) {
147 ast_log(AST_LOG_ERROR,
"Invalid metric type %s.\n", metric);
163 static int validate_numeric(
const char *numeric_value) {
165 int decimal_counter = 0;
169 if (!isdigit(*num++)) {
170 if (strstr(numeric_value,
".") != NULL && decimal_counter == 0) {
174 ast_log(AST_LOG_ERROR,
"%s is not a number!\n", numeric_value);
194 static int determine_actual_value(
const char *raw_value) {
195 const char *actual_value;
197 if ((raw_value[0] ==
'+') || (raw_value[0] ==
'-')) {
198 actual_value = &raw_value[1];
199 if (ast_strlen_zero(actual_value)) {
200 ast_log(AST_LOG_ERROR,
"Value argument %s only contains a sign"
201 " operator.\n", raw_value);
205 actual_value = &raw_value[0];
208 return validate_numeric(actual_value);
223 static int validate_name(
const char *name)
225 if (ast_strlen_zero(name) || (strstr(name,
"|") != NULL)) {
226 ast_log(AST_LOG_ERROR,
"Statistic name %s is missing or contains a pipe (|)"
227 " character.\n", name);
247 static int validate_metric_type_gauge(
const char *statistic_name,
const char *value) {
249 if (ast_strlen_zero(value)) {
250 ast_log(AST_LOG_ERROR,
"Missing value argument.\n");
254 if (validate_name(statistic_name) || determine_actual_value(value)
255 || value_in_range(value)) {
274 static int validate_metric_type_counter(
const char *statistic_name,
const char *value) {
276 if (ast_strlen_zero(value)) {
277 ast_log(AST_LOG_ERROR,
"Missing value argument.\n");
281 if (validate_name(statistic_name) || determine_actual_value(value)
282 || value_in_range(value)) {
301 static int validate_metric_type_timer(
const char *statistic_name,
const char *value) {
303 if (ast_strlen_zero(value)) {
304 ast_log(AST_LOG_ERROR,
"Missing value argument.\n");
308 if (validate_name(statistic_name) || validate_numeric(value)
309 || non_neg_value_range(value)) {
328 static int validate_metric_type_set(
const char *statistic_name,
const char *value) {
329 if (ast_strlen_zero(value)) {
330 ast_log(AST_LOG_ERROR,
"Missing value argument.\n");
334 if (validate_name(statistic_name)) {
338 if (strstr(value,
"|") != NULL) {
339 ast_log(AST_LOG_ERROR,
"Pipe (|) character is not allowed for value %s"
340 " in a set metric.\n", value);
347 static int statsd_exec(
struct ast_channel *chan,
const char *data)
350 double numerical_rate = 1.0;
360 ast_log(AST_LOG_ERROR,
"No parameters were provided. Correct format is "
361 "StatsD(metric_type,statistic_name,value[,sample_rate]). Sample rate is the "
362 "only optional parameter.\n");
369 if (validate_metric(args.metric_type)) {
373 if (!strcmp(args.metric_type,
"g")) {
374 if (validate_metric_type_gauge(args.statistic_name, args.value)) {
375 ast_log(AST_LOG_ERROR,
"Invalid input for a gauge metric.\n");
379 else if (!strcmp(args.metric_type,
"c")) {
380 if (validate_metric_type_counter(args.statistic_name, args.value)) {
381 ast_log(AST_LOG_ERROR,
"Invalid input for a counter metric.\n");
385 else if (!strcmp(args.metric_type,
"ms")) {
386 if (validate_metric_type_timer(args.statistic_name, args.value)) {
387 ast_log(AST_LOG_ERROR,
"Invalid input for a timer metric.\n");
391 else if (!strcmp(args.metric_type,
"s")) {
392 if (validate_metric_type_set(args.statistic_name, args.value)) {
393 ast_log(AST_LOG_ERROR,
"Invalid input for a set metric.\n");
398 if (args.sample_rate) {
400 if (validate_numeric(args.sample_rate)) {
404 numerical_rate = strtod(args.sample_rate, NULL);
407 ast_statsd_log_string(args.statistic_name, args.metric_type, args.value,
413 static int unload_module(
void)
418 static int load_module(
void)
423 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"StatsD Dialplan Application",
424 .support_level = AST_MODULE_SUPPORT_EXTENDED,
426 .unload = unload_module,
427 .requires =
"res_statsd",
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
String manipulation functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_unregister_application(const char *app)
Unregister an application.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Core PBX routines and definitions.
Support for logging to various files, console and syslog Configuration in file logger.conf.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.