summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-06-15 13:23:35 +0200
committerGitHub <noreply@github.com>2022-06-15 13:23:35 +0200
commitf1b86b698d629afb08569c9fd0f39dfb1da71f0d (patch)
treede2815334afc9575dffff0423869c276b08351ee
parent9f7b3b4211cdafd9f8fa680443bf7224d974b831 (diff)
parenta0f18f5183b1e43163bbfbbfa6f6fff86149d014 (diff)
Merge pull request #23097 from vespa-engine/bratseth/trace
Bratseth/trace
-rw-r--r--container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java13
-rw-r--r--container-search/abi-spec.json46
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java8
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/querytransform/LiteralBoostSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/querytransform/NormalizingSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/semantics/RuleBase.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/Query.java227
-rw-r--r--container-search/src/main/java/com/yahoo/search/Result.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/Searcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/cluster/ClusterSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/vespa/GroupingExecutor.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/Model.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/Trace.java242
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/context/QueryContext.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java12
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java26
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java8
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchchain/Execution.java4
-rw-r--r--container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java14
-rw-r--r--container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java2
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/querytransform/test/NormalizingSearcherTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/searcher/test/JSONDebugSearcherTestCase.java68
-rw-r--r--container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java84
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/config/test/validxml/root.xml2
-rw-r--r--container-search/src/test/java/com/yahoo/search/searchchain/test/TraceTestCase.java53
-rw-r--r--container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java8
-rw-r--r--container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcherTestCase.java4
37 files changed, 544 insertions, 343 deletions
diff --git a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java
index 8c8b65a4a5a..e370b1f19d3 100644
--- a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java
+++ b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java
@@ -17,6 +17,7 @@ import com.yahoo.search.config.IndexInfoConfig;
import com.yahoo.search.query.Model;
import com.yahoo.search.query.Presentation;
import com.yahoo.search.query.Ranking;
+import com.yahoo.search.query.Trace;
import com.yahoo.search.query.ranking.Diversity;
import com.yahoo.search.query.ranking.MatchPhase;
import com.yahoo.search.query.restapi.ErrorResponse;
@@ -192,11 +193,13 @@ public class GUIHandler extends ThreadedHttpRequestHandler {
json.set("childMap", childMap);
ArrayNode levelZeroParameters = jsonMapper.createArrayNode().add(MinimalQueryInserter.YQL.toString()).add(Query.HITS.toString()).add(Query.OFFSET.toString())
- .add("queryProfile").add(Query.NO_CACHE.toString()).add(Query.GROUPING_SESSION_CACHE.toString())
- .add(Query.SEARCH_CHAIN.toString()).add(Query.TIMEOUT.toString()).add("trace").add("tracelevel")
- .add(Query.TRACE_LEVEL.toString()).add(Query.EXPLAIN_LEVEL.toString()).add("explainlevel").add(Model.MODEL).add(Ranking.RANKING).add("collapse").add("collapsesize").add("collapsefield")
- .add(Presentation.PRESENTATION).add("pos").add("streaming").add("rules").add(RecallSearcher.recallName.toString()).add("user")
- .add("metrics").add("");
+ .add("queryProfile").add(Query.NO_CACHE.toString()).add(Query.GROUPING_SESSION_CACHE.toString())
+ .add(Query.SEARCH_CHAIN.toString()).add(Query.TIMEOUT.toString()).add("trace")
+ .add("tracelevel").add("traceLevel") // TODO: Remove on Vespa 9
+ .add("explainLevel").add("explainlevel") // TODO: Remove on Vespa 9
+ .add(Model.MODEL).add(Ranking.RANKING).add("collapse").add("collapsesize").add("collapsefield")
+ .add(Presentation.PRESENTATION).add("pos").add("streaming").add("rules").add(RecallSearcher.recallName.toString()).add("user")
+ .add("metrics").add("");
json.set("levelZeroParameters", levelZeroParameters);
return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);
diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json
index 6b31c570efa..7f100df4e2c 100644
--- a/container-search/abi-spec.json
+++ b/container-search/abi-spec.json
@@ -1983,6 +1983,7 @@
"public com.yahoo.search.query.Select getSelect()",
"public com.yahoo.search.query.Ranking getRanking()",
"public com.yahoo.search.query.Model getModel()",
+ "public com.yahoo.search.query.Trace getTrace()",
"public com.yahoo.container.jdisc.HttpRequest getHttpRequest()",
"public com.yahoo.search.query.SessionId getSessionId()",
"public com.yahoo.search.query.SessionId getSessionId(java.lang.String)",
@@ -1993,15 +1994,16 @@
"public bridge synthetic java.lang.Object clone()"
],
"fields": [
+ "public com.yahoo.search.query.Trace trace",
"public static final com.yahoo.processing.request.CompoundName OFFSET",
"public static final com.yahoo.processing.request.CompoundName HITS",
"public static final com.yahoo.processing.request.CompoundName QUERY_PROFILE",
"public static final com.yahoo.processing.request.CompoundName SEARCH_CHAIN",
- "public static final com.yahoo.processing.request.CompoundName TRACE_LEVEL",
- "public static final com.yahoo.processing.request.CompoundName EXPLAIN_LEVEL",
"public static final com.yahoo.processing.request.CompoundName NO_CACHE",
"public static final com.yahoo.processing.request.CompoundName GROUPING_SESSION_CACHE",
"public static final com.yahoo.processing.request.CompoundName TIMEOUT",
+ "public static final com.yahoo.processing.request.CompoundName TRACE_LEVEL",
+ "public static final com.yahoo.processing.request.CompoundName EXPLAIN_LEVEL",
"public static final java.util.List nativeProperties"
]
},
@@ -5613,6 +5615,46 @@
"public static final java.lang.String LOWERCASE"
]
},
+ "com.yahoo.search.query.Trace": {
+ "superClass": "java.lang.Object",
+ "interfaces": [
+ "java.lang.Cloneable"
+ ],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public static com.yahoo.search.query.profile.types.QueryProfileType getArgumentType()",
+ "public void <init>(com.yahoo.search.Query)",
+ "public int getLevel()",
+ "public void setLevel(int)",
+ "public boolean isTraceable(int)",
+ "public void setExplainLevel(int)",
+ "public int getExplainLevel()",
+ "public boolean getTimestamps()",
+ "public void setTimestamps(boolean)",
+ "public boolean getQuery()",
+ "public void setQuery(boolean)",
+ "public void trace(java.lang.String, int)",
+ "public void trace(java.lang.Object, int)",
+ "public void trace(java.lang.String, boolean, int)",
+ "public varargs void trace(boolean, int, java.lang.Object[])",
+ "public void traceProperties()",
+ "public com.yahoo.search.query.Trace cloneFor(com.yahoo.search.Query)",
+ "public boolean equals(java.lang.Object)",
+ "public int hashCode()",
+ "public com.yahoo.search.query.Trace clone()",
+ "public java.lang.String toString()",
+ "public bridge synthetic java.lang.Object clone()"
+ ],
+ "fields": [
+ "public static final java.lang.String TRACE",
+ "public static final java.lang.String LEVEL",
+ "public static final java.lang.String EXPLAIN_LEVEL",
+ "public static final java.lang.String TIMESTAMPS",
+ "public static final java.lang.String QUERY"
+ ]
+ },
"com.yahoo.search.query.UniqueRequestId": {
"superClass": "java.lang.Object",
"interfaces": [],
diff --git a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
index 496e057a243..729aebf2fc2 100644
--- a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java
@@ -204,7 +204,7 @@ public class ClusterSearcher extends Searcher {
private void validateQueryTimeout(Query query) {
if (query.getTimeout() <= maxQueryTimeout) return;
- if (query.isTraceable(2)) {
+ if (query.getTrace().isTraceable(2)) {
query.trace("Query timeout (" + query.getTimeout() + " ms) > max query timeout (" +
maxQueryTimeout + " ms). Setting timeout to " + maxQueryTimeout + " ms.", 2);
}
@@ -215,7 +215,7 @@ public class ClusterSearcher extends Searcher {
if ( ! query.getRanking().getQueryCache() ) return;
if (query.getTimeout() <= maxQueryCacheTimeout) return;
- if (query.isTraceable(2)) {
+ if (query.getTrace().isTraceable(2)) {
query.trace("Query timeout (" + query.getTimeout() + " ms) > max query cache timeout (" +
maxQueryCacheTimeout + " ms). Disabling query cache.", 2);
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
index 33ad8d8c9a8..edd11974f8c 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java
@@ -106,7 +106,7 @@ public class FastSearcher extends VespaBackEndSearcher {
return new Result(query,ErrorMessage.createTimeout(e.getMessage()));
} catch (IOException e) {
Result result = new Result(query);
- if (query.getTraceLevel() >= 1)
+ if (query.getTrace().getLevel() >= 1)
query.trace(getName() + " error response: " + result, false, 1);
result.hits().addError(ErrorMessage.createBackendCommunicationError(getName() + " failed: "+ e.getMessage()));
return result;
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
index 584249fa1f3..e184037bc90 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
@@ -190,7 +190,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
Result result = doSearch2(query, execution);
- if (query.getTraceLevel() >= 1)
+ if (query.getTrace().getLevel() >= 1)
query.trace(getName() + " dispatch response: " + result, false, 1);
result.trace(getName());
return result;
@@ -243,7 +243,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
}
void traceQuery(String sourceName, String type, Query query, int offset, int hits, int level, Optional<String> quotedSummaryClass) {
- if ((query.getTraceLevel()<level) || query.properties().getBoolean(TRACE_DISABLE)) return;
+ if ((query.getTrace().getLevel()<level) || query.properties().getBoolean(TRACE_DISABLE)) return;
StringBuilder s = new StringBuilder();
s.append(sourceName).append(" ").append(type).append(" to dispatch: ")
@@ -314,12 +314,12 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
}
query.trace(s.toString(), false, level);
- if (query.isTraceable(level + 1)) {
+ if (query.getTrace().isTraceable(level + 1)) {
query.trace("Current state of query tree: "
+ new TextualQueryRepresentation(query.getModel().getQueryTree().getRoot()),
false, level+1);
}
- if (query.isTraceable(level + 2)) {
+ if (query.getTrace().isTraceable(level + 2)) {
query.trace("YQL+ representation: " + query.yqlRepresentation(), level+2);
}
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java b/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
index 8cc820d8f76..545bb8e777f 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
@@ -21,7 +21,7 @@ import static com.yahoo.prelude.query.parser.Token.Kind.MINUS;
import static com.yahoo.prelude.query.parser.Token.Kind.SPACE;
/**
- * Parser for queries of type all.
+ * Parser for queries of type all and weakAnd.
*
* @author Steinar Knutsen
* @author bratseth
@@ -31,9 +31,9 @@ public class AllParser extends SimpleParser {
private final boolean weakAnd;
/**
- * Creates an And parser
+ * Creates an all/weakAnd parser
*
- * @param weakAnd false to parse into AndItem (by default), true to parse to WeakAnd
+ * @param weakAnd false to parse into AndItem (by default), true to parse to WeakAndItem
*/
public AllParser(ParserEnvironment environment, boolean weakAnd) {
super(environment);
diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/LiteralBoostSearcher.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/LiteralBoostSearcher.java
index 47a5213c041..28d4d9dff67 100644
--- a/container-search/src/main/java/com/yahoo/prelude/querytransform/LiteralBoostSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/querytransform/LiteralBoostSearcher.java
@@ -44,7 +44,7 @@ public class LiteralBoostSearcher extends Searcher {
if (newRankTerms.getItemCount() > 0)
addTopLevelRankTerms(newRankTerms, query);
- if (query.getTraceLevel() >= 2 && newRankTerms.getItemCount() > 0)
+ if (query.getTrace().getLevel() >= 2 && newRankTerms.getItemCount() > 0)
query.trace("Added rank terms for possible literal field matches.", true, 2);
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/NormalizingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/NormalizingSearcher.java
index a847a84e134..b7fd1069a6b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/querytransform/NormalizingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/querytransform/NormalizingSearcher.java
@@ -53,11 +53,11 @@ public class NormalizingSearcher extends Searcher {
}
protected void normalize(Query query, IndexFacts.Session indexFacts) {
- String oldQuery = (query.getTraceLevel() >= 2) ? query.getModel().getQueryTree().getRoot().toString() : null;
+ String oldQuery = (query.getTrace().getLevel() >= 2) ? query.getModel().getQueryTree().getRoot().toString() : null;
normalizeBody(query, indexFacts);
- if (query.getTraceLevel() >= 2 && ! query.getModel().getQueryTree().getRoot().toString().equals(oldQuery))
+ if (query.getTrace().getLevel() >= 2 && ! query.getModel().getQueryTree().getRoot().toString().equals(oldQuery))
query.trace(getFunctionName(), true, 2);
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/semantics/RuleBase.java b/container-search/src/main/java/com/yahoo/prelude/semantics/RuleBase.java
index 4980b035876..5a168d42779 100644
--- a/container-search/src/main/java/com/yahoo/prelude/semantics/RuleBase.java
+++ b/container-search/src/main/java/com/yahoo/prelude/semantics/RuleBase.java
@@ -312,14 +312,14 @@ public class RuleBase {
* If there is an error, this query is destroyed (unusable)
*/
public String analyze(Query query, int traceLevel) {
- int queryTraceLevel = query.getTraceLevel();
+ int queryTraceLevel = query.getTrace().getLevel();
if (traceLevel > 0 && queryTraceLevel == 0)
- query.setTraceLevel(1);
+ query.getTrace().setLevel(1);
matchAutomata(query, traceLevel);
String error = analyzer.evaluate(query, traceLevel);
- query.setTraceLevel(queryTraceLevel);
+ query.getTrace().setLevel(queryTraceLevel);
return error;
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java b/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java
index e25f00bdc80..42a2b4f4e9b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/semantics/SemanticSearcher.java
@@ -84,7 +84,7 @@ public class SemanticSearcher extends Searcher {
if (query.properties().getBoolean(rulesOff))
return execution.search(query);
- int traceLevel = query.properties().getInteger(tracelevelRules, query.getTraceLevel() - 2);
+ int traceLevel = query.properties().getInteger(tracelevelRules, query.getTrace().getLevel() - 2);
if (traceLevel < 0) traceLevel = 0;
RuleBase ruleBase = resolveRuleBase(query);
if (ruleBase == null)
diff --git a/container-search/src/main/java/com/yahoo/search/Query.java b/container-search/src/main/java/com/yahoo/search/Query.java
index dc731669a48..48885e4b3da 100644
--- a/container-search/src/main/java/com/yahoo/search/Query.java
+++ b/container-search/src/main/java/com/yahoo/search/Query.java
@@ -12,10 +12,10 @@ import com.yahoo.search.schema.SchemaInfo;
import com.yahoo.search.dispatch.Dispatcher;
import com.yahoo.search.federation.FederationSearcher;
import com.yahoo.search.query.Model;
+import com.yahoo.search.query.Trace;
import com.yahoo.search.query.ParameterParser;
import com.yahoo.search.query.Presentation;
import com.yahoo.search.query.Properties;
-import com.yahoo.search.query.QueryTree;
import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.Select;
import com.yahoo.search.query.SessionId;
@@ -50,14 +50,11 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* A search query containing all the information required to produce a Result.
@@ -72,7 +69,7 @@ import java.util.logging.Logger;
* </ul>
*
* <p>
- * The properties has three sources
+ * The properties have three sources
* <ol>
* <li>They may be set in some Searcher component already executed for this Query - the properties acts as
* a blackboard for communicating arbitrary objects between Searcher components.
@@ -130,6 +127,9 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
}
+ /** The time this query was created */
+ private long startTime;
+
//-------------- Query properties treated as fields in Query ---------------
/** The offset from the most relevant hits found from this query */
@@ -138,12 +138,6 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
/** The number of hits to return */
private int hits = 10;
- /** The query context level, 0 means no tracing */
- private int traceLevel = 0;
-
- /** The query explain level, 0 means no explaining */
- private int explainLevel = 0;
-
// The timeout to be used when dumping rank features
private static final long dumpTimeout = (6 * 60 * 1000); // 6 minutes
private static final long defaultTimeout = 500;
@@ -181,12 +175,8 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
/** The selection of where-clause and grouping */
private Select select = new Select(this);
- //---------------- Tracing ----------------------------------------------------
-
- private static final Logger log = Logger.getLogger(Query.class.getName());
-
- /** The time this query was created */
- private long startTime;
+ /** How this query should be traced */
+ public Trace trace = new Trace(this);
//---------------- Static property handling ------------------------------------
@@ -195,12 +185,18 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
public static final CompoundName QUERY_PROFILE = new CompoundName("queryProfile");
public static final CompoundName SEARCH_CHAIN = new CompoundName("searchChain");
- public static final CompoundName TRACE_LEVEL = new CompoundName("traceLevel");
- public static final CompoundName EXPLAIN_LEVEL = new CompoundName("explainLevel");
+
public static final CompoundName NO_CACHE = new CompoundName("noCache");
public static final CompoundName GROUPING_SESSION_CACHE = new CompoundName("groupingSessionCache");
public static final CompoundName TIMEOUT = new CompoundName("timeout");
+ /** @deprecated use Trace.LEVEL */
+ @Deprecated // TODO: Remove on Vespa 9
+ public static final CompoundName TRACE_LEVEL = new CompoundName("traceLevel");
+
+ /** @deprecated use Trace.EXPLAIN_LEVEL */
+ @Deprecated // TODO: Remove on Vespa 9
+ public static final CompoundName EXPLAIN_LEVEL = new CompoundName("explainLevel");
private static final QueryProfileType argumentType;
static {
@@ -213,8 +209,6 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
argumentType.addField(new FieldDescription(HITS.toString(), "integer", "hits count"));
argumentType.addField(new FieldDescription(QUERY_PROFILE.toString(), "string"));
argumentType.addField(new FieldDescription(SEARCH_CHAIN.toString(), "string"));
- argumentType.addField(new FieldDescription(TRACE_LEVEL.toString(), "integer", "tracelevel"));
- argumentType.addField(new FieldDescription(EXPLAIN_LEVEL.toString(), "integer", "explainlevel"));
argumentType.addField(new FieldDescription(NO_CACHE.toString(), "boolean", "nocache"));
argumentType.addField(new FieldDescription(GROUPING_SESSION_CACHE.toString(), "boolean", "groupingSessionCache"));
argumentType.addField(new FieldDescription(TIMEOUT.toString(), "string", "timeout"));
@@ -225,6 +219,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
argumentType.addField(new FieldDescription(Dispatcher.DISPATCH, new QueryProfileFieldType(Dispatcher.getArgumentType())));
argumentType.addField(new FieldDescription(Ranking.RANKING, new QueryProfileFieldType(Ranking.getArgumentType())));
argumentType.addField(new FieldDescription(Presentation.PRESENTATION, new QueryProfileFieldType(Presentation.getArgumentType())));
+ argumentType.addField(new FieldDescription(Trace.TRACE, new QueryProfileFieldType(Trace.getArgumentType())));
argumentType.freeze();
}
public static QueryProfileType getArgumentType() { return argumentType; }
@@ -260,6 +255,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
registry.register(Select.getArgumentType().unfrozen());
registry.register(Ranking.getArgumentType().unfrozen());
registry.register(Presentation.getArgumentType().unfrozen());
+ registry.register(Trace.getArgumentType().unfrozen());
registry.register(DefaultProperties.argumentType.unfrozen());
}
@@ -403,7 +399,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
}
properties().setParentQuery(this);
- traceProperties();
+ trace.traceProperties();
}
public Query(Query query) {
@@ -478,59 +474,6 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
public Properties properties() { return (Properties)super.properties(); }
/**
- * Traces how properties was resolved and from where. Done after the fact to avoid special handling
- * of tracelevel, which is the property deciding whether this needs to be done
- */
- private void traceProperties() {
- if (traceLevel == 0) return;
- CompiledQueryProfile profile = null;
- QueryProfileProperties profileProperties = properties().getInstance(QueryProfileProperties.class);
- if (profileProperties != null)
- profile = profileProperties.getQueryProfile();
-
- if (profile == null)
- trace("No query profile is used", false, 1);
- else
- trace("Using " + profile.toString(), false, 1);
-
- if (traceLevel < 4) return;
- StringBuilder b = new StringBuilder("Resolved properties:\n");
- Set<String> mentioned = new HashSet<>();
- for (Map.Entry<String,String> requestProperty : requestProperties().entrySet() ) {
- Object resolvedValue = properties().get(requestProperty.getKey(), requestProperties());
- if (resolvedValue == null && requestProperty.getKey().equals("queryProfile"))
- resolvedValue = requestProperty.getValue();
-
- b.append(requestProperty.getKey());
- b.append(": ");
- b.append(resolvedValue); // (may be null)
- b.append(" (");
-
- if (profile != null && ! profile.isOverridable(new CompoundName(requestProperty.getKey()), requestProperties()))
- b.append("from query profile - unoverridable, ignoring request value");
- else
- b.append("from request");
- b.append(")\n");
- mentioned.add(requestProperty.getKey());
- }
- if (profile != null) {
- appendQueryProfileProperties(profile, mentioned, b);
- }
- trace(b.toString(),false,4);
- }
-
- private Map<String, String> requestProperties() {
- return httpRequest.propertyMap();
- }
-
- private void appendQueryProfileProperties(CompiledQueryProfile profile, Set<String> mentioned, StringBuilder b) {
- for (var property : profile.listValuesWithSources(CompoundName.empty, requestProperties(), properties()).entrySet()) {
- if ( ! mentioned.contains(property.getKey()))
- b.append(property.getKey()).append(": ").append(property.getValue()).append("\n");
- }
- }
-
- /**
* Validates this query
*
* @return the reason if it is invalid, null if it is valid
@@ -599,35 +542,30 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
*/
public void resetTimeout() { this.startTime = System.currentTimeMillis(); }
- /**
- * Sets the context level of this query, 0 means no tracing
- * Higher numbers means increasingly more tracing
- */
- public void setTraceLevel(int traceLevel) { this.traceLevel = traceLevel; }
- /**
- * Sets the explain level of this query, 0 means no tracing
- * Higher numbers means increasingly more explaining
- */
- public void setExplainLevel(int explainLevel) { this.explainLevel = explainLevel; }
+ /** @deprecated use getTrace().setLevel(level) */
+ @Deprecated // TODO: Remove on Vespa 9
+ public void setTraceLevel(int traceLevel) { trace.setLevel(traceLevel); }
- /**
- * Returns the context level of this query, 0 means no tracing
- * Higher numbers means increasingly more tracing
- */
- public int getTraceLevel() { return traceLevel; }
+ /** @deprecated use getTrace().setExplainLevel(level) */
+ @Deprecated // TODO: Remove on Vespa 9
+ public void setExplainLevel(int explainLevel) { trace.setExplainLevel(explainLevel); }
- /**
- * Returns the explain level of this query, 0 means no tracing
- * Higher numbers means increasingly more explaining
- */
- public int getExplainLevel() { return explainLevel; }
+ /** @deprecated use getTrace().setLevel(level) */
+ @Deprecated // TODO: Remove on Vespa 9
+ public int getTraceLevel() { return trace.getLevel(); }
+
+ /** @deprecated use getTrace().getExplainLevel(level) */
+ @Deprecated // TODO: Remove on Vespa 9
+ public int getExplainLevel() { return getTrace().getExplainLevel(); }
/**
* Returns the context level of this query, 0 means no tracing
* Higher numbers means increasingly more tracing
+ *
+ * @deprecated use getTrace().isTraceable(level)
*/
- public final boolean isTraceable(int level) { return traceLevel >= level; }
-
+ @Deprecated // TODO: Remove on Vespa 9
+ public final boolean isTraceable(int level) { return trace.isTraceable(level); }
/** Returns whether this query should never be served from a cache. Default is false */
public boolean getNoCache() { return noCache; }
@@ -711,65 +649,24 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
return model.getQueryTree().encode(buffer);
}
- /**
- * Adds a context message to this query and to the info log,
- * if the context level of the query is sufficiently high.
- * The context information will be carried over to the result at creation.
- * The message parameter will be included <i>with</i> XML escaping.
- *
- * @param message the message to add
- * @param traceLevel the context level of the message, this method will do nothing
- * if the traceLevel of the query is lower than this value
- */
+ /** Calls getTrace().trace(message, traceLevel). */
public void trace(String message, int traceLevel) {
- trace(message, false, traceLevel);
+ trace.trace(message, traceLevel);
}
+ /** Calls getTrace().trace(message, traceLevel). */
public void trace(Object message, int traceLevel) {
- if ( ! isTraceable(traceLevel)) return;
- getContext(true).trace(message, 0);
+ trace.trace(message, traceLevel);
}
- /**
- * Adds a trace message to this query
- * if the trace level of the query is sufficiently high.
- *
- * @param message the message to add
- * @param includeQuery true to append the query root stringValue at the end of the message
- * @param traceLevel the context level of the message, this method will do nothing
- * if the traceLevel of the query is lower than this value
- */
+ /** Calls getTrace().trace(message, includeQuery, traceLevel). */
public void trace(String message, boolean includeQuery, int traceLevel) {
- if ( ! isTraceable(traceLevel)) return;
-
- if (includeQuery)
- message += ": [" + queryTreeText() + "]";
-
- log.log(Level.FINE,message);
-
- // Pass 0 as traceLevel as the trace level check is already done above,
- // and it is not propagated to trace until execution has started
- // (it is done in the execution.search method)
- getContext(true).trace(message, 0);
+ trace.trace(message, includeQuery, traceLevel);
}
- /**
- * Adds a trace message to this query
- * if the trace level of the query is sufficiently high.
- *
- * @param includeQuery true to append the query root stringValue at the end of the message
- * @param traceLevel the context level of the message, this method will do nothing
- * if the traceLevel of the query is lower than this value
- * @param messages the messages whose toStrings will be concatenated into the trace message.
- * Concatenation will only happen if the trace level is sufficiently high.
- */
+ /** Calls getTrace().trace(message, traceLevel, messages). */
public void trace(boolean includeQuery, int traceLevel, Object... messages) {
- if ( ! isTraceable(traceLevel)) return;
-
- StringBuilder concatenated = new StringBuilder();
- for (Object message : messages)
- concatenated.append(message);
- trace(concatenated.toString(), includeQuery, traceLevel);
+ trace.trace(includeQuery, traceLevel, messages);
}
/**
@@ -780,47 +677,27 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
* by an IllegalStateException. In other words, intended use is create the
* new query, and attach the context to the invoking query as soon as the new
* query is properly initialized.
- *
* <p>
* This method will always set the argument query's context level to the context
* level of this query.
*
- * @param query
- * The query which should be traced as a part of this query.
- * @throws IllegalStateException
- * If the query given as argument already has context
- * information.
+ * @param query the query which should be traced as a part of this query
+ * @throws IllegalStateException if the query given as argument already has context information
*/
public void attachContext(Query query) throws IllegalStateException {
- query.setTraceLevel(getTraceLevel());
- query.setExplainLevel(getExplainLevel());
- if (context == null) {
- // Nothing to attach to. This is about the same as
- // getTraceLevel() == 0,
- // but is a direct test of what will make the function superfluous.
- return;
- }
+ query.getTrace().setLevel(getTrace().getLevel());
+ query.getTrace().setExplainLevel(getTrace().getExplainLevel());
+ if (context == null) return;
if (query.getContext(false) != null) {
// If we added the other query's context info as a subnode in this
// query's context tree, we would have to check for loops in the
// context graph. If we simply created a new node without checking,
// we might silently overwrite useful information.
- throw new IllegalStateException("Query to attach already has context information stored.");
+ throw new IllegalStateException("Query to attach already has context information stored");
}
query.context = context;
}
- private String queryTreeText() {
- QueryTree root = getModel().getQueryTree();
-
- if (getTraceLevel() < 2)
- return root.toString();
- if (getTraceLevel() < 6)
- return yqlRepresentation();
- else
- return "\n" + yqlRepresentation() + "\n" + new TextualQueryRepresentation(root.getRoot()) + "\n";
- }
-
/**
* Serialize this query as YQL+. This method will never throw exceptions,
* but instead return a human readable error message if a problem occurred while
@@ -1000,6 +877,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
clone.model = model.cloneFor(clone);
clone.select = select.cloneFor(clone);
clone.ranking = ranking.cloneFor(clone);
+ clone.trace = trace.cloneFor(clone);
clone.presentation = (Presentation) presentation.clone();
clone.context = getContext(true).cloneFor(clone);
@@ -1008,8 +886,6 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
assert (clone.properties().getParentQuery() == clone);
clone.setTimeout(getTimeout());
- clone.setTraceLevel(getTraceLevel());
- clone.setExplainLevel(getExplainLevel());
clone.setHits(getHits());
clone.setOffset(getOffset());
clone.setNoCache(getNoCache());
@@ -1029,6 +905,9 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
/** Returns the query representation model to be used for this query, never null */
public Model getModel() { return model; }
+ /** Returns the trace settings and facade API. */
+ public Trace getTrace() { return trace; }
+
/**
* Return the HTTP request which caused this query. This will never be null
* when running with queries from the network.
diff --git a/container-search/src/main/java/com/yahoo/search/Result.java b/container-search/src/main/java/com/yahoo/search/Result.java
index b31a4fb6e24..1fd69f15012 100644
--- a/container-search/src/main/java/com/yahoo/search/Result.java
+++ b/container-search/src/main/java/com/yahoo/search/Result.java
@@ -245,7 +245,7 @@ public final class Result extends com.yahoo.processing.Response implements Clone
* @param name the name of the searcher instance returning this result
*/
public void trace(String name) {
- if (hits().getQuery().getTraceLevel() < 5) {
+ if (hits().getQuery().getTrace().getLevel() < 5) {
return;
}
StringBuilder hitBuffer = new StringBuilder(name);
diff --git a/container-search/src/main/java/com/yahoo/search/Searcher.java b/container-search/src/main/java/com/yahoo/search/Searcher.java
index 473adfa17db..63dba2864f7 100644
--- a/container-search/src/main/java/com/yahoo/search/Searcher.java
+++ b/container-search/src/main/java/com/yahoo/search/Searcher.java
@@ -163,7 +163,7 @@ public abstract class Searcher extends Processor {
}
else {
int fillRejectTraceAt = 3;
- if (result.getQuery().getTraceLevel() >= fillRejectTraceAt)
+ if (result.getQuery().getTrace().getLevel() >= fillRejectTraceAt)
result.getQuery().trace("Ignoring fill(" + summaryClass + "): " +
( result.hits().getFilled() == null ? "Hits are unfillable" : "Hits already filled" ) +
": result.hits().getFilled()=" + result.hits().getFilled(), fillRejectTraceAt);
diff --git a/container-search/src/main/java/com/yahoo/search/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/search/cluster/ClusterSearcher.java
index 71758666b99..4af6757db8c 100644
--- a/container-search/src/main/java/com/yahoo/search/cluster/ClusterSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/cluster/ClusterSearcher.java
@@ -162,7 +162,7 @@ public abstract class ClusterSearcher<T> extends PingableSearcher implements Nod
if (timedOut(query))
return new Result(query, ErrorMessage.createTimeout("No time left for searching"));
- if (query.getTraceLevel() >= 8)
+ if (query.getTrace().getLevel() >= 8)
query.trace("Trying " + connection, false, 8);
result = robustSearch(query, execution, connection);
@@ -170,7 +170,7 @@ public abstract class ClusterSearcher<T> extends PingableSearcher implements Nod
if ( ! shouldRetry(query, result))
return result;
- if (query.getTraceLevel() >= 6)
+ if (query.getTrace().getLevel() >= 6)
query.trace("Error from connection " + connection + " : " + result.hits().getError(), false, 6);
if (result.hits().getError().getCode() == Error.TIMEOUT.code)
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
index 82c570a9975..8b2457606ab 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java
@@ -89,12 +89,12 @@ public class ProtobufSerialization {
}
public static int getTraceLevelForBackend(Query query) {
- int traceLevel = query.getTraceLevel();
+ int traceLevel = query.getTrace().getLevel();
if (query.getModel().getExecution().trace().getForceTimestamps()) {
traceLevel = Math.max(traceLevel, 5); // Backend produces timing information on level 4 and 5
}
- if (query.getExplainLevel() > 0) {
- traceLevel = Math.max(traceLevel, query.getExplainLevel() + 5);
+ if (query.getTrace().getExplainLevel() > 0) {
+ traceLevel = Math.max(traceLevel, query.getTrace().getExplainLevel() + 5);
}
return traceLevel;
}
@@ -157,7 +157,7 @@ public class ProtobufSerialization {
if (includeQueryData) {
mergeQueryDataToDocsumRequest(query, builder);
}
- if (query.getTraceLevel() >= 3) {
+ if (query.getTrace().getLevel() >= 3) {
query.trace((includeQueryData ? "ProtoBuf: Resending " : "Not resending ") + "query during document summary fetching", 3);
}
@@ -250,7 +250,7 @@ public class ProtobufSerialization {
if ( ! slimeTrace.isEmpty()) {
var traces = new Value.ArrayValue();
traces.add(new SlimeAdapter(BinaryFormat.decode(slimeTrace.toByteArray()).get()));
- query.trace(traces, query.getTraceLevel());
+ query.trace(traces, query.getTrace().getLevel());
}
return result;
}
diff --git a/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java b/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
index adf03340c6c..21b4d1d538f 100644
--- a/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
@@ -487,7 +487,7 @@ public class FederationSearcher extends ForkingSearcher {
private void traceTargets(Query query, Collection<Target> targets) {
int traceFederationLevel = 2;
- if ( ! query.isTraceable(traceFederationLevel)) return;
+ if ( ! query.getTrace().isTraceable(traceFederationLevel)) return;
query.trace("Federating to " + targets, traceFederationLevel);
}
@@ -537,7 +537,7 @@ public class FederationSearcher extends ForkingSearcher {
}
}
- if (query.getTraceLevel()>=4)
+ if (query.getTrace().getLevel()>=4)
query.trace("Got " + group.getConcreteSize() + " hits from " + group.getId(),false, 4);
mergedResults.hits().add(group);
}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/vespa/GroupingExecutor.java b/container-search/src/main/java/com/yahoo/search/grouping/vespa/GroupingExecutor.java
index 694aa76e5f8..2ba33f60ea1 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/vespa/GroupingExecutor.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/vespa/GroupingExecutor.java
@@ -219,7 +219,7 @@ public class GroupingExecutor extends Searcher {
if (lastPass > 0) {
baseRoot = origRoot.clone();
}
- if (query.isTraceable(3) && query.getGroupingSessionCache()) {
+ if (query.getTrace().isTraceable(3) && query.getGroupingSessionCache()) {
query.trace("Grouping in " + (lastPass + 1) + " passes. SessionId='" + query.getSessionId() + "'.", 3);
}
for (int pass = 0; pass <= lastPass; ++pass) {
@@ -242,7 +242,7 @@ public class GroupingExecutor extends Searcher {
// noinspection ConstantConditions
passRoot = baseRoot.clone();
}
- if (query.isTraceable(4) && query.getGroupingSessionCache()) {
+ if (query.getTrace().isTraceable(4) && query.getGroupingSessionCache()) {
query.trace("Grouping with session cache '" + query.getGroupingSessionCache() + "' enabled for pass #" + pass + ".", 4);
}
if (origRoot != passRoot) {
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
index 6d69a2cb877..98789480a1e 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
@@ -122,7 +122,7 @@ public class PageTemplatesXmlRenderer extends AsynchronousSectionedRenderer<Resu
}
private void queryContext(XMLWriter writer, Query owner) {
- if (owner.getTraceLevel()!=0) {
+ if (owner.getTrace().getLevel()!=0) {
XMLWriter xmlWriter=XMLWriter.from(writer);
xmlWriter.openTag("meta").attribute("type", QueryContext.ID);
TraceNode traceRoot = owner.getModel().getExecution().trace().traceNode().root();
diff --git a/container-search/src/main/java/com/yahoo/search/query/Model.java b/container-search/src/main/java/com/yahoo/search/query/Model.java
index dbaab3045bf..63fc386963a 100644
--- a/container-search/src/main/java/com/yahoo/search/query/Model.java
+++ b/container-search/src/main/java/com/yahoo/search/query/Model.java
@@ -248,7 +248,7 @@ public class Model implements Cloneable {
try {
Parser parser = ParserFactory.newInstance(type, ParserEnvironment.fromExecutionContext(execution.context()));
queryTree = parser.parse(Parsable.fromQueryModel(this));
- if (parent.getTraceLevel() >= 2)
+ if (parent.getTrace().getLevel() >= 2)
parent.trace("Query parsed to: " + parent.yqlRepresentation(), 2);
}
catch (IllegalArgumentException e) {
diff --git a/container-search/src/main/java/com/yahoo/search/query/Trace.java b/container-search/src/main/java/com/yahoo/search/query/Trace.java
new file mode 100644
index 00000000000..9f056b14c21
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/query/Trace.java
@@ -0,0 +1,242 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.query;
+
+import com.yahoo.api.annotations.Beta;
+import com.yahoo.prelude.query.textualrepresentation.TextualQueryRepresentation;
+import com.yahoo.processing.request.CompoundName;
+import com.yahoo.search.Query;
+import com.yahoo.search.query.profile.QueryProfileProperties;
+import com.yahoo.search.query.profile.compiled.CompiledQueryProfile;
+import com.yahoo.search.query.profile.types.FieldDescription;
+import com.yahoo.search.query.profile.types.QueryProfileType;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Trace settings and methods for tracing a query.
+ * The actual trace is a tree structure stored in the query execution.
+ *
+ * @author bratseth
+ */
+@Beta
+public class Trace implements Cloneable {
+
+ private static final Logger log = Logger.getLogger(Trace.class.getName());
+
+ /** The type representing the property arguments consumed by this */
+ private static final QueryProfileType argumentType;
+
+ public static final String TRACE = "trace";
+ public static final String LEVEL = "level";
+ public static final String EXPLAIN_LEVEL = "explainLevel";
+ public static final String TIMESTAMPS = "timestamps";
+ public static final String QUERY = "query";
+
+ static {
+ argumentType = new QueryProfileType(TRACE);
+ argumentType.setStrict(true);
+ argumentType.setBuiltin(true);
+ argumentType.addField(new FieldDescription(LEVEL, "integer", "tracelevel traceLevel"));
+ argumentType.addField(new FieldDescription(EXPLAIN_LEVEL, "integer", "explainlevel explainLevel"));
+ argumentType.addField(new FieldDescription(TIMESTAMPS, "boolean"));
+ argumentType.addField(new FieldDescription(QUERY, "boolean"));
+ argumentType.freeze();
+ }
+
+ public static QueryProfileType getArgumentType() { return argumentType; }
+
+ private Query parent;
+
+ private int level = 0;
+ private int explainLevel = 0;
+ private boolean timestamps = false;
+ private boolean query = true;
+
+ public Trace(Query parent) {
+ this.parent = Objects.requireNonNull(parent);
+ }
+
+ /** Returns the level of detail we'll be tracing at in this query. The default level is 0; no tracing. */
+ public int getLevel() { return level; }
+ public void setLevel(int level) { this.level = level; }
+ public boolean isTraceable(int level) { return level <= this.level; }
+
+ /** Sets the explain level of this query, 0 means no tracing. Higher numbers means increasingly more explaining. */
+ public void setExplainLevel(int explainLevel) { this.explainLevel = explainLevel; }
+ public int getExplainLevel() { return explainLevel; }
+
+ /** Returns whether trace entries should have a timestamp. Default is false. */
+ public boolean getTimestamps() { return timestamps; }
+ public void setTimestamps(boolean timestamps) { this.timestamps = timestamps; }
+
+ /** Returns whether any trace entries should include the query. Default is true. */
+ public boolean getQuery() { return query; }
+ public void setQuery(boolean query) { this.query = query; }
+
+ /**
+ * Adds a context message to this query and to the info log,
+ * if the context level of the query is sufficiently high.
+ * The context information will be carried over to the result at creation.
+ * The message parameter will be included <i>with</i> XML escaping.
+ *
+ * @param message the message to add
+ * @param traceLevel the context level of the message, this method will do nothing
+ * if the traceLevel of the query is lower than this value
+ */
+ public void trace(String message, int traceLevel) {
+ trace(message, false, traceLevel);
+ }
+
+ public void trace(Object message, int traceLevel) {
+ if ( ! isTraceable(traceLevel)) return;
+ parent.getContext(true).trace(message, 0);
+ }
+
+ /**
+ * Adds a trace message to this query
+ * if the trace level of the query is sufficiently high.
+ *
+ * @param message the message to add
+ * @param includeQuery true to append the query root stringValue at the end of the message
+ * @param traceLevel the context level of the message, this method will do nothing
+ * if the traceLevel of the query is lower than this value
+ */
+ public void trace(String message, boolean includeQuery, int traceLevel) {
+ if ( ! isTraceable(traceLevel)) return;
+
+ if (includeQuery && query)
+ message += ": [" + queryTreeText() + "]";
+
+ log.log(Level.FINE, message);
+
+ // Pass 0 as traceLevel as the trace level check is already done above,
+ // and it is not propagated to trace until execution has started
+ // (it is done in the execution.search method)
+ parent.getContext(true).trace(message, 0);
+ }
+
+ /**
+ * Adds a trace message to this query
+ * if the trace level of the query is sufficiently high.
+ *
+ * @param includeQuery true to append the query root stringValue at the end of the message
+ * @param traceLevel the context level of the message, this method will do nothing
+ * if the traceLevel of the query is lower than this value
+ * @param messages the messages whose toStrings will be concatenated into the trace message.
+ * Concatenation will only happen if the trace level is sufficiently high.
+ */
+ public void trace(boolean includeQuery, int traceLevel, Object... messages) {
+ if ( ! isTraceable(traceLevel)) return;
+
+ StringBuilder concatenated = new StringBuilder();
+ for (Object message : messages)
+ concatenated.append(message);
+ trace(concatenated.toString(), includeQuery, traceLevel);
+ }
+
+ /**
+ * Traces how properties was resolved and from where. Done after the fact to avoid special handling
+ * of tracelevel, which is the property deciding whether this needs to be done
+ */
+ public void traceProperties() {
+ if (level == 0) return;
+ CompiledQueryProfile profile = null;
+ QueryProfileProperties profileProperties = parent.properties().getInstance(QueryProfileProperties.class);
+ if (profileProperties != null)
+ profile = profileProperties.getQueryProfile();
+
+ if (profile == null)
+ trace("No query profile is used", false, 1);
+ else
+ trace("Using " + profile.toString(), false, 1);
+
+ if (level < 4) return;
+ StringBuilder b = new StringBuilder("Resolved properties:\n");
+ Set<String> mentioned = new HashSet<>();
+ for (Map.Entry<String,String> requestProperty : requestProperties().entrySet() ) {
+ Object resolvedValue = parent.properties().get(requestProperty.getKey(), requestProperties());
+ if (resolvedValue == null && requestProperty.getKey().equals("queryProfile"))
+ resolvedValue = requestProperty.getValue();
+
+ b.append(requestProperty.getKey());
+ b.append(": ");
+ b.append(resolvedValue); // (may be null)
+ b.append(" (");
+
+ if (profile != null && ! profile.isOverridable(new CompoundName(requestProperty.getKey()), requestProperties()))
+ b.append("from query profile - unoverridable, ignoring request value");
+ else
+ b.append("from request");
+ b.append(")\n");
+ mentioned.add(requestProperty.getKey());
+ }
+ if (profile != null) {
+ appendQueryProfileProperties(profile, mentioned, b);
+ }
+ trace(b.toString(),false,4);
+ }
+
+ private void appendQueryProfileProperties(CompiledQueryProfile profile, Set<String> mentioned, StringBuilder b) {
+ for (var property : profile.listValuesWithSources(CompoundName.empty, requestProperties(), parent.properties()).entrySet()) {
+ if ( ! mentioned.contains(property.getKey()))
+ b.append(property.getKey()).append(": ").append(property.getValue()).append("\n");
+ }
+ }
+
+ private Map<String, String> requestProperties() {
+ return parent.getHttpRequest().propertyMap();
+ }
+
+ private String queryTreeText() {
+ QueryTree root = parent.getModel().getQueryTree();
+
+ if (level < 2)
+ return root.toString();
+ if (level < 6)
+ return parent.yqlRepresentation();
+ else
+ return "\n" + parent.yqlRepresentation() + "\n" + new TextualQueryRepresentation(root.getRoot()) + "\n";
+ }
+
+ public Trace cloneFor(Query parent) {
+ Trace trace = this.clone();
+ trace.parent = parent;
+ return trace;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this ) return true;
+ if ( ! (o instanceof Trace)) return false;
+ Trace other = (Trace)o;
+ if (other.level != this.level) return false;
+ if (other.explainLevel != this.explainLevel) return false;
+ if (other.timestamps != this.timestamps) return false;
+ if (other.query != this.query) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() { return Objects.hash(level, explainLevel, timestamps, query); }
+
+ @Override
+ public Trace clone() {
+ try {
+ return (Trace)super.clone();
+ }
+ catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "trace [level: " + level + ", explainLevel: " + explainLevel + ", timestamps: " + timestamps + ", query: " + query + "]";
+ }
+
+}
diff --git a/container-search/src/main/java/com/yahoo/search/query/context/QueryContext.java b/container-search/src/main/java/com/yahoo/search/query/context/QueryContext.java
index 38f76c6ca49..c0ca5ac4731 100644
--- a/container-search/src/main/java/com/yahoo/search/query/context/QueryContext.java
+++ b/container-search/src/main/java/com/yahoo/search/query/context/QueryContext.java
@@ -87,7 +87,7 @@ public class QueryContext implements Cloneable {
}
public boolean render(Writer writer) throws java.io.IOException {
- if (owner.getTraceLevel()!=0) {
+ if (owner.getTrace().getLevel()!=0) {
XMLWriter xmlWriter=XMLWriter.from(writer);
xmlWriter.openTag("meta").attribute("type",ID);
TraceNode traceRoot=owner.getModel().getExecution().trace().traceNode().root();
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
index 989f12172b3..e3ab49f0e32 100644
--- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
+++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
@@ -344,7 +344,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable
* a primitive value, a substitutable string, a query profile, or null if not found.
*/
public final Object lookup(String name, Map<String, String> context) {
- return lookup(new CompoundName(name),true,DimensionBinding.createFrom(getDimensions(),context));
+ return lookup(new CompoundName(name), true, DimensionBinding.createFrom(getDimensions(),context));
}
/** Sets a value in this or any nested profile using null as context */
@@ -733,7 +733,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable
// ----------------- Private ----------------------------------------------------------------------------------
- private Boolean isDeclaredOverridable(CompoundName name,DimensionBinding dimensionBinding) {
+ private Boolean isDeclaredOverridable(CompoundName name, DimensionBinding dimensionBinding) {
QueryProfile parent = lookupParentExact(name, true, dimensionBinding);
if (parent.overridable == null) return null;
return parent.overridable.get(name.last());
@@ -743,15 +743,15 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable
* Sets the overridability of a field in this profile,
* this overrides the corresponding setting in the type (if any)
*/
- private void setOverridable(CompoundName fieldName, boolean overridable, DimensionBinding dimensionBinding) {
- QueryProfile parent = lookupParentExact(fieldName, true, dimensionBinding);
+ private void setOverridable(CompoundName name, boolean overridable, DimensionBinding dimensionBinding) {
+ QueryProfile parent = lookupParentExact(name, true, dimensionBinding);
if (dimensionBinding.isNull()) {
if (parent.overridable == null)
parent.overridable = new HashMap<>();
- parent.overridable.put(fieldName.last(), overridable);
+ parent.overridable.put(name.last(), overridable);
}
else {
- variants.setOverridable(fieldName.last(), overridable, dimensionBinding.getValues());
+ variants.setOverridable(name.last(), overridable, dimensionBinding.getValues());
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
index 4cced8d7923..f6e158cf04a 100644
--- a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
+++ b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
@@ -11,6 +11,7 @@ import com.yahoo.search.query.Presentation;
import com.yahoo.search.query.Properties;
import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.Select;
+import com.yahoo.search.query.Trace;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry;
import com.yahoo.search.query.profile.types.ConversionContext;
import com.yahoo.search.query.profile.types.FieldDescription;
@@ -132,11 +133,16 @@ public class QueryProperties extends Properties {
} else if (key.size() == 3 && key.get(1).equals(Presentation.FORMAT)) {
if (key.last().equals(Presentation.TENSORS)) return query.getPresentation().getTensorShortForm();
}
- } else if (key.size() == 1) {
+ }
+ else if (key.size() == 2 && key.first().equals(Trace.TRACE)) {
+ if (key.last().equals(Trace.LEVEL)) return query.getTrace().getLevel();
+ if (key.last().equals(Trace.EXPLAIN_LEVEL)) return query.getTrace().getExplainLevel();
+ if (key.last().equals(Trace.TIMESTAMPS)) return query.getTrace().getTimestamps();
+ if (key.last().equals(Trace.QUERY)) return query.getTrace().getQuery();
+ }
+ else if (key.size() == 1) {
if (key.equals(Query.HITS)) return query.getHits();
if (key.equals(Query.OFFSET)) return query.getOffset();
- if (key.equals(Query.TRACE_LEVEL)) return query.getTraceLevel();
- if (key.equals(Query.EXPLAIN_LEVEL)) return query.getExplainLevel();
if (key.equals(Query.TIMEOUT)) return query.getTimeout();
if (key.equals(Query.NO_CACHE)) return query.getNoCache();
if (key.equals(Query.GROUPING_SESSION_CACHE)) return query.getGroupingSessionCache();
@@ -301,6 +307,16 @@ public class QueryProperties extends Properties {
else
throwIllegalParameter(key.last(), Presentation.PRESENTATION);
}
+ else if (key.size() == 2 && key.first().equals(Trace.TRACE)) {
+ if (key.last().equals(Trace.LEVEL))
+ query.getTrace().setLevel(asInteger(value, 0));
+ if (key.last().equals(Trace.EXPLAIN_LEVEL))
+ query.getTrace().setExplainLevel(asInteger(value, 0));
+ if (key.last().equals(Trace.TIMESTAMPS))
+ query.getTrace().setTimestamps(asBoolean(value, false));
+ if (key.last().equals(Trace.QUERY))
+ query.getTrace().setQuery(asBoolean(value, true));
+ }
else if (key.first().equals(Select.SELECT)) {
if (key.size() == 1) {
query.getSelect().setGroupingExpressionString(asString(value, ""));
@@ -322,10 +338,6 @@ public class QueryProperties extends Properties {
query.setHits(asInteger(value,10));
else if (key.equals(Query.OFFSET))
query.setOffset(asInteger(value,0));
- else if (key.equals(Query.TRACE_LEVEL))
- query.setTraceLevel(asInteger(value,0));
- else if (key.equals(Query.EXPLAIN_LEVEL))
- query.setExplainLevel(asInteger(value,0));
else if (key.equals(Query.TIMEOUT))
query.setTimeout(value.toString());
else if (key.equals(Query.NO_CACHE))
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
index d3bb1e7a81d..f43be20e0ac 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
@@ -39,7 +39,7 @@ public class BooleanSearcher extends Searcher {
if (fieldName != null) {
return search(query, execution, fieldName);
} else {
- if (query.isTraceable(5)) {
+ if (query.getTrace().isTraceable(5)) {
query.trace("BooleanSearcher: Nothing added to query", false, 5);
}
}
@@ -49,7 +49,7 @@ public class BooleanSearcher extends Searcher {
private Result search(Query query, Execution execution, String fieldName) {
String attributes = query.properties().getString(ATTRIBUTES);
String rangeAttributes = query.properties().getString(RANGE_ATTRIBUTES);
- if (query.isTraceable(5)) {
+ if (query.getTrace().isTraceable(5)) {
query.trace("BooleanSearcher: fieldName(" + fieldName + "), attributes(" + attributes +
"), rangeAttributes(" + rangeAttributes + ")", false, 5);
}
@@ -57,7 +57,7 @@ public class BooleanSearcher extends Searcher {
if (attributes != null || rangeAttributes != null) {
try {
addPredicateTerm(query, fieldName, attributes, rangeAttributes);
- if (query.isTraceable(4)) {
+ if (query.getTrace().isTraceable(4)) {
query.trace("BooleanSearcher: Added boolean operator", true, 4);
}
} catch (TokenMgrException e) {
@@ -68,7 +68,7 @@ public class BooleanSearcher extends Searcher {
}
}
else {
- if (query.isTraceable(5)) {
+ if (query.getTrace().isTraceable(5)) {
query.trace("BooleanSearcher: Nothing added to query", false, 5);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
index 250e66ca9fb..58353cc5907 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
@@ -224,7 +224,7 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> {
protected void renderTrace(Trace trace) throws IOException {
if (!trace.traceNode().children().iterator().hasNext()) return;
- if (getResult().getQuery().getTraceLevel() == 0) return;
+ if (getResult().getQuery().getTrace().getLevel() == 0) return;
try {
long basetime = trace.traceNode().timestamp();
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
index f93c70c0199..53e59d9deea 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
@@ -160,7 +160,7 @@ public final class XmlRenderer extends AsynchronousSectionedRenderer<Result> {
@SuppressWarnings("UnusedParameters")
public void queryContext(XMLWriter writer, QueryContext queryContext, Query owner) throws IOException {
- if (owner.getTraceLevel()!=0) {
+ if (owner.getTrace().getLevel()!=0) {
XMLWriter xmlWriter=XMLWriter.from(writer);
xmlWriter.openTag("meta").attribute("type", QueryContext.ID);
TraceNode traceRoot = owner.getModel().getExecution().trace().traceNode().root();
diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java b/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java
index 02537e63a6b..988021a6da0 100644
--- a/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java
+++ b/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java
@@ -494,7 +494,7 @@ public class Execution extends com.yahoo.processing.execution.Execution {
// Transfer state between query and execution as the execution constructors does not do that completely
query.getModel().setExecution(this);
- trace().setTraceLevel(query.getTraceLevel());
+ trace().setTraceLevel(query.getTrace().getLevel());
return (Result)super.process(query);
}
@@ -504,7 +504,7 @@ public class Execution extends com.yahoo.processing.execution.Execution {
super.onInvoking(request,processor);
final int traceDependencies = 6;
Query query = (Query) request;
- if (query.getTraceLevel() >= traceDependencies) {
+ if (query.getTrace().getLevel() >= traceDependencies) {
query.trace(processor.getId() + " " + processor.getDependencies(), traceDependencies);
}
}
diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
index 7f4de2e43f5..51035e3e313 100644
--- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
@@ -45,9 +45,9 @@ import java.util.logging.Logger;
*/
public class VdsStreamingSearcher extends VespaBackEndSearcher {
- private static final CompoundName streamingUserid=new CompoundName("streaming.userid");
- private static final CompoundName streamingGroupname=new CompoundName("streaming.groupname");
- private static final CompoundName streamingSelection=new CompoundName("streaming.selection");
+ private static final CompoundName streamingUserid = new CompoundName("streaming.userid");
+ private static final CompoundName streamingGroupname = new CompoundName("streaming.groupname");
+ private static final CompoundName streamingSelection = new CompoundName("streaming.selection");
static final String STREAMING_STATISTICS = "streaming.statistics";
private final VisitorFactory visitorFactory;
@@ -142,13 +142,13 @@ public class VdsStreamingSearcher extends VespaBackEndSearcher {
private boolean shouldTraceQuery(Query query) {
// Only trace for explicit bucket subset queries, as otherwise we'd get a trace entry for every superbucket in the system.
return (queryIsLocationConstrained(query) &&
- ((query.getTraceLevel() > 0) || tracingOptions.getSamplingStrategy().shouldSample()));
+ ((query.getTrace().getLevel() > 0) || tracingOptions.getSamplingStrategy().shouldSample()));
}
private int inferEffectiveQueryTraceLevel(Query query) {
- return ((query.getTraceLevel() == 0) && shouldTraceQuery(query)) // Honor query's explicit trace level if present.
+ return ((query.getTrace().getLevel() == 0) && shouldTraceQuery(query)) // Honor query's explicit trace level if present.
? tracingOptions.getTraceLevelOverride()
- : query.getTraceLevel();
+ : query.getTrace().getLevel();
}
@Override
@@ -308,7 +308,7 @@ public class VdsStreamingSearcher extends VespaBackEndSearcher {
}
private static void lazyTrace(Query query, int level, Object... args) {
- if (query.isTraceable(level)) {
+ if (query.getTrace().isTraceable(level)) {
StringBuilder s = new StringBuilder();
for (Object arg : args) {
s.append(arg);
diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
index 22f77e6f19d..bd96f888b87 100644
--- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
+++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
@@ -94,7 +94,7 @@ class VdsVisitor extends VisitorDataHandler implements Visitor {
} else if (log.isLoggable(Level.FINE)) {
implicitLevel = 7;
}
- return Math.max(query.getTraceLevel(), implicitLevel);
+ return Math.max(query.getTrace().getLevel(), implicitLevel);
}
private static String createSelectionString(String documentType, String selection) {
diff --git a/container-search/src/test/java/com/yahoo/prelude/querytransform/test/NormalizingSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/querytransform/test/NormalizingSearcherTestCase.java
index 0694c1a7e55..7ab50118c6d 100644
--- a/container-search/src/test/java/com/yahoo/prelude/querytransform/test/NormalizingSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/querytransform/test/NormalizingSearcherTestCase.java
@@ -84,7 +84,7 @@ public class NormalizingSearcherTestCase {
@Test
public void testPhraseQuery() {
Query query = new Query("/search?query=" + enc("\"b\u00e9yonc\u00e8 beyonc\u00e9\"") + "&search=cluster1&restrict=type1");
- query.setTraceLevel(2);
+ query.getTrace().setLevel(2);
createExecution().search(query);
assertEquals("WEAKAND(100) \"beyonce beyonce\"", query.getModel().getQueryTree().getRoot().toString());
}
diff --git a/container-search/src/test/java/com/yahoo/prelude/searcher/test/JSONDebugSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/searcher/test/JSONDebugSearcherTestCase.java
index 2841ce5521a..6a230da4950 100644
--- a/container-search/src/test/java/com/yahoo/prelude/searcher/test/JSONDebugSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/searcher/test/JSONDebugSearcherTestCase.java
@@ -14,36 +14,35 @@ import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.testutil.DocumentSourceSearcher;
import com.yahoo.yolean.trace.TraceNode;
import com.yahoo.yolean.trace.TraceVisitor;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
/**
* Visit the trace and check JSON payload is stored there when requested.
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
*/
public class JSONDebugSearcherTestCase {
private static final String NODUMPJSON = "?query=1&tracelevel=6";
private static final String DUMPJSON = "?query=1&dumpjson=jsonfield&tracelevel=6";
- private Chain<Searcher> searchChain;
- private static class LookForJson extends TraceVisitor {
- private static final String JSON_PAYLOAD = "{1: 2}";
- public boolean gotJson = false;
-
- @Override
- public void visit(TraceNode node) {
- if (node.payload() == null || node.payload().getClass() != String.class) {
- return;
- }
- if (node.payload().toString().equals(JSONDebugSearcher.JSON_FIELD + JSON_PAYLOAD)) {
- gotJson = true;
- }
- }
+ @Test
+ public void test() {
+ Chain<Searcher> searchChain = makeSearchChain("{1: 2}", new JSONDebugSearcher());
+ Execution e = new Execution(searchChain, Execution.Context.createContextStub());
+ e.search(new Query(NODUMPJSON));
+ Trace t = e.trace();
+ LookForJson visitor = new LookForJson();
+ t.accept(visitor);
+ assertFalse(visitor.gotJson);
+ e = new Execution(searchChain, Execution.Context.createContextStub());
+ e.search(new Query(DUMPJSON));
+ t = e.trace();
+ t.accept(visitor);
+ assertTrue(visitor.gotJson);
}
private Chain<Searcher> makeSearchChain(String content, Searcher dumper) {
@@ -63,29 +62,20 @@ public class JSONDebugSearcherTestCase {
docsource.addResult(q, r);
}
+ private static class LookForJson extends TraceVisitor {
- @Before
- public void setUp() throws Exception {
- searchChain = makeSearchChain("{1: 2}", new JSONDebugSearcher());
- }
-
- @After
- public void tearDown() throws Exception {
- }
+ private static final String JSON_PAYLOAD = "{1: 2}";
+ public boolean gotJson = false;
- @Test
- public final void test() {
- Execution e = new Execution(searchChain, Execution.Context.createContextStub());
- e.search(new Query(NODUMPJSON));
- Trace t = e.trace();
- LookForJson visitor = new LookForJson();
- t.accept(visitor);
- assertEquals(false, visitor.gotJson);
- e = new Execution(searchChain, Execution.Context.createContextStub());
- e.search(new Query(DUMPJSON));
- t = e.trace();
- t.accept(visitor);
- assertEquals(true, visitor.gotJson);
+ @Override
+ public void visit(TraceNode node) {
+ if (node.payload() == null || node.payload().getClass() != String.class) {
+ return;
+ }
+ if (node.payload().toString().equals(JSONDebugSearcher.JSON_FIELD + JSON_PAYLOAD)) {
+ gotJson = true;
+ }
+ }
}
}
diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java
index 347276d680d..e07d38fbf10 100644
--- a/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java
+++ b/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java
@@ -488,7 +488,7 @@ public class InterleavedSearchInvokerTest {
public TestQuery() {
super();
setTimeout(5000);
- setTraceLevel(5);
+ getTrace().setLevel(5);
}
@Override
diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java
index b1faac2036b..62bc89c8453 100644
--- a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/XmlReadingTestCase.java
@@ -49,80 +49,82 @@ public class XmlReadingTestCase {
@Test
public void testValid() {
- QueryProfileRegistry registry=
+ QueryProfileRegistry registry =
new QueryProfileXMLReader().read("src/test/java/com/yahoo/search/query/profile/config/test/validxml");
- CompiledQueryProfileRegistry cRegistry= registry.compile();
+ CompiledQueryProfileRegistry cRegistry = registry.compile();
QueryProfileType rootType = registry.getType("rootType");
- assertEquals(1,rootType.inherited().size());
- assertEquals("native",rootType.inherited().get(0).getId().getName());
+ assertEquals(1, rootType.inherited().size());
+ assertEquals("native", rootType.inherited().get(0).getId().getName());
assertTrue(rootType.isStrict());
assertTrue(rootType.getMatchAsPath());
- FieldDescription timeField=rootType.getField("time");
+ FieldDescription timeField = rootType.getField("time");
assertTrue(timeField.isMandatory());
- assertEquals("long",timeField.getType().toInstanceDescription());
- FieldDescription userField=rootType.getField("user");
+ assertEquals("long", timeField.getType().toInstanceDescription());
+ FieldDescription userField = rootType.getField("user");
assertFalse(userField.isMandatory());
- assertEquals("reference to a query profile of type 'user'",userField.getType().toInstanceDescription());
+ assertEquals("reference to a query profile of type 'user'", userField.getType().toInstanceDescription());
- QueryProfileType user=registry.getType("user");
- assertEquals(0,user.inherited().size());
+ QueryProfileType user = registry.getType("user");
+ assertEquals(0, user.inherited().size());
assertFalse(user.isStrict());
assertFalse(user.getMatchAsPath());
assertTrue(userField.isOverridable());
- FieldDescription ageField=user.getField("age");
+ FieldDescription ageField = user.getField("age");
assertTrue(ageField.isMandatory());
- assertEquals("integer",ageField.getType().toInstanceDescription());
- FieldDescription robotField=user.getField("robot");
+ assertEquals("integer", ageField.getType().toInstanceDescription());
+ FieldDescription robotField = user.getField("robot");
assertFalse(robotField.isMandatory());
assertFalse(robotField.isOverridable());
- assertEquals("boolean",robotField.getType().toInstanceDescription());
+ assertEquals("boolean", robotField.getType().toInstanceDescription());
- CompiledQueryProfile defaultProfile=cRegistry.getComponent("default");
+ CompiledQueryProfile defaultProfile = cRegistry.getComponent("default");
assertNull(defaultProfile.getType());
- assertEquals("20",defaultProfile.get("hits"));
+ assertEquals("20", defaultProfile.get("hits"));
assertFalse(defaultProfile.isOverridable(new CompoundName("hits"), null));
assertFalse(defaultProfile.isOverridable(new CompoundName("user.trusted"), null));
- assertEquals("false",defaultProfile.get("user.trusted"));
+ assertEquals("false", defaultProfile.get("user.trusted"));
- CompiledQueryProfile referencingProfile=cRegistry.getComponent("referencingModelSettings");
+ CompiledQueryProfile referencingProfile = cRegistry.getComponent("referencingModelSettings");
assertNull(referencingProfile.getType());
- assertEquals("some query",referencingProfile.get("model.queryString"));
- assertEquals("aDefaultIndex",referencingProfile.get("model.defaultIndex"));
+ assertEquals("some query", referencingProfile.get("model.queryString"));
+ assertEquals("aDefaultIndex", referencingProfile.get("model.defaultIndex"));
// Request parameters here should be ignored
- HttpRequest request=HttpRequest.createTestRequest("?query=foo&user.trusted=true&default-index=title", Method.GET);
- Query query=new Query(request, defaultProfile);
- assertEquals("false",query.properties().get("user.trusted"));
- assertEquals("default",query.getModel().getDefaultIndex());
- assertEquals("default",query.properties().get("default-index"));
-
- CompiledQueryProfile rootProfile=cRegistry.getComponent("root");
- assertEquals("rootType",rootProfile.getType().getId().getName());
- assertEquals(30,rootProfile.get("hits"));
- assertEquals(3,rootProfile.get("traceLevel"));
+ HttpRequest request = HttpRequest.createTestRequest("?query=foo&user.trusted=true&default-index=title", Method.GET);
+ Query query = new Query(request, defaultProfile);
+ assertEquals("false", query.properties().get("user.trusted"));
+ assertEquals("default", query.getModel().getDefaultIndex());
+ assertEquals("default", query.properties().get("default-index"));
+
+ CompiledQueryProfile rootProfile = cRegistry.getComponent("root");
+ assertEquals("rootType", rootProfile.getType().getId().getName());
+ assertEquals(30, rootProfile.get("hits"));
+ //assertEquals(3, rootProfile.get("traceLevel"));
assertTrue(rootProfile.isOverridable(new CompoundName("hits"), null));
+ query = new Query(request, rootProfile);
+ assertEquals(3, query.getTrace().getLevel());
- QueryProfile someUser=registry.getComponent("someUser");
+ QueryProfile someUser = registry.getComponent("someUser");
assertEquals("5",someUser.get("sub.test"));
assertEquals(18,someUser.get("age"));
// aliases
- assertEquals(18,someUser.get("alder"));
- assertEquals(18,someUser.get("anno"));
- assertEquals(18,someUser.get("aLdER"));
- assertEquals(18,someUser.get("ANNO"));
+ assertEquals(18, someUser.get("alder"));
+ assertEquals(18, someUser.get("anno"));
+ assertEquals(18, someUser.get("aLdER"));
+ assertEquals(18, someUser.get("ANNO"));
assertNull(someUser.get("Age")); // Only aliases are case insensitive
Map<String, String> context = new HashMap<>();
context.put("x", "x1");
assertEquals(37, someUser.get("alder", context, null));
- assertEquals(37,someUser.get("anno", context, null));
- assertEquals(37,someUser.get("aLdER", context, null));
- assertEquals(37,someUser.get("ANNO", context, null));
- assertEquals("male",someUser.get("gender", context, null));
- assertEquals("male",someUser.get("sex", context, null));
- assertEquals("male",someUser.get("Sex", context, null));
+ assertEquals(37, someUser.get("anno", context, null));
+ assertEquals(37, someUser.get("aLdER", context, null));
+ assertEquals(37, someUser.get("ANNO", context, null));
+ assertEquals("male", someUser.get("gender", context, null));
+ assertEquals("male", someUser.get("sex", context, null));
+ assertEquals("male", someUser.get("Sex", context, null));
assertNull(someUser.get("Gender", context, null)); // Only aliases are case insensitive
}
diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/validxml/root.xml b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/validxml/root.xml
index 82ff7afb186..e7a5f132aaf 100644
--- a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/validxml/root.xml
+++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/validxml/root.xml
@@ -4,6 +4,6 @@
<query-profile id="root" type="rootType">
<field name="hits">30</field>
- <field name="traceLevel">3</field>
+ <field name="trace.level">3</field>
</query-profile>
diff --git a/container-search/src/test/java/com/yahoo/search/searchchain/test/TraceTestCase.java b/container-search/src/test/java/com/yahoo/search/searchchain/test/TraceTestCase.java
index 90da5a5b746..04b1fd85872 100644
--- a/container-search/src/test/java/com/yahoo/search/searchchain/test/TraceTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/searchchain/test/TraceTestCase.java
@@ -48,11 +48,33 @@ public class TraceTestCase {
public void testTracingOnIncorrectAPIUseParallel() {
assertTracing(false,true);
}
-
+
+ @Test
+ public void testTraceWithQuery() {
+ testQueryInTrace(true, "trace.query=true");
+ testQueryInTrace(false, "trace.query=false");
+ testQueryInTrace(true, "");
+ }
+
+ private void testQueryInTrace(boolean expectQueryInTrace, String queryParameters) {
+ Query query = new Query("?query=foo&trace.level=1&" + queryParameters);
+ Chain<Searcher> chain = new Chain<>(new Tracer("tracer1", true));
+ Execution execution = new Execution(chain, Execution.Context.createContextStub());
+ Result result = execution.search(query);
+ Iterator<String> trace = collectTrace(query).iterator();
+ assertEquals("(level start)", trace.next());
+ assertEquals(" No query profile is used", trace.next());
+ assertEquals(" (level start)", trace.next());
+ if (expectQueryInTrace)
+ assertEquals(" During tracer1: 0: [WEAKAND(100) foo]", trace.next());
+ else
+ assertEquals(" During tracer1: 0", trace.next());
+ }
+
@Test
public void testTraceInvocationsUnfillableHits() {
final int traceLevel = 5;
- Query query = new Query("?tracelevel=" + traceLevel);
+ Query query = new Query("?trace.level=" + traceLevel);
Chain<Searcher> forkingChain = new Chain<>(new Tracer("tracer1"),
new Tracer("tracer2"),
new Backend("backend1", false));
@@ -118,7 +140,8 @@ public class TraceTestCase {
private void assertTracing(boolean carryOverContext, boolean parallel) {
Query query = new Query("?tracelevel=1");
- query.trace("Before execution",1);
+ assertEquals(1, query.getTrace().getLevel());
+ query.trace("Before execution", 1);
Chain<Searcher> forkingChain = new Chain<>(new Tracer("forker"),
new Forker(carryOverContext, parallel,
new Tracer("branch 1") ,
@@ -222,8 +245,8 @@ public class TraceTestCase {
private static class TraceCollector extends TraceVisitor {
- private List<String> trace = new ArrayList<>();
- private StringBuilder indent = new StringBuilder();
+ private final List<String> trace = new ArrayList<>();
+ private final StringBuilder indent = new StringBuilder();
@Override
public void entering(TraceNode node) {
@@ -249,30 +272,38 @@ public class TraceTestCase {
private static class Tracer extends Searcher {
- private String name;
+ private final String name;
+ private final boolean traceQuery;
+
private int counter = 0;
public Tracer(String name) {
+ this(name, false);
+ }
+
+ public Tracer(String name, boolean traceQuery) {
super(new ComponentId(name));
this.name = name;
+ this.traceQuery = traceQuery;
}
@Override
public Result search(Query query, Execution execution) {
- query.trace("During " + name + ": " + (counter++),1);
+ query.trace("During " + name + ": " + (counter++), traceQuery, 1);
return execution.search(query);
}
+
}
private static class Forker extends Searcher {
- private List<Searcher> branches;
+ private final List<Searcher> branches;
/** If true, this is using the api as recommended, if false, it is not */
- private boolean carryOverContext;
+ private final boolean carryOverContext;
/** If true, simulate parallel execution by cloning the query */
- private boolean parallel;
+ private final boolean parallel;
public Forker(boolean carryOverContext, boolean parallel, Searcher ... branches) {
this.carryOverContext = carryOverContext;
@@ -280,7 +311,6 @@ public class TraceTestCase {
this.branches = Arrays.asList(branches);
}
- @SuppressWarnings("deprecation")
@Override
public Result search(Query query, Execution execution) {
Result result = execution.search(query);
@@ -319,6 +349,7 @@ public class TraceTestCase {
result.hits().add(hit1);
return result;
}
+
}
}
diff --git a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
index 5c5d9006d1a..7cd7e20b76f 100644
--- a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
@@ -552,7 +552,7 @@ public class QueryTestCase {
@Test
public void testTracing() {
Query q = new Query("?query=foo&type=all&traceLevel=2");
- assertEquals(2, q.getTraceLevel());
+ assertEquals(2, q.getTrace().getLevel());
q.trace(true, 1, "trace1");
q.trace(false,2, "trace2");
q.trace(true, 3, "Ignored");
@@ -571,7 +571,7 @@ public class QueryTestCase {
@Test
public void testNullTracing() {
Query q = new Query("?query=foo&traceLevel=2");
- assertEquals(2, q.getTraceLevel());
+ assertEquals(2, q.getTrace().getLevel());
q.trace(false,2, "trace2 ", null);
Set<String> traces = new HashSet<>();
for (String trace : q.getContext(true).getTrace().traceNode().descendants(String.class))
@@ -582,8 +582,8 @@ public class QueryTestCase {
@Test
public void testExplain() {
Query q = new Query("?query=foo&explainLevel=2");
- assertEquals(2, q.getExplainLevel());
- assertEquals(0, q.getTraceLevel());
+ assertEquals(2, q.getTrace().getExplainLevel());
+ assertEquals(0, q.getTrace().getLevel());
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcherTestCase.java b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcherTestCase.java
index 861be9a3ade..835235a593c 100644
--- a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcherTestCase.java
@@ -170,10 +170,10 @@ public class VdsStreamingSearcherTestCase {
} else if (i == 1) {
query.getPresentation().setSummary("summary");
} else if (i == 2) {
- query.setTraceLevel(100);
+ query.getTrace().setLevel(100);
} else if (i == 3) {
query.getPresentation().setSummary("summary");
- query.setTraceLevel(100);
+ query.getTrace().setLevel(100);
}
queries[i] = query;
}