/**
* 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.jena.fuseki.mgt;
import static java.lang.String.format ;
import static org.apache.jena.riot.WebContent.charsetUTF8 ;
import static org.apache.jena.riot.WebContent.contentTypeTextPlain ;
import java.io.IOException ;
import java.util.Iterator ;
import java.util.List ;
import javax.servlet.ServletOutputStream ;
import javax.servlet.http.HttpServletResponse ;
import org.apache.jena.atlas.json.JsonBuilder ;
import org.apache.jena.atlas.json.JsonObject ;
import org.apache.jena.atlas.json.JsonValue ;
import org.apache.jena.fuseki.server.* ;
import org.apache.jena.fuseki.servlets.HttpAction ;
public class ActionStats extends ActionContainerItem
{
private static final long serialVersionUID = 7077403170416268730L;
public ActionStats() { super() ; }
// This does not consult the system database for dormant etc.
@Override
protected JsonValue execGetContainer(HttpAction action) {
action.log.info(format("[%d] GET stats all", action.id)) ;
return generateStats(action.getDataAccessPointRegistry()) ;
}
public static JsonObject generateStats(DataAccessPointRegistry registry) {
JsonBuilder builder = new JsonBuilder() ;
builder.startObject("top") ;
builder.key(JsonConst.datasets) ;
builder.startObject("datasets") ;
registry.forEach((name, access)->statsDataset(builder, access));
builder.finishObject("datasets") ;
builder.finishObject("top") ;
return builder.build().getAsObject() ;
}
@Override
protected JsonValue execGetItem(HttpAction action) {
action.log.info(format("[%d] GET stats dataset %s", action.id, action.getDatasetName())) ;
JsonBuilder builder = new JsonBuilder() ;
String datasetPath = DataAccessPoint.canonical(action.getDatasetName()) ;
builder.startObject("TOP") ;
builder.key(JsonConst.datasets) ;
builder.startObject("datasets") ;
statsDataset(builder, datasetPath, action.getDataAccessPointRegistry()) ;
builder.finishObject("datasets") ;
builder.finishObject("TOP") ;
return builder.build() ;
}
public static JsonObject generateStats(DataAccessPoint access) {
JsonBuilder builder = new JsonBuilder() ;
statsDataset(builder, access) ;
return builder.build().getAsObject() ;
}
private void statsDataset(JsonBuilder builder, String name, DataAccessPointRegistry registry) {
DataAccessPoint access = registry.get(name) ;
statsDataset(builder, access);
}
private static void statsDataset(JsonBuilder builder, DataAccessPoint access) {
// Object started
builder.key(access.getName()) ;
DataService dSrv = access.getDataService() ;
builder.startObject("counters") ;
builder.key(CounterName.Requests.name()).value(dSrv.getCounters().value(CounterName.Requests)) ;
builder.key(CounterName.RequestsGood.name()).value(dSrv.getCounters().value(CounterName.RequestsGood)) ;
builder.key(CounterName.RequestsBad.name()).value(dSrv.getCounters().value(CounterName.RequestsBad)) ;
builder.key(JsonConst.endpoints).startObject("endpoints") ;
for ( OperationName operName : dSrv.getOperations() ) {
List<Endpoint> endpoints = access.getDataService().getOperation(operName) ;
for ( Endpoint endpoint : endpoints ) {
// Endpoint names are unique for a given service.
builder.key(endpoint.getEndpoint()) ;
builder.startObject() ;
operationCounters(builder, endpoint);
builder.key(JsonConst.operation).value(operName.name()) ;
builder.key(JsonConst.description).value(operName.getDescription()) ;
builder.finishObject() ;
}
}
builder.finishObject("endpoints") ;
builder.finishObject("counters") ;
}
private static void operationCounters(JsonBuilder builder, Endpoint operation) {
for (CounterName cn : operation.getCounters().counters()) {
Counter c = operation.getCounters().get(cn) ;
builder.key(cn.name()).value(c.value()) ;
}
}
private void statsTxt(HttpServletResponse resp, DataAccessPointRegistry registry) throws IOException
{
ServletOutputStream out = resp.getOutputStream() ;
resp.setContentType(contentTypeTextPlain);
resp.setCharacterEncoding(charsetUTF8) ;
Iterator<String> iter = registry.keys().iterator() ;
while(iter.hasNext())
{
String ds = iter.next() ;
DataAccessPoint desc = registry.get(ds) ;
statsTxt(out, desc) ;
if ( iter.hasNext() )
out.println() ;
}
out.flush() ;
}
private void statsTxt(ServletOutputStream out, DataAccessPoint desc) throws IOException
{
DataService dSrv = desc.getDataService() ;
out.println("Dataset: "+desc.getName()) ;
out.println(" Requests = "+dSrv.getCounters().value(CounterName.Requests)) ;
out.println(" Good = "+dSrv.getCounters().value(CounterName.RequestsGood)) ;
out.println(" Bad = "+dSrv.getCounters().value(CounterName.RequestsBad)) ;
out.println(" SPARQL Query:") ;
out.println(" Request = "+counter(dSrv, OperationName.Query, CounterName.Requests)) ;
out.println(" Good = "+counter(dSrv, OperationName.Query, CounterName.RequestsGood)) ;
out.println(" Bad requests = "+counter(dSrv, OperationName.Query, CounterName.RequestsBad)) ;
out.println(" Timeouts = "+counter(dSrv, OperationName.Query, CounterName.QueryTimeouts)) ;
out.println(" Bad exec = "+counter(dSrv, OperationName.Query, CounterName.QueryExecErrors)) ;
out.println(" IO Errors = "+counter(dSrv, OperationName.Query, CounterName.QueryIOErrors)) ;
out.println(" SPARQL Update:") ;
out.println(" Request = "+counter(dSrv, OperationName.Update, CounterName.Requests)) ;
out.println(" Good = "+counter(dSrv, OperationName.Update, CounterName.RequestsGood)) ;
out.println(" Bad requests = "+counter(dSrv, OperationName.Update, CounterName.RequestsBad)) ;
out.println(" Bad exec = "+counter(dSrv, OperationName.Update, CounterName.UpdateExecErrors)) ;
out.println(" Upload:") ;
out.println(" Requests = "+counter(dSrv, OperationName.Upload, CounterName.Requests)) ;
out.println(" Good = "+counter(dSrv, OperationName.Upload, CounterName.RequestsGood)) ;
out.println(" Bad = "+counter(dSrv, OperationName.Upload, CounterName.RequestsBad)) ;
out.println(" SPARQL Graph Store Protocol:") ;
out.println(" GETs = "+gspValue(dSrv, CounterName.HTTPget)+ " (good="+gspValue(dSrv, CounterName.HTTPgetGood)+"/bad="+gspValue(dSrv, CounterName.HTTPGetBad)+")") ;
out.println(" PUTs = "+gspValue(dSrv, CounterName.HTTPput)+ " (good="+gspValue(dSrv, CounterName.HTTPputGood)+"/bad="+gspValue(dSrv, CounterName.HTTPputBad)+")") ;
out.println(" POSTs = "+gspValue(dSrv, CounterName.HTTPpost)+ " (good="+gspValue(dSrv, CounterName.HTTPpostGood)+"/bad="+gspValue(dSrv, CounterName.HTTPpostBad)+")") ;
out.println(" DELETEs = "+gspValue(dSrv, CounterName.HTTPdelete)+ " (good="+gspValue(dSrv, CounterName.HTTPdeleteGood)+"/bad="+gspValue(dSrv, CounterName.HTTPdeleteBad)+")") ;
out.println(" HEADs = "+gspValue(dSrv, CounterName.HTTPhead)+ " (good="+gspValue(dSrv, CounterName.HTTPheadGood)+"/bad="+gspValue(dSrv, CounterName.HTTPheadBad)+")") ;
}
private long counter(DataService dSrv, OperationName opName, CounterName cName) {
return 0 ;
}
private long gspValue(DataService dSrv, CounterName cn) {
return counter(dSrv, OperationName.GSP_RW, cn) +
counter(dSrv, OperationName.GSP_R, cn) ;
}
// We shouldn't get here - no doPost above.
@Override
protected JsonValue execPostContainer(HttpAction action) {
throw new InternalError(METHOD_POST+" container") ;
}
@Override
protected JsonValue execPostItem(HttpAction action) {
throw new InternalError(METHOD_POST+" item") ;
}
}