From 51da8bc531304f253258aedf8293b885328dfdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Mon, 29 Apr 2013 10:18:48 +0200 Subject: [PATCH] * report more data in airbrake plugin * preserve text version of backtrace (there might be multiple alarm handlers for any segfault) * fix reload errors --- plugins/airbrake/airbrake_plugin.c | 143 +++++++++++++++++------------ 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/plugins/airbrake/airbrake_plugin.c b/plugins/airbrake/airbrake_plugin.c index 87994e8f..535ee820 100644 --- a/plugins/airbrake/airbrake_plugin.c +++ b/plugins/airbrake/airbrake_plugin.c @@ -8,6 +8,7 @@ struct uwsgi_airbrake_config { int first; char *arg; char *apikey; + char *env; }; struct uwsgi_airbrake_opt { @@ -28,9 +29,14 @@ static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg, uacc->apikey = arg; } +static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) { + uacc->env = arg; +} + static struct uwsgi_airbrake_opt uaco[] = { {"url", CURLOPT_URL, NULL}, {"apikey", 0, uwsgi_airbrake_set_apikey}, + {"env", 0, uwsgi_airbrake_set_env}, {"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl}, {"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int}, {"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int}, @@ -65,78 +71,89 @@ end: *equal = '='; } -static size_t uwsgi_airbrake_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) { - struct uwsgi_thread *ut = (struct uwsgi_thread *) userp; - size_t full_size = size * nmemb; - size_t remains = ut->len - ut->pos; +char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) { - if (remains == 0) return 0; - - if (ut->custom0 == 0) { - size_t newline = 0; - size_t required = 1; - char *addr = ptr; - if (required > full_size) goto skip; - -skip: - if (newline > 0) { - *addr = '\n'; - } - ut->custom0 = 1; - return required; - } - - if (full_size < remains) { - remains = full_size; - } - - memcpy(ptr, ut->buf + ut->pos, remains); - ut->pos += remains; - - return remains; -} - -static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apikey) { + struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data; xmlChar *xmlbuff; int buffersize; xmlDocPtr doc = NULL; xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL; - char *msg = uwsgi_str("uWSGI segfault"); + char *msg = NULL; doc = xmlNewDoc(BAD_CAST "1.0"); notice_node = xmlNewNode(NULL, BAD_CAST "notice"); xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3"); xmlDocSetRootElement(doc, notice_node); - xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST apikey); + xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey); node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL); xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI"); xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION); xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi"); + // request env + node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL); + node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL); + + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version"); + + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version"); + + struct utsname uuts; +#ifdef __sun__ + if (uname(&uuts) < 0) { +#else + if (uname(&uuts)) { +#endif + uwsgi_error("uname()"); + } + else { + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname"); + + char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version); + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version"); + free(os_version); + + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine"); + + line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename); + xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename"); + + } + // end request env + + node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL); + xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION); + if (uacc->env) { + xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env); + } + else { + xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION); + } + errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL); xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError"); node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL); - char *p = strtok(ut->buf, "\n"); - int i = 0; + char *ctx = NULL; + char *text = uwsgi_str(ut->buf); + char *p = strtok_r(text, "\n", &ctx); while (p) { // skip log messages if (!uwsgi_startswith(p, "***", 3)) goto next; - i++; - // skip last 2 backtrace lines, real bt starts after them - if (i <= 2) { - goto next; - } // backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555] // we take binary/lib as filename // and extract method name from remaining string char *n = strchr(p, '('); if (n) { - line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL); *n = 0; char *pls = strchr(n+1, '+'); @@ -144,8 +161,15 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike *pls = 0; } - if (i == 3) { - free(msg); + if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) { + goto next; + } + else if (!strcmp("uwsgi_fpe", n+1)) { + msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p); + goto next; + } + + if (!msg) { if (strlen(n+1)) { msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p); } @@ -155,6 +179,12 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike } } + // skip empty lines + if (!p) + goto next; + + line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL); + if ((n+1)[0] == ')') { xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()"); } @@ -164,28 +194,23 @@ static void uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut, char *apike xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p); - xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0"); + //xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0"); } next: - p = strtok(NULL, "\n"); + p = strtok_r(NULL, "\n", &ctx); } xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg); - node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL); - xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION); - xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION); - xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); xmlFreeDoc(doc); xmlCleanupParser(); xmlMemoryDump(); - - free(ut->buf); free(msg); - ut->buf = (char *) xmlbuff; - ut->len = strlen(ut->buf); + free(text); + + return (char *) xmlbuff; } @@ -199,7 +224,7 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) { curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); - curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_airbrake_read_callback); + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_READDATA, ut); curl_easy_setopt(curl, CURLOPT_POST, 1L); struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:"); @@ -218,7 +243,8 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) { for(;;) { int ret = event_queue_wait(ut->queue, -1, &interesting_fd); - if (ret <= 0) continue; + if (ret < 0) return; + if (ret == 0) continue; if (interesting_fd != ut->pipe[1]) continue; ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize); if (rlen <= 0) continue; @@ -226,19 +252,20 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) { ut->len = (size_t) rlen; ut->custom0 = 0; - uwsgi_format_airbrake_backtrace(ut, uacc->apikey); + char *notice = uwsgi_format_airbrake_backtrace(ut); curl_slist_append(expect, "Accept: */*"); curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ut->buf); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, ut->len); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice)); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } + free(notice); } }