diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-06-15 13:23:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-15 13:23:35 +0200 |
commit | f1b86b698d629afb08569c9fd0f39dfb1da71f0d (patch) | |
tree | de2815334afc9575dffff0423869c276b08351ee /container-search | |
parent | 9f7b3b4211cdafd9f8fa680443bf7224d974b831 (diff) | |
parent | a0f18f5183b1e43163bbfbbfa6f6fff86149d014 (diff) |
Merge pull request #23097 from vespa-engine/bratseth/trace
Bratseth/trace
Diffstat (limited to 'container-search')
36 files changed, 536 insertions, 338 deletions
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; } |