Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create health_stats API for query insights #122

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@
import org.opensearch.env.NodeEnvironment;
import org.opensearch.plugin.insights.core.listener.QueryInsightsListener;
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 @@ -107,12 +110,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
Loading