[papertrail] use the curl_looper

This commit is contained in:
Timothy Stack 2015-08-02 20:12:21 -07:00
parent 9555ad911a
commit e9a96caf09
6 changed files with 113 additions and 141 deletions

View File

@ -57,7 +57,7 @@ public:
template<typename F>
auto_mem(F free_func)
: am_ptr(NULL), am_free_func((void(*) (void *))free_func) { };
: am_ptr(NULL), am_free_func((free_func_t)free_func) { };
~auto_mem()
{
@ -102,7 +102,7 @@ public:
{
if (this->am_ptr != ptr) {
if (this->am_ptr != NULL) {
this->am_free_func(this->am_ptr);
this->am_free_func((void *)this->am_ptr);
}
this->am_ptr = ptr;
}

View File

@ -2679,13 +2679,15 @@ int main(int argc, char *argv[])
}
if (!lnav_data.ld_pt_search.empty()) {
lnav_data.ld_pt_proc.reset(new papertrail_proc(lnav_data.ld_pt_search.substr(3)));
if (!lnav_data.ld_pt_proc->start()) {
fprintf(stderr, "error:%s\n", lnav_data.ld_pt_proc->ptp_error.c_str());
return EXIT_FAILURE;
}
#ifdef HAVE_LIBCURL
auto_ptr<papertrail_proc> pt(new papertrail_proc(lnav_data.ld_pt_search.substr(3)));
lnav_data.ld_file_names.insert(
make_pair(lnav_data.ld_pt_search, lnav_data.ld_pt_proc->ptp_fd.release()));
make_pair(lnav_data.ld_pt_search, pt->copy_fd().release()));
lnav_data.ld_curl_looper.add_request(pt.release());
#else
fprintf(stderr, "error: lnav not compiled with libcurl\n");
retval = EXIT_FAILURE;
#endif
}
if (lnav_data.ld_file_names.empty() && !(lnav_data.ld_flags & LNF_HELP)) {

View File

@ -237,7 +237,6 @@ struct _lnav_data {
std::list<pid_t> ld_children;
std::list<piper_proc *> ld_pipers;
std::auto_ptr<papertrail_proc> ld_pt_proc;
xterm_mouse ld_mouse;
term_extra ld_term_extra;

View File

@ -1135,6 +1135,7 @@ static string com_open(string cmdline, vector<string> &args)
string fn = wordmem->we_wordv[lpc];
if (startswith(fn, "pt:")) {
#ifdef HAVE_LIBCURL
for (list<logfile *>::iterator iter = lnav_data.ld_files.begin();
iter != lnav_data.ld_files.end();
++iter) {
@ -1145,18 +1146,19 @@ static string com_open(string cmdline, vector<string> &args)
}
}
lnav_data.ld_curl_looper.close_request("papertrailapp.com");
auto_ptr<papertrail_proc> pt(new papertrail_proc(fn.substr(3)));
lnav_data.ld_pt_search = fn;
lnav_data.ld_pt_proc.reset(new papertrail_proc(lnav_data.ld_pt_search.substr(3)));
if (!lnav_data.ld_pt_proc->start()) {
retval = "error:" + lnav_data.ld_pt_proc->ptp_error;
break;
}
lnav_data.ld_file_names.insert(
make_pair(lnav_data.ld_pt_search, lnav_data.ld_pt_proc->ptp_fd.release()));
make_pair(lnav_data.ld_pt_search, pt->copy_fd().release()));
lnav_data.ld_curl_looper.add_request(pt.release());
ensure_view(&lnav_data.ld_views[LNV_LOG]);
retval = "info: opened papertrail query";
#else
retval = "error: lnav not compiled with libcurl";
#endif
continue;
}

View File

