fix #1764 download logs on maintenance page
This commit is contained in:
parent
9dbe3eaaec
commit
50ba9b0b1b
7 changed files with 201 additions and 5 deletions
|
@ -20,7 +20,7 @@ import javax.validation.constraints.Size;
|
|||
import org.codelibs.fess.Constants;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
|
||||
public class UpgradeForm {
|
||||
public class ActionForm {
|
||||
@Size(max = 10)
|
||||
public String replaceAliases = Constants.ON;
|
||||
|
|
@ -15,15 +15,31 @@
|
|||
*/
|
||||
package org.codelibs.fess.app.web.admin.maintenance;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.codelibs.core.io.CopyUtil;
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.curl.CurlResponse;
|
||||
import org.codelibs.fess.app.web.base.FessAdminAction;
|
||||
import org.codelibs.fess.es.client.FessEsClient;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig.SimpleImpl;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.lastaflute.web.Execute;
|
||||
import org.lastaflute.web.response.ActionResponse;
|
||||
import org.lastaflute.web.response.HtmlResponse;
|
||||
import org.lastaflute.web.ruts.process.ActionRuntime;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -36,6 +52,10 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|||
//
|
||||
private static final Logger logger = LoggerFactory.getLogger(AdminMaintenanceAction.class);
|
||||
|
||||
private static final String[] ES_CAT_NAMES = new String[] { "aliases", "allocation", "count", "fielddata", "health", "indices",
|
||||
"master", "nodeattrs", "nodes", "pending_tasks", "plugins", "recovery", "repositories", "thread_pool", "shards", "segments",
|
||||
"snapshots", "templates" };
|
||||
|
||||
// ===================================================================================
|
||||
// Attribute
|
||||
//
|
||||
|
@ -63,11 +83,11 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|||
}
|
||||
|
||||
private HtmlResponse asIndexHtml() {
|
||||
return asHtml(path_AdminMaintenance_AdminMaintenanceJsp).useForm(UpgradeForm.class);
|
||||
return asHtml(path_AdminMaintenance_AdminMaintenanceJsp).useForm(ActionForm.class);
|
||||
}
|
||||
|
||||
@Execute
|
||||
public HtmlResponse reindexOnly(final UpgradeForm form) {
|
||||
public HtmlResponse reindexOnly(final ActionForm form) {
|
||||
validate(form, messages -> {}, this::asIndexHtml);
|
||||
verifyToken(this::asIndexHtml);
|
||||
if (startReindex(isCheckboxEnabled(form.replaceAliases), form.numberOfShardsForDoc, form.autoExpandReplicasForDoc)) {
|
||||
|
@ -77,7 +97,7 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|||
}
|
||||
|
||||
@Execute
|
||||
public HtmlResponse clearCrawlerIndex(final UpgradeForm form) {
|
||||
public HtmlResponse clearCrawlerIndex(final ActionForm form) {
|
||||
validate(form, messages -> {}, this::asIndexHtml);
|
||||
verifyToken(this::asIndexHtml);
|
||||
fessEsClient
|
||||
|
@ -94,7 +114,151 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|||
return redirect(getClass());
|
||||
}
|
||||
|
||||
private boolean startReindex(final boolean replaceAliases, final String numberOfShards, final String autoExpandReplicas) {
|
||||
@Execute
|
||||
public ActionResponse downloadLogs(final ActionForm form) {
|
||||
validate(form, messages -> {}, this::asIndexHtml);
|
||||
verifyTokenKeep(this::asIndexHtml);
|
||||
|
||||
final String diagnosticId = "log" + new SimpleDateFormat("yyyyMMddHHmm").format(ComponentUtil.getSystemHelper().getCurrentTime());
|
||||
return asStream(diagnosticId + ".zip").contentTypeOctetStream().stream(out -> {
|
||||
try (ZipOutputStream zos = new ZipOutputStream(out.stream())) {
|
||||
writeLogFiles(zos, diagnosticId);
|
||||
writeSystemProperties(zos, diagnosticId);
|
||||
writeFessBasicConfig(zos, diagnosticId);
|
||||
writeFessConfig(zos, diagnosticId);
|
||||
writeElasticsearchCat(zos, diagnosticId);
|
||||
writeElasticsearchJson(zos, diagnosticId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void writeElasticsearchJson(final ZipOutputStream zos, final String id) {
|
||||
writeElastisearchJsonApi(zos, id, "cluster", "health");
|
||||
writeElastisearchJsonApi(zos, id, "cluster", "state");
|
||||
writeElastisearchJsonApi(zos, id, "cluster", "stats");
|
||||
writeElastisearchJsonApi(zos, id, "cluster", "pending_tasks");
|
||||
writeElastisearchJsonApi(zos, id, "nodes", "stats");
|
||||
writeElastisearchJsonApi(zos, id, "nodes", "_all");
|
||||
writeElastisearchJsonApi(zos, id, "nodes", "usage");
|
||||
writeElastisearchJsonApi(zos, id, "remote", "info");
|
||||
writeElastisearchJsonApi(zos, id, "tasks", "");
|
||||
writeElastisearchJsonApi(zos, id, "nodes", "hot_threads");
|
||||
}
|
||||
|
||||
protected void writeElastisearchJsonApi(final ZipOutputStream zos, final String id, final String v1, final String v2) {
|
||||
final ZipEntry entry = new ZipEntry(id + "/es_" + v1 + "_" + v2 + ".json");
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
try (CurlResponse response = ComponentUtil.getCurlHelper().get("/_" + v1 + "/" + v2).execute()) {
|
||||
CopyUtil.copy(response.getContentAsStream(), zos);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
logger.warn("Failed to access /_" + v1 + "/" + v2, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeElasticsearchCat(final ZipOutputStream zos, final String id) {
|
||||
Arrays.stream(ES_CAT_NAMES).forEach(name -> {
|
||||
final ZipEntry entry = new ZipEntry(id + "/es_cat_" + name + ".txt");
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
try (CurlResponse response = ComponentUtil.getCurlHelper().get("/_cat/" + name).param("v", "").execute()) {
|
||||
CopyUtil.copy(response.getContentAsStream(), zos);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
logger.warn("Failed to access /_cat/" + name, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void writeFessConfig(final ZipOutputStream zos, final String id) {
|
||||
if (fessConfig instanceof SimpleImpl) {
|
||||
final Properties prop = new Properties();
|
||||
((SimpleImpl) fessConfig).keySet().stream().forEach(k -> prop.setProperty(k, fessConfig.get(k)));
|
||||
|
||||
final ZipEntry entry = new ZipEntry(id + "/fess_config.properties");
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
prop.store(zos, getHostInfo());
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access system.properties.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeFessBasicConfig(final ZipOutputStream zos, final String id) {
|
||||
final ZipEntry entry = new ZipEntry(id + "/fess_basic_config.bulk");
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
try (CurlResponse response =
|
||||
ComponentUtil.getCurlHelper().get("/.fess_basic_config/_data").param("format", "json")
|
||||
.param("scroll", fessConfig.getIndexScrollSearchTimeout()).execute()) {
|
||||
CopyUtil.copy(response.getContentAsStream(), zos);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access system.properties.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeSystemProperties(final ZipOutputStream zos, final String id) {
|
||||
final ZipEntry entry = new ZipEntry(id + "/system.properties");
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
ComponentUtil.getSystemProperties().store(zos, getHostInfo());
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access system.properties.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeLogFiles(final ZipOutputStream zos, final String id) {
|
||||
final String logFilePath = systemHelper.getLogFilePath();
|
||||
if (StringUtil.isNotBlank(logFilePath)) {
|
||||
final Path logDirPath = Paths.get(logFilePath);
|
||||
try (Stream<Path> stream = Files.list(logDirPath)) {
|
||||
stream.filter(entry -> isLogFilename(entry.getFileName().toString())).forEach(filePath -> {
|
||||
final ZipEntry entry = new ZipEntry(id + "/" + filePath.getFileName().toString());
|
||||
try {
|
||||
zos.putNextEntry(entry);
|
||||
final long len = Files.copy(filePath, zos);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(filePath.getFileName() + ": " + len);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access " + filePath, e);
|
||||
}
|
||||
});
|
||||
} catch (final Exception e) {
|
||||
logger.warn("Failed to access log files.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String getHostInfo() {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
final InetAddress ia = InetAddress.getLocalHost();
|
||||
final String hostname = ia.getHostName();
|
||||
if (StringUtil.isNotBlank(hostname)) {
|
||||
buf.append(hostname);
|
||||
}
|
||||
final String ip = ia.getHostAddress();
|
||||
if (StringUtil.isNotBlank(ip)) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(" : ");
|
||||
}
|
||||
buf.append(ip);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected boolean isLogFilename(final String name) {
|
||||
return name.endsWith(".log") || name.endsWith(".log.gz");
|
||||
}
|
||||
|
||||
protected boolean startReindex(final boolean replaceAliases, final String numberOfShards, final String autoExpandReplicas) {
|
||||
final String docIndex = "fess";
|
||||
final String fromIndex = fessConfig.getIndexDocumentUpdateIndex();
|
||||
final String toIndex = docIndex + "." + new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
|
||||
|
|
|
@ -2829,6 +2829,12 @@ public class FessLabels extends UserMessages {
|
|||
/** The key of the message: Clear .crawler Indices */
|
||||
public static final String LABELS_clear_crawler_index_button = "{labels.clear_crawler_index_button}";
|
||||
|
||||
/** The key of the message: Diagnostic */
|
||||
public static final String LABELS_diagnostic_logs = "{labels.diagnostic_logs}";
|
||||
|
||||
/** The key of the message: Download Logs */
|
||||
public static final String LABELS_download_diagnostic_logs_button = "{labels.download_diagnostic_logs_button}";
|
||||
|
||||
/**
|
||||
* Assert the property is not null.
|
||||
* @param property The value of the property. (NotNull)
|
||||
|
|
|
@ -933,3 +933,5 @@ labels.number_of_shards_for_doc=The number of shards
|
|||
labels.auto_expand_replicas_for_doc=Auto expand replicas
|
||||
labels.clear_crawler_index=Crawler Indices
|
||||
labels.clear_crawler_index_button=Clear .crawler Indices
|
||||
labels.diagnostic_logs=Diagnostic
|
||||
labels.download_diagnostic_logs_button=Download Logs
|
||||
|
|
|
@ -933,3 +933,5 @@ labels.number_of_shards_for_doc=The number of shards
|
|||
labels.auto_expand_replicas_for_doc=Auto expand replicas
|
||||
labels.clear_crawler_index=Crawler Indices
|
||||
labels.clear_crawler_index_button=Clear .crawler Indices
|
||||
labels.diagnostic_logs=Diagnostic
|
||||
labels.download_diagnostic_logs_button=Download Logs
|
||||
|
|
|
@ -935,3 +935,5 @@ labels.number_of_shards_for_doc=シャード数
|
|||
labels.auto_expand_replicas_for_doc=最大レプリカ数
|
||||
labels.clear_crawler_index=Crawlerインデックス
|
||||
labels.clear_crawler_index_button=.crawlerインデックスの削除
|
||||
labels.diagnostic_logs=診断
|
||||
labels.download_diagnostic_logs_button=ログのダウンロード
|
||||
|
|
|
@ -101,6 +101,26 @@
|
|||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<la:message key="labels.diagnostic_logs" />
|
||||
</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary"
|
||||
name="downloadLogs"
|
||||
value="<la:message key="labels.download_diagnostic_logs_button"/>">
|
||||
<i class="fa fa-arrow-circle-right"></i>
|
||||
<la:message key="labels.download_diagnostic_logs_button" />
|
||||
</button>
|
||||
</div>
|
||||
<!-- /.box-footer -->
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
</la:form>
|
||||
</div>
|
||||
</section>
|
||||
|
|
Loading…
Add table
Reference in a new issue