Skip to content

Commit

Permalink
Create healthstats API for query insights (#122)
Browse files Browse the repository at this point in the history
Signed-off-by: Chenyang Ji <cyji@amazon.com>
(cherry picked from commit e4c6b8f)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Sep 27, 2024
1 parent 71b84c4 commit 91fe604
Show file tree
Hide file tree
Showing 18 changed files with 965 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@
import org.opensearch.plugin.insights.core.listener.QueryInsightsListener;
import org.opensearch.plugin.insights.core.metrics.OperationalMetricsCounter;
import org.opensearch.plugin.insights.core.service.QueryInsightsService;
import org.opensearch.plugin.insights.rules.action.health_stats.HealthStatsAction;
import org.opensearch.plugin.insights.rules.action.top_queries.TopQueriesAction;
import org.opensearch.plugin.insights.rules.resthandler.health_stats.RestHealthStatsAction;
import org.opensearch.plugin.insights.rules.resthandler.top_queries.RestTopQueriesAction;
import org.opensearch.plugin.insights.rules.transport.health_stats.TransportHealthStatsAction;
import org.opensearch.plugin.insights.rules.transport.top_queries.TransportTopQueriesAction;
import org.opensearch.plugin.insights.settings.QueryCategorizationSettings;
import org.opensearch.plugin.insights.settings.QueryInsightsSettings;
Expand Down Expand Up @@ -110,12 +113,15 @@ public List<RestHandler> getRestHandlers(
final IndexNameExpressionResolver indexNameExpressionResolver,
final Supplier<DiscoveryNodes> nodesInCluster
) {
return List.of(new RestTopQueriesAction());
return List.of(new RestTopQueriesAction(), new RestHealthStatsAction());
}

@Override
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
return List.of(new ActionPlugin.ActionHandler<>(TopQueriesAction.INSTANCE, TransportTopQueriesAction.class));
return List.of(
new ActionPlugin.ActionHandler<>(TopQueriesAction.INSTANCE, TransportTopQueriesAction.class),
new ActionPlugin.ActionHandler<>(HealthStatsAction.INSTANCE, TransportHealthStatsAction.class)
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.plugin.insights.rules.action.health_stats;

import org.opensearch.action.ActionType;

/**
* Transport action for cluster/node level query insights plugin health stats.
*/
public class HealthStatsAction extends ActionType<HealthStatsResponse> {

/**
* The HealthStatsAction Instance.
*/
public static final HealthStatsAction INSTANCE = new HealthStatsAction();
/**
* The name of this Action
*/
public static final String NAME = "cluster:admin/opensearch/insights/health_stats";

private HealthStatsAction() {
super(NAME, HealthStatsResponse::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.plugin.insights.rules.action.health_stats;

import java.io.IOException;
import org.opensearch.action.support.nodes.BaseNodeResponse;
import org.opensearch.cluster.node.DiscoveryNode;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.plugin.insights.rules.model.healthStats.QueryInsightsHealthStats;

/**
* Holds the health stats retrieved from a node
*/
public class HealthStatsNodeResponse extends BaseNodeResponse implements ToXContentObject {
/** The health stats retrieved from one node */
private final QueryInsightsHealthStats healthStats;

/**
* Create the HealthStatsNodeResponse Object from StreamInput
* @param in A {@link StreamInput} object.
* @throws IOException IOException
*/
public HealthStatsNodeResponse(final StreamInput in) throws IOException {
super(in);
healthStats = new QueryInsightsHealthStats(in);
}

/**
* Create the HealthStatsNodeResponse Object
* @param node A node that is part of the cluster.
* @param healthStats A list of HealthStats from nodes.
*/
public HealthStatsNodeResponse(final DiscoveryNode node, final QueryInsightsHealthStats healthStats) {
super(node);
this.healthStats = healthStats;
}

@Override
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
builder.startObject(this.getNode().getId());
healthStats.toXContent(builder, params);
return builder.endObject();
}

@Override
public void writeTo(final StreamOutput out) throws IOException {
super.writeTo(out);
healthStats.writeTo(out);

}

/**
* Get health stats
*
* @return the health stats records in this node response
*/
public QueryInsightsHealthStats getHealthStats() {
return healthStats;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.plugin.insights.rules.action.health_stats;

import java.io.IOException;
import org.opensearch.action.support.nodes.BaseNodesRequest;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;

/**
* A request to get cluster/node level health stats information.
*/
public class HealthStatsRequest extends BaseNodesRequest<HealthStatsRequest> {
/**
* Constructor for HealthStatsRequest
*
* @param in A {@link StreamInput} object.
* @throws IOException if the stream cannot be deserialized.
*/
public HealthStatsRequest(final StreamInput in) throws IOException {
super(in);
}

/**
* Get health stats from nodes based on the nodes ids specified.
* If none are passed, cluster level health stats will be returned.
*
* @param nodesIds the nodeIds specified in the request
*/
public HealthStatsRequest(final String... nodesIds) {
super(nodesIds);
}

@Override
public void writeTo(final StreamOutput out) throws IOException {
super.writeTo(out);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.plugin.insights.rules.action.health_stats;

import java.io.IOException;
import java.util.List;
import org.opensearch.action.FailedNodeException;
import org.opensearch.action.support.nodes.BaseNodesResponse;
import org.opensearch.cluster.ClusterName;
import org.opensearch.common.xcontent.XContentFactory;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.xcontent.ToXContentFragment;
import org.opensearch.core.xcontent.XContentBuilder;

/**
* Transport response for cluster/node level health stats
*/
public class HealthStatsResponse extends BaseNodesResponse<HealthStatsNodeResponse> implements ToXContentFragment {
/**
* Constructor for HealthStatsNodeResponseResponse.
*
* @param in A {@link StreamInput} object.
* @throws IOException if the stream cannot be deserialized.
*/
public HealthStatsResponse(final StreamInput in) throws IOException {
super(in);
}

/**
* Constructor for HealthStatsResponse
*
* @param clusterName The current cluster name
* @param nodes A list that contains health stats from all nodes
* @param failures A list that contains FailedNodeException
*/
public HealthStatsResponse(
final ClusterName clusterName,
final List<HealthStatsNodeResponse> nodes,
final List<FailedNodeException> failures
) {
super(clusterName, nodes, failures);
}

@Override
protected List<HealthStatsNodeResponse> readNodesFrom(final StreamInput in) throws IOException {
return in.readList(HealthStatsNodeResponse::new);
}

@Override
protected void writeNodesTo(final StreamOutput out, final List<HealthStatsNodeResponse> nodes) throws IOException {
out.writeList(nodes);
}

@Override
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
final List<HealthStatsNodeResponse> results = getNodes();
builder.startObject();
for (HealthStatsNodeResponse nodeResponse : results) {
nodeResponse.toXContent(builder, params);
}
return builder.endObject();
}

@Override
public String toString() {
try {
final XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint();
builder.startObject();
this.toXContent(builder, EMPTY_PARAMS);
builder.endObject();
return builder.toString();
} catch (IOException e) {
return "{ \"error\" : \"" + e.getMessage() + "\"}";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/**
* Transport Actions, Requests and Responses for Query Insights Health Stats
*/
package org.opensearch.plugin.insights.rules.action.health_stats;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.plugin.insights.rules.resthandler.health_stats;

import static org.opensearch.plugin.insights.settings.QueryInsightsSettings.QUERY_INSIGHTS_HEALTH_STATS_URI;
import static org.opensearch.rest.RestRequest.Method.GET;

import java.util.List;
import java.util.Set;
import org.opensearch.client.node.NodeClient;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.common.Strings;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.plugin.insights.rules.action.health_stats.HealthStatsAction;
import org.opensearch.plugin.insights.rules.action.health_stats.HealthStatsRequest;
import org.opensearch.plugin.insights.rules.action.health_stats.HealthStatsResponse;
import org.opensearch.rest.BaseRestHandler;
import org.opensearch.rest.BytesRestResponse;
import org.opensearch.rest.RestChannel;
import org.opensearch.rest.RestRequest;
import org.opensearch.rest.RestResponse;
import org.opensearch.rest.action.RestResponseListener;

/**
* Rest action to get operational health stats of the query insights plugin
*/
public class RestHealthStatsAction extends BaseRestHandler {
/**
* Constructor for RestHealthStatsAction
*/
public RestHealthStatsAction() {}

@Override
public List<Route> routes() {
return List.of(new Route(GET, QUERY_INSIGHTS_HEALTH_STATS_URI));
}

@Override
public String getName() {
return "query_insights_health_stats_action";
}

@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) {
final HealthStatsRequest healthStatsRequest = prepareRequest(request);
healthStatsRequest.timeout(request.param("timeout"));

return channel -> client.execute(HealthStatsAction.INSTANCE, healthStatsRequest, healthStatsResponse(channel));
}

static HealthStatsRequest prepareRequest(final RestRequest request) {
final String[] nodesIds = Strings.splitStringByCommaToArray(request.param("nodeId"));
return new HealthStatsRequest(nodesIds);
}

@Override
protected Set<String> responseParams() {
return Settings.FORMAT_PARAMS;
}

@Override
public boolean canTripCircuitBreaker() {
return false;
}

RestResponseListener<HealthStatsResponse> healthStatsResponse(final RestChannel channel) {
return new RestResponseListener<>(channel) {
@Override
public RestResponse buildResponse(final HealthStatsResponse response) throws Exception {
return new BytesRestResponse(RestStatus.OK, response.toXContent(channel.newBuilder(), ToXContent.EMPTY_PARAMS));
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/**
* Rest Handlers for Query Insights Health Stats
*/
package org.opensearch.plugin.insights.rules.resthandler.health_stats;
Loading

0 comments on commit 91fe604

Please sign in to comment.