@ -33,13 +33,12 @@
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
#include "papertrail_proc.hh"
#include "yajl/api/yajl_parse.h"
static const int POLL_DELAY = 2;
static const char *PT_SEARCH_URL = "https://papertrailapp.com/api/v1/events/search.json?min_id=%s&q=%s";
const char *papertrail_proc::PT_SEARCH_URL =
"https://papertrailapp.com/api/v1/events/search.json?min_id=%s&q=%s";
static int read_max_id(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
{
@ -80,7 +79,7 @@ static int read_event_field(yajlpp_parse_context *ypc, const unsigned char *str,
return 1;
}
static int json_map_start(void *ctx)
int papertrail_proc::json_map_start(void *ctx)
{
yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
@ -92,7 +91,7 @@ static int json_map_start(void *ctx)
return 1;
}
static int json_map_end(void *ctx)
int papertrail_proc::json_map_end(void *ctx)
{
yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
@ -136,112 +135,17 @@ void papertrail_proc::yajl_writer(void *context, const char *str, size_t len)
write(ptp->ptp_fd, str, len);
}
bool papertrail_proc::start(void)
long papertrail_proc::complete(CURLcode result)
{
#ifndef HAVE_LIBCURL
return false;
#else
this->ptp_api_key = getenv("PAPERTRAIL_API_TOKEN");
yajl_reset(this->ptp_jhandle.in());
if (this->ptp_api_key == NULL) {
this->ptp_error = "papertrail search requested, but PAPERTRAIL_API_TOKEN is not set";
return false;
if (result != CURLE_OK) {
return -1;
}
char piper_tmpname[PATH_MAX];
const char *tmpdir;
this->set_url();
if ((tmpdir = getenv("TMPDIR")) == NULL) {
tmpdir = _PATH_VARTMP;
}
snprintf(piper_tmpname, sizeof(piper_tmpname),
"%s/lnav.papertrail.XXXXXX",
tmpdir);
if ((this->ptp_fd = mkstemp(piper_tmpname)) == -1) {
this->ptp_error = "Unable to make temporary file for papertrail";
return false;
}
unlink(piper_tmpname);
fcntl(this->ptp_fd.get(), F_SETFD, FD_CLOEXEC);
if ((this->ptp_child = fork()) < 0) {
this->ptp_error = "Unable to fork papertrail child";
return false;
}
signal(SIGTERM, SIG_DFL);
signal(SIGINT, SIG_DFL);
if (this->ptp_child != 0) {
return true;
}
try {
this->child_body();
} catch (...) {
fprintf(stderr, "papertrail child failed");
}
_exit(0);
#endif
};
void papertrail_proc::child_body()
{
#ifdef HAVE_LIBCURL
int nullfd;
nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, STDIN_FILENO);
dup2(nullfd, STDOUT_FILENO);
auto_mem<CURL> handle(curl_easy_cleanup);
yajlpp_parse_context ypc("papertrailapp.com", FORMAT_HANDLERS);
ypc.ypc_alt_callbacks.yajl_start_map = json_map_start;
ypc.ypc_alt_callbacks.yajl_end_map = json_map_end;
yajl_handle jhandle = yajl_alloc(&ypc.ypc_callbacks, NULL, &ypc);
auto_mem<yajl_gen_t> gen(yajl_gen_free);
this->ptp_gen = gen = yajl_gen_alloc(NULL);
ypc.ypc_userdata = this;
yajl_gen_config(gen, yajl_gen_print_callback, yajl_writer, this);
const char *quoted_search = curl_easy_escape(
handle, this->ptp_search.c_str(), this->ptp_search.size());
bool looping = true;
while (looping) {
auto_mem<char> url;
handle = curl_easy_init();
asprintf(url.out(), PT_SEARCH_URL, this->ptp_last_max_id.c_str(),
quoted_search);
if (!url.in()) {
break;
}
curl_easy_setopt(handle, CURLOPT_URL, url.in());
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, jhandle);
auto_mem<struct curl_slist> chunk(curl_slist_free_all);
auto_mem<char> token_header;
asprintf(token_header.out(), "X-Papertrail-Token: %s", this->ptp_api_key);
if (!token_header.in()) {
break;
}
chunk = curl_slist_append(chunk, token_header.in());
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, chunk.in());
curl_easy_perform(handle);
yajl_reset(jhandle);
sleep(POLL_DELAY);
}
#endif
return 3000;
}
#endif

View File

