void traceQuery(String sourceName, DispatchPhase phase, Query query, int offset, int hits, int level, Optional<String> quotedSummaryClass) {
        if ((query.getTrace().getLevel()<level) || !query.getTrace().getQuery()) return;

        StringBuilder s = new StringBuilder();
        s.append(sourceName).append(" ").append(phase.name().toLowerCase()).append(" to dispatch: ")
                .append("query=[")
                .append(query.getModel().getQueryTree().getRoot().toString())
                .append("]");

        s.append(" timeout=").append(query.getTimeout()).append("ms");

        s.append(" offset=")
                .append(offset)
                .append(" hits=")
                .append(hits);

        if (query.getRanking().hasRankProfile()) {
            s.append(" rankprofile[")
                .append(query.getRanking().getProfile())
                .append("]");
        }

        if (query.getRanking().getFreshness() != null) {
            s.append(" freshness=")
                    .append(query.getRanking().getFreshness().getRefTime());
        }

        if (query.getRanking().getSorting() != null) {
            s.append(" sortspec=")
                    .append(query.getRanking().getSorting().fieldOrders().toString());
        }

        if (query.getRanking().getLocation() != null) {
            s.append(" location=")
                    .append(query.getRanking().getLocation().backendString());
        }

        if (query.getGroupingSessionCache()) {
            s.append(" groupingSessionCache=true");
        }
        if (query.getRanking().getQueryCache()) {
            s.append(" ranking.queryCache=true");
        }
        if (query.getGroupingSessionCache() || query.getRanking().getQueryCache()) {
            s.append(" sessionId=").append(query.getSessionId(getServerId()));
        }

        if (query.getTrace().getLevel() >= (level+3)) {
            List<Grouping> grouping = GroupingExecutor.getGroupingList(query);
            s.append(" grouping=").append(grouping.size()).append(" : ");
            for (Grouping g : grouping) {
                s.append(g.toString());
            }
        }

        if ( ! query.getRanking().getProperties().isEmpty()) {
            s.append(" rankproperties=")
                    .append(query.getRanking().getProperties().toString());
        }

        if ( ! query.getRanking().getFeatures().isEmpty()) {
            s.append(" rankfeatures=")
                    .append(query.getRanking().getFeatures().toString());
        }

        if (query.getModel().getRestrict() != null) {
            s.append(" restrict=").append(query.getModel().getRestrict().toString());
        }

        quotedSummaryClass.ifPresent((String summaryClass) -> s.append(" summary=").append(summaryClass));

        query.trace(s.toString(), false, level);
        if (query.getTrace().isTraceable(level + 1) && query.getTrace().getQuery()) {
            query.trace("Current state of query tree: "
                            + new TextualQueryRepresentation(query.getModel().getQueryTree().getRoot()),
                    false, level + 1);
        }
        if (query.getTrace().isTraceable(level + 2) && query.getTrace().getQuery()) {
            query.trace("YQL+ representation: " + query.yqlRepresentation(), level + 2);
        }
    }
Returns whether we need to send the query when fetching summaries.
This is necessary if the query requests summary features or dynamic snippeting.
container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackend.java