You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ta...@apache.org on 2020/07/17 17:06:38 UTC
[tika] branch main updated: TIKA-3129 -- add a status endpoint to
report server status. Users must turn it on via the commandline -status
option.
This is an automated email from the ASF dual-hosted git repository.
tallison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 23329a6 TIKA-3129 -- add a status endpoint to report server status. Users must turn it on via the commandline -status option.
23329a6 is described below
commit 23329a6bfb41098022554f751882e86168a965ce
Author: tallison <ta...@apache.org>
AuthorDate: Fri Jul 17 13:01:43 2020 -0400
TIKA-3129 -- add a status endpoint to report server status. Users must turn it on
via the commandline -status option.
---
.../java/org/apache/tika/server/ServerStatus.java | 9 ++-
.../java/org/apache/tika/server/TikaServerCli.java | 9 +++
.../tika/server/resource/TikaServerStatus.java | 44 +++++++++++++++
.../apache/tika/server/writer/JSONObjWriter.java | 64 ++++++++++++++++++++++
.../apache/tika/server/TikaServerStatusTest.java | 56 +++++++++++++++++++
5 files changed, 181 insertions(+), 1 deletion(-)
diff --git a/tika-server/src/main/java/org/apache/tika/server/ServerStatus.java b/tika-server/src/main/java/org/apache/tika/server/ServerStatus.java
index 255ce70..32d74cf 100644
--- a/tika-server/src/main/java/org/apache/tika/server/ServerStatus.java
+++ b/tika-server/src/main/java/org/apache/tika/server/ServerStatus.java
@@ -81,6 +81,8 @@ public class ServerStatus {
private final boolean isLegacy;
private STATUS status = STATUS.OPERATING;
+ private volatile long lastStarted = Instant.now().toEpochMilli();
+
public ServerStatus() {
isLegacy = false;
}
@@ -91,7 +93,9 @@ public class ServerStatus {
public synchronized long start(TASK task, String fileName) {
long taskId = counter.incrementAndGet();
- tasks.put(taskId, new TaskStatus(task, Instant.now(), fileName));
+ Instant now = Instant.now();
+ lastStarted = now.toEpochMilli();
+ tasks.put(taskId, new TaskStatus(task, now, fileName));
return taskId;
}
@@ -126,6 +130,9 @@ public class ServerStatus {
return counter.get();
}
+ public long getMillisSinceLastParseStarted() {
+ return Instant.now().toEpochMilli()-lastStarted;
+ }
/**
*
* @return true if this is legacy, otherwise whether or not status == OPERATING.
diff --git a/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java b/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
index 10616cd..d1b6baf 100644
--- a/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
+++ b/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
@@ -53,12 +53,14 @@ import org.apache.tika.server.resource.TikaDetectors;
import org.apache.tika.server.resource.TikaMimeTypes;
import org.apache.tika.server.resource.TikaParsers;
import org.apache.tika.server.resource.TikaResource;
+import org.apache.tika.server.resource.TikaServerStatus;
import org.apache.tika.server.resource.TikaVersion;
import org.apache.tika.server.resource.TikaWelcome;
import org.apache.tika.server.resource.TranslateResource;
import org.apache.tika.server.resource.UnpackerResource;
import org.apache.tika.server.writer.CSVMessageBodyWriter;
import org.apache.tika.server.writer.JSONMessageBodyWriter;
+import org.apache.tika.server.writer.JSONObjWriter;
import org.apache.tika.server.writer.MetadataListMessageBodyWriter;
import org.apache.tika.server.writer.TarWriter;
import org.apache.tika.server.writer.TextMessageBodyWriter;
@@ -102,6 +104,7 @@ public class TikaServerCli {
options.addOption("dml", "digestMarkLimit", true, "max number of bytes to mark on stream for digest");
options.addOption("l", "log", true, "request URI log level ('debug' or 'info')");
options.addOption("s", "includeStack", false, "whether or not to return a stack trace\nif there is an exception during 'parse'");
+ options.addOption("status", false, "enable the status endpoint");
options.addOption("?", "help", false, "this help message");
options.addOption("enableUnsecureFeatures", false, "this is required to enable fileUrl.");
options.addOption("enableFileUrl", false, "allows user to pass in fileUrl instead of InputStream.");
@@ -305,6 +308,9 @@ public class TikaServerCli {
rCoreProviders.add(new SingletonResourceProvider(new TikaDetectors()));
rCoreProviders.add(new SingletonResourceProvider(new TikaParsers()));
rCoreProviders.add(new SingletonResourceProvider(new TikaVersion()));
+ if (line.hasOption("status")) {
+ rCoreProviders.add(new SingletonResourceProvider(new TikaServerStatus(serverStatus)));
+ }
List<ResourceProvider> rAllProviders = new ArrayList<>(rCoreProviders);
rAllProviders.add(new SingletonResourceProvider(new TikaWelcome(rCoreProviders)));
sf.setResourceProviders(rAllProviders);
@@ -318,6 +324,9 @@ public class TikaServerCli {
providers.add(new XMPMessageBodyWriter());
providers.add(new TextMessageBodyWriter());
providers.add(new TikaServerParseExceptionMapper(returnStackTrace));
+ if (line.hasOption("status")) {
+ providers.add(new JSONObjWriter());
+ }
if (logFilter != null) {
providers.add(logFilter);
}
diff --git a/tika-server/src/main/java/org/apache/tika/server/resource/TikaServerStatus.java b/tika-server/src/main/java/org/apache/tika/server/resource/TikaServerStatus.java
new file mode 100644
index 0000000..2e55221
--- /dev/null
+++ b/tika-server/src/main/java/org/apache/tika/server/resource/TikaServerStatus.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.tika.server.resource;
+
+import org.apache.tika.server.ServerStatus;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Path("/status")
+public class TikaServerStatus {
+ private final ServerStatus serverStatus;
+
+ public TikaServerStatus(ServerStatus serverStatus) {
+ this.serverStatus = serverStatus;
+ }
+
+ @GET
+ @Produces("application/json")
+ public Map<String, Object> getStatus() {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("status", serverStatus.getStatus());
+ map.put("millis_since_last_parse_started", serverStatus.getMillisSinceLastParseStarted());
+ map.put("files_processed", serverStatus.getFilesProcessed());
+ return map;
+ }
+}
diff --git a/tika-server/src/main/java/org/apache/tika/server/writer/JSONObjWriter.java b/tika-server/src/main/java/org/apache/tika/server/writer/JSONObjWriter.java
new file mode 100644
index 0000000..08851d6
--- /dev/null
+++ b/tika-server/src/main/java/org/apache/tika/server/writer/JSONObjWriter.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.tika.server.writer;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.serialization.JsonMetadata;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+public class JSONObjWriter implements MessageBodyWriter<Map<String, Object>> {
+ private static Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return Map.class.isAssignableFrom(type);
+ }
+
+ public long getSize(Metadata data, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(Map<String, Object> map, Class<?> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+ Writer writer = new OutputStreamWriter(entityStream, UTF_8);
+ GSON.toJson(map, writer);
+ writer.flush();
+ entityStream.flush();
+ }
+}
diff --git a/tika-server/src/test/java/org/apache/tika/server/TikaServerStatusTest.java b/tika-server/src/test/java/org/apache/tika/server/TikaServerStatusTest.java
new file mode 100644
index 0000000..28e62e7
--- /dev/null
+++ b/tika-server/src/test/java/org/apache/tika/server/TikaServerStatusTest.java
@@ -0,0 +1,56 @@
+package org.apache.tika.server;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.tika.server.resource.RecursiveMetadataResource;
+import org.apache.tika.server.resource.TikaResource;
+import org.apache.tika.server.resource.TikaServerStatus;
+import org.apache.tika.server.writer.JSONMessageBodyWriter;
+import org.apache.tika.server.writer.JSONObjWriter;
+import org.apache.tika.server.writer.MetadataListMessageBodyWriter;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TikaServerStatusTest extends CXFTestBase {
+
+ private final static String STATUS_PATH = "/status";
+
+ @Override
+ protected void setUpResources(JAXRSServerFactoryBean sf) {
+ sf.setResourceClasses(TikaServerStatus.class);
+ sf.setResourceProvider(TikaServerStatus.class,
+ new SingletonResourceProvider(new TikaServerStatus(new ServerStatus())));
+ }
+
+ @Override
+ protected void setUpProviders(JAXRSServerFactoryBean sf) {
+ List<Object> providers = new ArrayList<>();
+ providers.add(new JSONObjWriter());
+ sf.setProviders(providers);
+ }
+
+ @Test
+ public void testBasic() throws Exception {
+ Response response = WebClient.create(endPoint + STATUS_PATH).get();
+ String jsonString =
+ getStringFromInputStream((InputStream) response.getEntity());
+ JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
+ assertTrue(root.has("status"));
+ assertTrue(root.has("millis_since_last_parse_started"));
+ assertTrue(root.has("files_processed"));
+ assertEquals("OPERATING", root.getAsJsonPrimitive("status").getAsString());
+ assertEquals(0, root.getAsJsonPrimitive("files_processed").getAsInt());
+ long millis = root.getAsJsonPrimitive("millis_since_last_parse_started").getAsInt();
+ assertTrue(millis > 0 && millis < 360000);
+ }
+}