@ -32,6 +32,8 @@
#ifndef LNAV_PAPERTRAIL_PROC_HH
#define LNAV_PAPERTRAIL_PROC_HH
#ifdef HAVE_LIBCURL
#include <fcntl.h>
#include <paths.h>
#include <signal.h>
@ -44,45 +46,108 @@
#include "auto_fd.hh"
#include "auto_mem.hh"
#include "yajlpp.hh"
#include "curl_looper.hh"
#include "line_buffer.hh"
class papertrail_proc {
class papertrail_proc : public curl_request {
public:
papertrail_proc(const std::string &search)
: ptp_search(search), ptp_child(-1) {
: curl_request("papertrailapp.com"),
ptp_jcontext(this->cr_name, FORMAT_HANDLERS),
ptp_jhandle(yajl_free),
ptp_gen(yajl_gen_free),
ptp_search(search),
ptp_quoted_search(curl_free),
ptp_header_list(curl_slist_free_all) {
char piper_tmpname[PATH_MAX];
const char *tmpdir;
if ((tmpdir = getenv("TMPDIR")) == NULL) {
tmpdir = _PATH_VARTMP;
}
snprintf(piper_tmpname, sizeof(piper_tmpname),
"%s/lnav.pt.XXXXXX",
tmpdir);
if ((this->ptp_fd = mkstemp(piper_tmpname)) == -1) {
return;
}
unlink(piper_tmpname);
this->ptp_jcontext.ypc_alt_callbacks.yajl_start_map = json_map_start;
this->ptp_jcontext.ypc_alt_callbacks.yajl_end_map = json_map_end;
this->ptp_jcontext.ypc_userdata = this;
this->ptp_jhandle = yajl_alloc(&this->ptp_jcontext.ypc_callbacks, NULL, &this->ptp_jcontext);
this->ptp_gen = yajl_gen_alloc(NULL);
yajl_gen_config(this->ptp_gen, yajl_gen_print_callback, yajl_writer, this);
curl_easy_setopt(this->cr_handle, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(this->cr_handle, CURLOPT_WRITEDATA, this->ptp_jhandle.in());
curl_easy_setopt(this->cr_handle, CURLOPT_FAILONERROR, 1L);
this->ptp_api_key = getenv("PAPERTRAIL_API_TOKEN");
if (this->ptp_api_key == NULL) {
this->ptp_error = "papertrail search requested, but PAPERTRAIL_API_TOKEN is not set";
}
this->ptp_quoted_search = curl_easy_escape(this->cr_handle,
this->ptp_search.c_str(),
this->ptp_search.size());
asprintf(this->ptp_token_header.out(),
"X-Papertrail-Token: %s",
this->ptp_api_key);
this->ptp_header_list = curl_slist_append(this->ptp_header_list,
this->ptp_token_header.in());
curl_easy_setopt(this->cr_handle, CURLOPT_HTTPHEADER, this->ptp_header_list.in());
this->set_url();
};
~papertrail_proc() {
// TODO: refactor this with piper_proc
if (this->ptp_child > 0) {
int status;
kill(this->ptp_child, SIGTERM);
while (waitpid(this->ptp_child, &status, 0) < 0 && (errno == EINTR)) {
;
}
this->ptp_child = -1;
}
}
bool start(void);
void child_body(void);
auto_fd copy_fd() const {
return this->ptp_fd;
};
long complete(CURLcode result);
void set_url() {
asprintf(this->ptp_url.out(),
PT_SEARCH_URL,
this->ptp_last_max_id.c_str(),
this->ptp_quoted_search.in());
curl_easy_setopt(this->cr_handle, CURLOPT_URL, this->ptp_url.in());
};
static size_t write_cb(void *contents, size_t size, size_t nmemb, void *userp);
static int json_map_start(void *ctx);
static int json_map_end(void *ctx);
static void yajl_writer(void *context, const char *str, size_t len);
static struct json_path_handler FORMAT_HANDLERS[];
static const char *PT_SEARCH_URL;
yajlpp_parse_context ptp_jcontext;
auto_mem<yajl_handle_t> ptp_jhandle;
auto_mem<yajl_gen_t> ptp_gen;
const char *ptp_api_key;
const std::string ptp_search;
auto_mem<const char> ptp_quoted_search;
auto_mem<char> ptp_url;
auto_mem<char> ptp_token_header;
auto_mem<struct curl_slist> ptp_header_list;
auto_fd ptp_fd;
pid_t ptp_child;
line_buffer ptp_line_buffer;
yajl_gen ptp_gen;
std::string ptp_last_max_id;
std::string ptp_error;
};
#endif
#endif //LNAV_PAPERTRAIL_PROC_HH