Skip to content

Commit

Permalink
Fix OpenTSDB#773 - Add global_annotations to graphs
Browse files Browse the repository at this point in the history
Fixed a bug in which global_annotations were ignored by
GraphHandler.java (and thus, were not rendered by gnuplot). Added async
call to hbase to retrieve global annotations when required in a similar
fashion as that of QueryRpc.java.

Note: Since both GraphHandler.java and QueryRpc.java implement (similar)
query-processing logic, all of this should be unified in the future
(requires a large refactor to split all query logic with visualization
logic).
  • Loading branch information
HugoMFernandes committed Apr 15, 2016
1 parent 08acb73 commit 8bb0a90
Showing 1 changed file with 49 additions and 22 deletions.
71 changes: 49 additions & 22 deletions src/tsd/GraphHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,15 @@
import net.opentsdb.core.TSDB;
import net.opentsdb.core.TSQuery;
import net.opentsdb.graph.Plot;
import net.opentsdb.meta.Annotation;
import net.opentsdb.stats.Histogram;
import net.opentsdb.stats.StatsCollector;
import net.opentsdb.utils.DateTime;
import net.opentsdb.utils.JSON;

import com.stumbleupon.async.Callback;
import com.stumbleupon.async.Deferred;

/**
* Stateless handler of HTTP graph requests (the {@code /q} endpoint).
*/
Expand Down Expand Up @@ -123,6 +127,10 @@ public void execute(final TSDB tsdb, final HttpQuery query) {
}
}

// TODO(HugoMFernandes): Most of this (query-related) logic is implemented in
// net.opentsdb.tsd.QueryRpc.java (which actually does this asynchronously),
// so we should refactor both classes to split the actual logic used to
// generate the data from the actual visualization (removing all duped code).
private void doGraph(final TSDB tsdb, final HttpQuery query)
throws IOException {
final String basepath = getGnuplotBasePath(tsdb, query);
Expand Down Expand Up @@ -154,10 +162,15 @@ private void doGraph(final TSDB tsdb, final HttpQuery query)
if (!nocache && isDiskCacheHit(query, end_time, max_age, basepath)) {
return;
}
Query[] tsdbqueries;
List<String> options;
tsdbqueries = parseQuery(tsdb, query);
options = query.getQueryStringParams("o");

// Parse TSQuery from HTTP query
final TSQuery tsquery = QueryRpc.parseQuery(tsdb, query);
tsquery.validateAndSetQuery();

// Build the queries for the parsed TSQuery
Query[] tsdbqueries = tsquery.buildQueries(tsdb);

List<String> options = query.getQueryStringParams("o");
if (options == null) {
options = new ArrayList<String>(tsdbqueries.length);
for (int i = 0; i < tsdbqueries.length; i++) {
Expand Down Expand Up @@ -212,9 +225,37 @@ private void doGraph(final TSDB tsdb, final HttpQuery query)
return;
}

final RunGnuplot rungnuplot = new RunGnuplot(query, max_age, plot, basepath,
aggregated_tags, npoints);

class ErrorCB implements Callback<Object, Exception> {
public Object call(final Exception e) throws Exception {
LOG.info("Failed to retrieve global annotations: ", e);
throw e;
}
}

class GlobalCB implements Callback<Object, List<Annotation>> {
public Object call(final List<Annotation> globalAnnotations) throws Exception {
rungnuplot.plot.setGlobals(globalAnnotations);
execGnuplot(rungnuplot, query);

return null;
}
}

// Fetch global annotations, if needed
if (!tsquery.getNoAnnotations() && tsquery.getGlobalAnnotations()) {
Annotation.getGlobalAnnotations(tsdb, start_time, end_time)
.addCallback(new GlobalCB()).addErrback(new ErrorCB());
} else {
execGnuplot(rungnuplot, query);
}
}

private void execGnuplot(RunGnuplot rungnuplot, HttpQuery query) {
try {
gnuplot.execute(new RunGnuplot(query, max_age, plot, basepath,
aggregated_tags, npoints));
gnuplot.execute(rungnuplot);
} catch (RejectedExecutionException e) {
query.internalError(new Exception("Too many requests pending,"
+ " please try again later", e));
Expand Down Expand Up @@ -354,7 +395,7 @@ private String getGnuplotBasePath(final TSDB tsdb, final HttpQuery query) {
qs.remove("png");
qs.remove("json");
qs.remove("ascii");
return tsdb.getConfig().getDirectoryName("tsd.http.cachedir") +
return tsdb.getConfig().getDirectoryName("tsd.http.cachedir") +
Integer.toHexString(qs.hashCode());
}

Expand Down Expand Up @@ -841,21 +882,7 @@ private static void printMetricHeader(final PrintWriter writer, final String met
writer.print(timestamp / 1000L);
writer.print(' ');
}

/**
* Parses the {@code /q} query in a list of {@link Query} objects.
* @param tsdb The TSDB to use.
* @param query The HTTP query for {@code /q}.
* @return The corresponding {@link Query} objects.
* @throws BadRequestException if the query was malformed.
* @throws IllegalArgumentException if the metric or tags were malformed.
*/
private static Query[] parseQuery(final TSDB tsdb, final HttpQuery query) {
final TSQuery q = QueryRpc.parseQuery(tsdb, query);
q.validateAndSetQuery();
return q.buildQueries(tsdb);
}


private static final PlotThdFactory thread_factory = new PlotThdFactory();

private static final class PlotThdFactory implements ThreadFactory {
Expand Down

0 comments on commit 8bb0a90

Please # to comment.