Skip to content

Commit

Permalink
Align with stock statsd plugin, add extra tags, add metric whitelisti…
Browse files Browse the repository at this point in the history
…ng (#1)

- After this plugin was created, the stock statsd plugin in the uWSGI repo was updated to support disabling worker metrics and forcing all metrics to be gauges. The first change this commit makes is to port those two changes into this plugin.
- We only use 3-4 metrics of the dozens that uWSGI records. I've added a whitelisting feature that enables us to filter out undesired metrics, reducing our use of Datadog custom metrics.
- We need the ability to specify additional tags, so that we can more easily graph uWSGI metrics belonging to specific applications (or group uWSGI metrics by application). I've added that capability here.

This change is completely backwards compatible. If a user has a config such as the following, the plugin behavior will continue in the exact same manner as before this change:

```
stats-push=dogstatsd:localhost:8135,uwsgi
```

Now, however, we can add more advanced configuration options, like below, to alter the plugin behavior:

```
stats-push=dogstatsd:localhost:8135,uwsgi
dogstatsd-extra-tags=app:foo_service
dogstatsd-no-workers=true
dogstatsd-whitelist-metric=core.busy_workers
dogstatsd-whitelist-metric=core.idle_workers
dogstatsd-whitelist-metric=core.overloaded
dogstatsd-whitelist-metric=socket.listen_queue
```
  • Loading branch information
nickwilliams-eventbrite authored and jshuping committed Oct 15, 2019
1 parent 1a04f78 commit 9033133
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 4 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ wsgi-file = app.py
...
```

You can also add additional tags or filter which metrics are published (or how they are published) using one or more optional configuration options:

```ini
stats-push = dogstatsd:127.0.0.1:8125,myapp
dogstatsd-extra-tags = app:foo_service,instance:1
dogstatsd-no-workers = true
dogstatsd-all_gauges = true
dogstatsd-whitelist-metric = core.busy_workers
dogstatsd-whitelist-metric = core.idle_workers
dogstatsd-whitelist-metric = core.overloaded
dogstatsd-whitelist-metric = socket.listen_queue
```

This will begin producing metrics with the prefix defined in the configuration, `myapp` here:

```console
Expand Down
43 changes: 39 additions & 4 deletions plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ exports values exposed by the metric subsystem to a Datadog Agent StatsD server

extern struct uwsgi_server uwsgi;

struct dogstatsd_config {
int no_workers;
int all_gauges;
char *extra_tags;
struct uwsgi_string_list *metrics_whitelist;
} u_dogstatsd_config;

static struct uwsgi_option dogstatsd_options[] = {
{"dogstatsd-no-workers", no_argument, 0, "disable generation of single-worker metrics", uwsgi_opt_true, &u_dogstatsd_config.no_workers, 0},
{"dogstatsd-all-gauges", no_argument, 0, "push all metrics to dogstatsd as gauges", uwsgi_opt_true, &u_dogstatsd_config.all_gauges, 0},
{"dogstatsd-extra-tags", required_argument, 0, "add these extra tags to all metrics (example: foo:bar,qin,baz:qux)", uwsgi_opt_set_str, &u_dogstatsd_config.extra_tags, 0},
{"dogstatsd-whitelist-metric", required_argument, 0, "use one or more times to send only the whitelisted metrics (do not add prefix)", uwsgi_opt_add_string_list, &u_dogstatsd_config.metrics_whitelist, 0},
UWSGI_END_OF_OPTIONS
};

// configuration of a dogstatsd node
struct dogstatsd_node {
int fd;
Expand Down Expand Up @@ -49,6 +64,11 @@ static int dogstatsd_generate_tags(char *metric, size_t metric_len, char *datato
if (!token)
return -1;

if (u_dogstatsd_config.extra_tags && strlen(u_dogstatsd_config.extra_tags)) {
strncat(datadog_tags, tag_prefix, (MAX_BUFFER_SIZE - strlen(datadog_tags) - strlen(tag_prefix) - 1));
strncat(datadog_tags, u_dogstatsd_config.extra_tags, (MAX_BUFFER_SIZE - strlen(datadog_tags) - strlen(u_dogstatsd_config.extra_tags) - 1));
}

while (token != NULL && metric_len >= metric_offset) {

metric_offset += strlen(token) + 1;
Expand Down Expand Up @@ -126,6 +146,10 @@ static int dogstatsd_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pus
if (extracted_tags < 0)
return -1;

if (u_dogstatsd_config.metrics_whitelist && !uwsgi_string_list_has_item(u_dogstatsd_config.metrics_whitelist, datatog_metric_name, strlen(datatog_metric_name))) {
return 0;
}

if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;

Expand Down Expand Up @@ -191,12 +215,22 @@ static void stats_pusher_dogstatsd(struct uwsgi_stats_pusher_instance *uspi, tim
}

// we use the same buffer for all of the packets
if (uwsgi.metrics_cnt <= 0) {
uwsgi_log(" *** WARNING: Dogstatsd stats pusher configured but there are no metrics to push ***\n");
return;
}

struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
if (u_dogstatsd_config.no_workers && !uwsgi_starts_with(um->name, um->name_len, "worker.", 7)) {
um = um->next;
continue;
}

uwsgi_rlock(uwsgi.metrics_lock);
// ignore return value
if (um->type == UWSGI_METRIC_GAUGE) {
if (u_dogstatsd_config.all_gauges || um->type == UWSGI_METRIC_GAUGE) {
dogstatsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g");
}
else {
Expand All @@ -214,13 +248,14 @@ static void stats_pusher_dogstatsd(struct uwsgi_stats_pusher_instance *uspi, tim
}

static void dogstatsd_init(void) {
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("dogstatsd", stats_pusher_dogstatsd);
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("dogstatsd", stats_pusher_dogstatsd);
// we use a custom format not the JSON one
usp->raw = 1;
}

struct uwsgi_plugin dogstatsd_plugin = {

.name = "dogstatsd",
.on_load = dogstatsd_init,
.name = "dogstatsd",
.options = dogstatsd_options,
.on_load = dogstatsd_init,
};

0 comments on commit 9033133

Please sign in to comment.