fix #2682 add api.ping.es.fields and api.json.response.exception.included

This commit is contained in:
Shinsuke Sugaya 2022-09-04 18:51:25 +09:00
parent ea5d0e97ad
commit c64e957ce2
5 changed files with 129 additions and 23 deletions

View file

@ -23,10 +23,13 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codelibs.core.CoreLibConstants;
import org.codelibs.core.lang.StringUtil;
import org.codelibs.fess.Constants;
@ -37,6 +40,8 @@ import org.lastaflute.web.util.LaResponseUtil;
public abstract class BaseJsonApiManager extends BaseApiManager {
private static final Logger logger = LogManager.getLogger(BaseJsonApiManager.class);
protected String mimeType = "application/json";
protected void writeJsonResponse(final int status, final String body, final Throwable t) {
@ -57,13 +62,24 @@ public abstract class BaseJsonApiManager extends BaseApiManager {
} else {
sb.append(t.getMessage());
}
final StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
sb.append(" [ ").append(sw.toString()).append(" ]");
try {
sw.close();
try (final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw)) {
t.printStackTrace(pw);
pw.flush();
sb.append(" [ ").append(sw.toString()).append(" ]");
} catch (final IOException ignore) {}
writeJsonResponse(status, body, sb.toString());
final String message;
if (Constants.TRUE.equalsIgnoreCase(ComponentUtil.getFessConfig().getApiJsonResponseExceptionIncluded())) {
message = sb.toString();
} else {
final String errorCode = UUID.randomUUID().toString();
message = "error_code:" + errorCode;
if (logger.isDebugEnabled()) {
logger.debug("[{}] {}", errorCode, sb.toString().replace("\n", "\\n"));
} else {
logger.warn("[{}] {}", errorCode, t.getMessage());
}
}
writeJsonResponse(status, body, message);
}
protected void writeJsonResponse(final int status, final String body, final String errMsg) {

View file

@ -19,11 +19,13 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.text.StringEscapeUtils;
import org.codelibs.core.lang.StringUtil;
import org.codelibs.fess.Constants;
import org.codelibs.fess.util.ComponentUtil;
import org.codelibs.fess.util.SearchEngineUtil;
import org.lastaflute.di.exception.IORuntimeException;
import org.opensearch.action.admin.cluster.health.ClusterHealthResponse;
import org.opensearch.cluster.health.ClusterHealthStatus;
import org.opensearch.common.xcontent.XContentType;
@ -57,23 +59,54 @@ public class PingResponse {
status = response.getStatus() == ClusterHealthStatus.RED ? 1 : 0;
clusterName = response.getClusterName();
clusterStatus = response.getStatus().toString();
final Set<String> fieldSet = ComponentUtil.getFessConfig().getApiPingEsFieldSet();
try (OutputStream out = SearchEngineUtil.getXContentBuilderOutputStream((builder, params) -> {
builder.startObject();
builder.field(CLUSTER_NAME, response.getClusterName());
builder.field(STATUS, response.getStatus().name().toLowerCase(Locale.ROOT));
builder.field(TIMED_OUT, response.isTimedOut());
builder.field(NUMBER_OF_NODES, response.getNumberOfNodes());
builder.field(NUMBER_OF_DATA_NODES, response.getNumberOfDataNodes());
builder.field(ACTIVE_PRIMARY_SHARDS, response.getActivePrimaryShards());
builder.field(ACTIVE_SHARDS, response.getActiveShards());
builder.field(RELOCATING_SHARDS, response.getRelocatingShards());
builder.field(INITIALIZING_SHARDS, response.getInitializingShards());
builder.field(UNASSIGNED_SHARDS, response.getUnassignedShards());
builder.field(DELAYED_UNASSIGNED_SHARDS, response.getDelayedUnassignedShards());
builder.field(NUMBER_OF_PENDING_TASKS, response.getNumberOfPendingTasks());
builder.field(NUMBER_OF_IN_FLIGHT_FETCH, response.getNumberOfInFlightFetch());
builder.field(TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS, response.getTaskMaxWaitingTime().getMillis());
builder.field(ACTIVE_SHARDS_PERCENT_AS_NUMBER, response.getActiveShardsPercent());
if (fieldSet.contains(CLUSTER_NAME)) {
builder.field(CLUSTER_NAME, response.getClusterName());
}
if (fieldSet.contains(STATUS)) {
builder.field(STATUS, response.getStatus().name().toLowerCase(Locale.ROOT));
}
if (fieldSet.contains(TIMED_OUT)) {
builder.field(TIMED_OUT, response.isTimedOut());
}
if (fieldSet.contains(NUMBER_OF_NODES)) {
builder.field(NUMBER_OF_NODES, response.getNumberOfNodes());
}
if (fieldSet.contains(NUMBER_OF_DATA_NODES)) {
builder.field(NUMBER_OF_DATA_NODES, response.getNumberOfDataNodes());
}
if (fieldSet.contains(ACTIVE_PRIMARY_SHARDS)) {
builder.field(ACTIVE_PRIMARY_SHARDS, response.getActivePrimaryShards());
}
if (fieldSet.contains(ACTIVE_SHARDS)) {
builder.field(ACTIVE_SHARDS, response.getActiveShards());
}
if (fieldSet.contains(RELOCATING_SHARDS)) {
builder.field(RELOCATING_SHARDS, response.getRelocatingShards());
}
if (fieldSet.contains(INITIALIZING_SHARDS)) {
builder.field(INITIALIZING_SHARDS, response.getInitializingShards());
}
if (fieldSet.contains(UNASSIGNED_SHARDS)) {
builder.field(UNASSIGNED_SHARDS, response.getUnassignedShards());
}
if (fieldSet.contains(DELAYED_UNASSIGNED_SHARDS)) {
builder.field(DELAYED_UNASSIGNED_SHARDS, response.getDelayedUnassignedShards());
}
if (fieldSet.contains(NUMBER_OF_PENDING_TASKS)) {
builder.field(NUMBER_OF_PENDING_TASKS, response.getNumberOfPendingTasks());
}
if (fieldSet.contains(NUMBER_OF_IN_FLIGHT_FETCH)) {
builder.field(NUMBER_OF_IN_FLIGHT_FETCH, response.getNumberOfInFlightFetch());
}
if (fieldSet.contains(TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS)) {
builder.field(TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS, response.getTaskMaxWaitingTime().getMillis());
}
if (fieldSet.contains(ACTIVE_SHARDS_PERCENT_AS_NUMBER)) {
builder.field(ACTIVE_SHARDS_PERCENT_AS_NUMBER, response.getActiveShardsPercent());
}
builder.endObject();
return builder;
}, XContentType.JSON)) {
@ -82,7 +115,7 @@ public class PingResponse {
message = "{}";
}
} catch (final IOException e) {
message = "{ \"error\" : \"" + StringEscapeUtils.escapeJson(e.getMessage()) + "\"}";
throw new IORuntimeException(e);
}
}

View file

@ -250,6 +250,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. */
String API_JSON_RESPONSE_HEADERS = "api.json.response.headers";
/** The key of the configuration. e.g. false */
String API_JSON_RESPONSE_EXCEPTION_INCLUDED = "api.json.response.exception.included";
/** The key of the configuration. e.g. */
String API_GSA_RESPONSE_HEADERS = "api.gsa.response.headers";
@ -274,6 +277,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. false */
String API_JSONP_ENABLED = "api.jsonp.enabled";
/** The key of the configuration. e.g. status,timed_out */
String API_PING_ES_FIELDS = "api.ping.es.fields";
/** The key of the configuration. e.g. */
String VIRTUAL_HOST_HEADERS = "virtual.host.headers";
@ -2298,6 +2304,20 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
Integer getApiJsonResponseHeadersAsInteger();
/**
* Get the value for the key 'api.json.response.exception.included'. <br>
* The value is, e.g. false <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getApiJsonResponseExceptionIncluded();
/**
* Is the property for the key 'api.json.response.exception.included' true? <br>
* The value is, e.g. false <br>
* @return The determination, true or false. (if not found, exception but basically no way)
*/
boolean isApiJsonResponseExceptionIncluded();
/**
* Get the value for the key 'api.gsa.response.headers'. <br>
* The value is, e.g. <br>
@ -2392,6 +2412,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
boolean isApiJsonpEnabled();
/**
* Get the value for the key 'api.ping.es.fields'. <br>
* The value is, e.g. status,timed_out <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getApiPingEsFields();
/**
* Get the value for the key 'virtual.host.headers'. <br>
* The value is, e.g. <br>
@ -7645,6 +7672,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return getAsInteger(FessConfig.API_JSON_RESPONSE_HEADERS);
}
public String getApiJsonResponseExceptionIncluded() {
return get(FessConfig.API_JSON_RESPONSE_EXCEPTION_INCLUDED);
}
public boolean isApiJsonResponseExceptionIncluded() {
return is(FessConfig.API_JSON_RESPONSE_EXCEPTION_INCLUDED);
}
public String getApiGsaResponseHeaders() {
return get(FessConfig.API_GSA_RESPONSE_HEADERS);
}
@ -7697,6 +7732,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return is(FessConfig.API_JSONP_ENABLED);
}
public String getApiPingEsFields() {
return get(FessConfig.API_PING_ES_FIELDS);
}
public String getVirtualHostHeaders() {
return get(FessConfig.VIRTUAL_HOST_HEADERS);
}
@ -10426,6 +10465,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
defaultMap.put(FessConfig.API_SEARCH_ACCEPT_REFERERS, "");
defaultMap.put(FessConfig.API_SEARCH_SCROLL, "false");
defaultMap.put(FessConfig.API_JSON_RESPONSE_HEADERS, "");
defaultMap.put(FessConfig.API_JSON_RESPONSE_EXCEPTION_INCLUDED, "false");
defaultMap.put(FessConfig.API_GSA_RESPONSE_HEADERS, "");
defaultMap.put(FessConfig.API_DASHBOARD_RESPONSE_HEADERS, "");
defaultMap.put(FessConfig.API_CORS_ALLOW_ORIGIN, "*");
@ -10434,6 +10474,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
defaultMap.put(FessConfig.API_CORS_ALLOW_HEADERS, "Origin, Content-Type, Accept, Authorization, X-Requested-With");
defaultMap.put(FessConfig.API_CORS_ALLOW_CREDENTIALS, "true");
defaultMap.put(FessConfig.API_JSONP_ENABLED, "false");
defaultMap.put(FessConfig.API_PING_ES_FIELDS, "status,timed_out");
defaultMap.put(FessConfig.VIRTUAL_HOST_HEADERS, "");
defaultMap.put(FessConfig.HTTP_PROXY_HOST, "");
defaultMap.put(FessConfig.HTTP_PROXY_PORT, "8080");

View file

@ -70,6 +70,8 @@ import org.opensearch.search.sort.SortOrder;
public interface FessProp {
String API_PING_ES_FIELD_SET = "apiPingEsFieldSet";
String QUERY_HIGHLIGHT_TERMINAL_CHARS = "queryHighlightTerminalChars";
String QUERY_HIGHLIGHT_BOUNDARY_CHARS = "queryHighlightBoundaryChars";
@ -2113,4 +2115,16 @@ public interface FessProp {
return split(getSearchlogRequestHeaders(), ",")
.get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).toArray(n -> new String[n]));
}
String getApiPingEsFields();
default Set<String> getApiPingEsFieldSet() {
Set<String> value = (Set<String>) propMap.get(API_PING_ES_FIELD_SET);
if (value == null) {
value = split(getApiPingEsFields(), ",")
.get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.toSet()));
propMap.put(API_PING_ES_FIELD_SET, value);
}
return value;
}
}

View file

@ -170,6 +170,7 @@ api.admin.access.permissions=Radmin-api
api.search.accept.referers=
api.search.scroll=false
api.json.response.headers=
api.json.response.exception.included=false
api.gsa.response.headers=
api.dashboard.response.headers=
api.cors.allow.origin=*
@ -178,6 +179,7 @@ api.cors.max.age=3600
api.cors.allow.headers=Origin, Content-Type, Accept, Authorization, X-Requested-With
api.cors.allow.credentials=true
api.jsonp.enabled=false
api.ping.es.fields=status,timed_out
# Virtual Host: Host:fess.codelibs.org=fess