static int rest_show_feed(noit_http_rest_closure_t *restc, int npats, char **pats) { noit_http_session_ctx *ctx = restc->http_ctx; const char *err = "unknown error"; const char *jpath_with_sub; char jlogpath[PATH_MAX], *cp, **subs = NULL; int nsubs, i; noit_log_stream_t feed; jlog_ctx *jctx = NULL; xmlDocPtr doc = NULL; xmlNodePtr root = NULL, subnodes; feed = noit_log_stream_find("feed"); if(!feed) { err = "cannot find feed"; goto error; } jpath_with_sub = noit_log_stream_get_path(feed); strlcpy(jlogpath, jpath_with_sub, sizeof(jlogpath)); cp = strchr(jlogpath, '('); if(cp) *cp = '\0'; jctx = jlog_new(jlogpath); if((nsubs = jlog_ctx_list_subscribers(jctx, &subs)) == -1) { err = jlog_ctx_err_string(jctx); goto error; } doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"feed", NULL); xmlDocSetRootElement(doc, root); subnodes = xmlNewNode(NULL, (xmlChar *)"subscribers"); for(i=0; i<nsubs; i++) { xmlNewChild(subnodes, NULL, (xmlChar *)"subscriber", (xmlChar *)subs[i]); } xmlAddChild(root, subnodes); noit_http_response_ok(restc->http_ctx, "text/xml"); noit_http_response_xml(restc->http_ctx, doc); noit_http_response_end(restc->http_ctx); if(subs) jlog_ctx_list_subscribers_dispose(jctx, subs); xmlFreeDoc(doc); jlog_ctx_close(jctx); return 0; error: if(doc) xmlFreeDoc(doc); if(subs) jlog_ctx_list_subscribers_dispose(jctx, subs); noit_http_response_server_error(ctx, "text/plain"); noit_http_response_append(ctx, err, strlen(err)); noit_http_response_end(ctx); if(jctx) jlog_ctx_close(jctx); return 0; }
static int jlog_logio_reopen(noit_log_stream_t ls) { char **subs; jlog_asynch_ctx *actx = ls->op_ctx; pthread_rwlock_t *lock = ls->lock; pthread_attr_t tattr; int i; /* reopening only has the effect of removing temporary subscriptions */ /* (they start with ~ in our hair-brained model */ if(lock) pthread_rwlock_wrlock(lock); if(jlog_ctx_list_subscribers(actx->log, &subs) == -1) goto bail; for(i=0;subs[i];i++) if(subs[i][0] == '~') jlog_ctx_remove_subscriber(actx->log, subs[i]); jlog_ctx_list_subscribers_dispose(actx->log, subs); jlog_logio_cleanse(ls); bail: if(lock) pthread_rwlock_unlock(lock); pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); if(pthread_create(&actx->writer, NULL, jlog_logio_asynch_writer, ls) != 0) return -1; return 0; }
static int jlog_logio_open(noit_log_stream_t ls) { char path[PATH_MAX], *sub, **subs, *p; jlog_asynch_ctx *actx; jlog_ctx *log = NULL; pthread_attr_t tattr; int i, listed, found; if(jlog_lspath_to_fspath(ls, path, sizeof(path), &sub) <= 0) return -1; log = jlog_new(path); if(!log) return -1; jlog_set_error_func(log, noit_log_jlog_err, ls); /* Open the writer. */ if(jlog_ctx_open_writer(log)) { /* If that fails, we'll give one attempt at initiailizing it. */ /* But, since we attempted to open it as a writer, it is tainted. */ /* path: close, new, init, close, new, writer, add subscriber */ jlog_ctx_close(log); log = jlog_new(path); jlog_set_error_func(log, noit_log_jlog_err, ls); if(jlog_ctx_init(log)) { noitL(noit_error, "Cannot init jlog writer: %s\n", jlog_ctx_err_string(log)); jlog_ctx_close(log); return -1; } /* After it is initialized, we can try to reopen it as a writer. */ jlog_ctx_close(log); log = jlog_new(path); jlog_set_error_func(log, noit_log_jlog_err, ls); if(jlog_ctx_open_writer(log)) { noitL(noit_error, "Cannot open jlog writer: %s\n", jlog_ctx_err_string(log)); jlog_ctx_close(log); return -1; } } /* Add or remove subscribers according to the current configuration. */ listed = jlog_ctx_list_subscribers(log, &subs); if(listed == -1) { noitL(noit_error, "Cannot list jlog subscribers: %s\n", jlog_ctx_err_string(log)); return -1; } if(sub) { /* Match all configured subscribers against jlog's list. */ for(p=strtok(sub, ",");p;p=strtok(NULL, ",")) { for(i=0;i<listed;i++) { if((subs[i]) && (strcmp(p, subs[i]) == 0)) { free(subs[i]); subs[i] = NULL; break; } } if(i == listed) jlog_ctx_add_subscriber(log, p, JLOG_BEGIN); } /* Remove all unmatched subscribers. */ for(i=0;i<listed;i++) { if(subs[i]) { jlog_ctx_remove_subscriber(log, subs[i]); free(subs[i]); subs[i] = NULL; } } free(subs); subs = NULL; } else { /* Remove all subscribers other than DEFAULT_JLOG_SUBSCRIBER. */ found = 0; for(i=0;i<listed;i++) { if((subs[i]) && (strcmp(DEFAULT_JLOG_SUBSCRIBER, subs[i]) == 0)) { found = 1; continue; } jlog_ctx_remove_subscriber(log, subs[i]); } /* Add DEFAULT_JLOG_SUBSCRIBER if it wasn't already on the jlog's list. */ if(!found) jlog_ctx_add_subscriber(log, DEFAULT_JLOG_SUBSCRIBER, JLOG_BEGIN); jlog_ctx_list_subscribers_dispose(log, subs); } actx = calloc(1, sizeof(*actx)); actx->log = log; ls->op_ctx = actx; pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); if(pthread_create(&actx->writer, NULL, jlog_logio_asynch_writer, ls) != 0) return -1; /* We do this to clean things up */ jlog_logio_reopen(ls); return 0; }
static int process_jlog(const char *file, const char *sub) { jlog_ctx *log = jlog_new(file); if (add_subscriber) { if (jlog_ctx_add_subscriber(log, add_subscriber, JLOG_BEGIN)) { fprintf(stderr, "Could not add subscriber '%s': %s\n", add_subscriber, jlog_ctx_err_string(log)); } else { OUT("Added subscriber '%s'\n", add_subscriber); } } if (remove_subscriber) { if (jlog_ctx_remove_subscriber(log, remove_subscriber) <= 0) { fprintf(stderr, "Could not erase subscriber '%s': %s\n", remove_subscriber, jlog_ctx_err_string(log)); } else { OUT("Erased subscriber '%s'\n", remove_subscriber); } } if (!sub) { if (jlog_ctx_open_writer(log)) { fprintf(stderr, "error opening '%s'\n", file); return 0; } } else { if (jlog_ctx_open_reader(log, sub)) { fprintf(stderr, "error opening '%s'\n", file); return 0; } } if (show_progress) { char buff[20], buff2[20], buff3[20]; jlog_id id, id2, id3; jlog_get_checkpoint(log, sub, &id); if (jlog_ctx_last_log_id(log, &id3)) { fprintf(stderr, "jlog_error: %s\n", jlog_ctx_err_string(log)); fprintf(stderr, "error calling jlog_ctx_last_log_id\n"); } jlog_snprint_logid(buff, sizeof(buff), &id); jlog_snprint_logid(buff3, sizeof(buff3), &id3); OUT("--------------------\n" " Perspective of the '%s' subscriber\n" " current checkpoint: %s\n" " Last write: %s\n", sub, buff, buff3); if (jlog_ctx_read_interval(log, &id, &id2) < 0) { fprintf(stderr, "jlog_error: %s\n", jlog_ctx_err_string(log)); } jlog_snprint_logid(buff, sizeof(buff), &id); jlog_snprint_logid(buff2, sizeof(buff2), &id2); OUT(" next interval: [%s, %s]\n" "--------------------\n\n", buff, buff2); } if (show_subscribers) { char **list; int i; jlog_ctx_list_subscribers(log, &list); for (i = 0; list[i]; i++) { char buff[20]; jlog_id id; jlog_get_checkpoint(log, list[i], &id); jlog_snprint_logid(buff, sizeof(buff), &id); OUT("\t%32s @ %s\n", list[i], buff); } jlog_ctx_list_subscribers_dispose(log, list); } if (show_files) { struct dirent *de; DIR *dir; dir = opendir(file); if (!dir) { fprintf(stderr, "error opening '%s'\n", file); return 0; } while ((de = readdir(dir)) != NULL) { uint32_t logid; if (is_datafile(de->d_name, &logid)) { char fullfile[MAXPATHLEN]; char fullidx[MAXPATHLEN]; struct stat sb; int readers; snprintf(fullfile, sizeof(fullfile), "%s/%s", file, de->d_name); snprintf(fullidx, sizeof(fullidx), "%s/%s" INDEX_EXT, file, de->d_name); if (stat(fullfile, &sb)) { OUT("\t%8s [error stat(2)ing file: %s\n", de->d_name, strerror(errno)); } else { readers = __jlog_pending_readers(log, logid); OUT("\t%8s [%ju bytes] %d pending readers\n", de->d_name, sb.st_size, readers); if (show_index_info) { if (stat(fullidx, &sb)) { OUT("\t\t idx: none\n"); } else { uint32_t marker; int closed; if (jlog_idx_details(log, logid, &marker, &closed)) { OUT("\t\t idx: error\n"); } else { OUT("\t\t idx: %u messages (%08x), %s\n", marker, marker, closed ? "closed" : "open"); } } } if (analyze_datafiles) { analyze_datafile(log, logid); } if (readers == 0 && cleanup) { unlink(fullfile); unlink(fullidx); } } } } closedir(dir); } jlog_ctx_close(log); }