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:
parent
5384e4712a
commit
fc224a0de8
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue