Cat API: Add wildcard support for header names

This adds wildcard support (simple regexes) for specifying header names.
Aliases are supported as well.

Closes #10811
This commit is contained in:
Alexander Reelsen 2015-05-27 12:05:32 +02:00
parent 5384e4712a
commit fc224a0de8
4 changed files with 141 additions and 7 deletions

View File

@ -66,6 +66,10 @@ only those columns to appear.
192.168.56.30 9300 43.9 Ramsey, Doug 192.168.56.30 9300 43.9 Ramsey, Doug
-------------------------------------------------- --------------------------------------------------
You can also request multiple columns using simple wildcards like
`/_cat/thread_pool?h=ip,bulk.*` to get all headers (or aliases) starting
with `bulk.`.
[float] [float]
[[numeric-formats]] [[numeric-formats]]
=== Numeric formats === Numeric formats

View File

@ -29,6 +29,18 @@
/ #pid id host ip port / #pid id host ip port
^ (\d+ \s+ \S{4} \s+ \S+ \s+ (\d{1,3}\.){3}\d{1,3} \s+ (\d+|-) \s+ \n)+ $/ ^ (\d+ \s+ \S{4} \s+ \S+ \s+ (\d{1,3}\.){3}\d{1,3} \s+ (\d+|-) \s+ \n)+ $/
- do:
cat.thread_pool:
h: bulk.m*
- match:
$body: |
/^ bulk.max \s+ bulk.min \s+ \n
(\s+ \d+ \s+ \d+ \s+ \n)+ $/
#(\s+ \d+ \s+ \d+ \n)+ $/
- do: - do:
cat.thread_pool: cat.thread_pool:
h: id,ba,fa,gea,ga,ia,maa,ma,oa,pa h: id,ba,fa,gea,ga,ia,maa,ma,oa,pa

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.Table; import org.elasticsearch.common.Table;
import org.elasticsearch.common.io.UTF8StreamWriter; import org.elasticsearch.common.io.UTF8StreamWriter;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.SizeValue; import org.elasticsearch.common.unit.SizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
@ -32,8 +33,7 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.*; import org.elasticsearch.rest.*;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.List;
/** /**
*/ */
@ -96,11 +96,12 @@ public class RestTable {
return new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, bytesOut.bytes()); return new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, bytesOut.bytes());
} }
private static List<DisplayHeader> buildDisplayHeaders(Table table, RestRequest request) { static List<DisplayHeader> buildDisplayHeaders(Table table, RestRequest request) {
String pHeaders = request.param("h");
List<DisplayHeader> display = new ArrayList<>(); List<DisplayHeader> display = new ArrayList<>();
if (pHeaders != null) { if (request.hasParam("h")) {
for (String possibility : Strings.splitStringByCommaToArray(pHeaders)) { Set<String> headers = expandHeadersFromRequest(table, request);
for (String possibility : headers) {
DisplayHeader dispHeader = null; DisplayHeader dispHeader = null;
if (table.getAsMap().containsKey(possibility)) { if (table.getAsMap().containsKey(possibility)) {
@ -147,6 +148,41 @@ public class RestTable {
return display; return display;
} }
/**
* Extracts all the required fields from the RestRequest 'h' parameter. In order to support wildcards like
* 'bulk.*' this needs potentially parse all the configured headers and its aliases and needs to ensure
* that everything is only added once to the returned headers, even if 'h=bulk.*.bulk.*' is specified
* or some headers are contained twice due to matching aliases
*/
private static Set<String> expandHeadersFromRequest(Table table, RestRequest request) {
Set<String> headers = new LinkedHashSet<>(table.getHeaders().size());
Map<String, Table.Cell> headerMap = table.getHeaderMap();
// check headers and aliases
for (String header : Strings.splitStringByCommaToArray(request.param("h"))) {
if (Regex.isSimpleMatchPattern(header)) {
for (Map.Entry<String, Table.Cell> configuredHeaderEntry : headerMap.entrySet()) {
String configuredHeader = configuredHeaderEntry.getKey();
if (Regex.simpleMatch(header, configuredHeader)) {
headers.add(configuredHeader);
} else if (configuredHeaderEntry.getValue().attr.containsKey("alias")) {
String[] aliases = Strings.splitStringByCommaToArray(configuredHeaderEntry.getValue().attr.get("alias"));
for (String alias : aliases) {
if (Regex.simpleMatch(header, alias)) {
headers.add(configuredHeader);
break;
}
}
}
}
} else {
headers.add(header);
}
}
return headers;
}
public static int[] buildHelpWidths(Table table, RestRequest request) { public static int[] buildHelpWidths(Table table, RestRequest request) {
int[] width = new int[3]; int[] width = new int[3];
for (Table.Cell cell : table.getHeaders()) { for (Table.Cell cell : table.getHeaders()) {

View File

@ -0,0 +1,82 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.rest.action.support;
import org.elasticsearch.common.Table;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.elasticsearch.rest.action.support.RestTable.buildDisplayHeaders;
import static org.hamcrest.Matchers.*;
public class RestTableTest extends ElasticsearchTestCase {
private Table table = new Table();
private FakeRestRequest restRequest = new FakeRestRequest();
@Before
public void setup() {
table.startHeaders();
table.addCell("bulk.foo", "alias:f;desc:foo");
table.addCell("bulk.bar", "alias:b;desc:bar");
// should be matched as well due to the aliases
table.addCell("aliasedBulk", "alias:bulkWhatever;desc:bar");
table.addCell("aliasedSecondBulk", "alias:foobar,bulkolicious,bulkotastic;desc:bar");
// no match
table.addCell("unmatched", "alias:un.matched;desc:bar");
// invalid alias
table.addCell("invalidAliasesBulk", "alias:,,,;desc:bar");
table.endHeaders();
}
@Test
public void testThatDisplayHeadersSupportWildcards() throws Exception {
restRequest.params().put("h", "bulk*");
List<RestTable.DisplayHeader> headers = buildDisplayHeaders(table, restRequest);
List<String> headerNames = getHeaderNames(headers);
assertThat(headerNames, containsInAnyOrder("bulk.foo", "bulk.bar", "aliasedBulk", "aliasedSecondBulk"));
assertThat(headerNames, not(hasItem("unmatched")));
}
@Test
public void testThatDisplayHeadersAreNotAddedTwice() throws Exception {
restRequest.params().put("h", "nonexistent,bulk*,bul*");
List<RestTable.DisplayHeader> headers = buildDisplayHeaders(table, restRequest);
List<String> headerNames = getHeaderNames(headers);
assertThat(headerNames, containsInAnyOrder("bulk.foo", "bulk.bar", "aliasedBulk", "aliasedSecondBulk"));
assertThat(headerNames, not(hasItem("unmatched")));
}
private List<String> getHeaderNames(List<RestTable.DisplayHeader> headers) {
List<String> headerNames = new ArrayList<>();
for (RestTable.DisplayHeader header : headers) {
headerNames.add(header.name);
}
return headerNames;
}
}