Ejemplo: Escribir extensiones de mapa solicitadas en una clase de entidad
En este ejemplo se muestra cómo puede combinar la API REST de ArcGIS y las funciones de geoprocesamiento de ArcGIS para leer los registros del servidor y construir una clase de entidad que contenga las extensiones de todas las solicitudes de mapa realizadas al servidor. Esto puede ayudarle a comprender los modelos espaciales de cómo la gente ve el servicio.
Para utilizar esta secuencia de comandos, debe establecer primero el registro de ArcGIS Server en al menos el nivel FINO. Después de que su servidor haya satisfecho algunos mapa solicitudes de clientes, puede ejecutar esta secuencia de comandos para escribir el extensiones pedidas para la clase de entidad. La extensión de cada marca de hora ha registrado la información que también se escriben en la clase de entidad, lo que permite reproducir las peticiones en ArcGIS usando un control deslizante de tiempo.
Sugerencia:
Esta secuencia de comandos requiere una geodatabase de archivos existente. Sin embargo, crea la clase de entidad para usted.
Las referencias espaciales personalizadas (las que no se pueden representar con un Id. conocido o WKID) no se gestionan en esta secuencia de comandos.
# Queries the logs to find the map extents requested for a given map service
# For output Featureclass creation
print "\nImporting ArcPy..."
import arcpy
# Set Script arguments
arcpy.env.overwriteOutput = True
# For Http calls
import httplib, urllib, json
# For system tools
import sys, datetime, os
# For reading passwords without echoing
import getpass
#Defines the entry point into the script
def main(argv=None):
# Print some info
print
print "This tool is a sample script that queries the ArcGIS Server logs."
print
# Ask for admin/publisher user name and password
username = raw_input("Enter user name: ")
password = getpass.getpass("Enter password: ")
# Ask for server name
serverName = raw_input("Enter Server name: ")
serverPort = 6080
# Ask for map service name
mapService = raw_input("Enter map service name, using a forward slash / to denote a folder: ")
if mapService.endswith(".MapServer"):
pass
else:
mapService += ".MapServer"
# Ask for output workspace
outputWorkspace = raw_input("Enter output Workspace (Geodatabase location): ")
# Ask for output featureclass name
outputFeatureclass = raw_input("Enter output Featureclass name: ")
# Construct REST service URL
serviceURL = "/arcgis/rest/services/{0}".format( mapService.replace( ".", "/"))
# Get a token
print "Requesting Token..."
token = getToken(username, password, serverName, serverPort)
if token == "":
print "Could not generate a token with the username and password provided."
return
# Get Extent detail for service
print "\nLooking up Service details..."
serviceURL = serviceURL + "/?Token=" + token
fullExtent = getFullExtent( serverName, serverPort, serviceURL)
if not fullExtent:
return
# Construct URL to query the logs
logQueryURL = "/arcgis/admin/logs/query"
logFilter = "{'services': ['" + mapService + "']}"
# Supply the log level, filter, token, and return format
params = urllib.urlencode({'level': 'FINE', 'filter': logFilter, 'token': token, 'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
print "Accessing Logs..."
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", logQueryURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
print " Error while querying logs."
return
else:
data = response.read()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
print " Error returned by operation. " + data
else:
print " Operation completed successfully!"
# Deserialize response into Python object
dataObj = json.loads(data)
httpConn.close()
# Open Insert Cursor on output
output = openCursor( outputWorkspace, outputFeatureclass, fullExtent[ "spatialReference"][ "wkid"])
if not output:
return
# Need this variable to track number of events found for ExportMapImage call
logEvents = 0
# Need Array to hold Shape
shapeArray = arcpy.Array()
# Iterate over messages
for item in dataObj[ "logMessages"]:
eventDateTime = datetime.datetime.fromtimestamp( float( item[ "time"]) / 1000)
if item[ "message"].startswith( "Extent:"):
eventScale = None # Scale
eventInvScale = None # Inverse-Scale
eventWidth = None # Width
eventHeight = None # Height
# Cycle through message details
for pair in item[ "message"].replace(" ", "").split( ";"):
if pair.count( ":") == 1:
key, val = pair.split( ":")
# Pick out Extent
if key == "Extent" and val.count( ",") == 3:
# Split into ordinate values
MinX, MinY, MaxX, MaxY = val.split( ",")
MinX = float( MinX)
MinY = float( MinY)
MaxX = float( MaxX)
MaxY = float( MaxY)
# Make sure extent is within range
if MinX > fullExtent[ "xmin"] and MaxX < fullExtent[ "xmax"] and MinY > fullExtent[ "ymin"] and MaxY < fullExtent[ "ymax"]:
shapeArray.add( arcpy.Point( MinX, MinY))
shapeArray.add( arcpy.Point( MinX, MaxY))
shapeArray.add( arcpy.Point( MaxX, MaxY))
shapeArray.add( arcpy.Point( MaxX, MinY))
shapeArray.add( arcpy.Point( MinX, MinY))
# Pick out Size
if key == "Size" and val.count( ",") == 1:
eventWidth, eventHeight = val.split( ",")
eventWidth = float( eventWidth)
eventHeight = float( eventHeight)
# Pick out Scale
if key == "Scale":
eventScale = float( val)
eventInvScale = 1 / eventScale
# Save if Shape created
if shapeArray.count > 0:
# Create new row
newRow = output.newRow()
# Add Shape and Event Date
newRow.setValue( "Shape", shapeArray)
newRow.setValue( "EventDate", eventDateTime)
newRow.setValue( "Scale", eventScale)
newRow.setValue( "InvScale", eventInvScale)
newRow.setValue( "Width", eventWidth)
newRow.setValue( "Height", eventHeight)
output.insertRow( newRow)
# Clear out Array points
shapeArray.removeAll()
logEvents += 1
print "\nDone!\n\nTotal number of events found in logs: {0}".format( logEvents)
return
#A function to query service for Extent and Spatial Reference details
def getFullExtent( serverName, serverPort, serviceURL):
# Supply the return format
params = urllib.urlencode({'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", serviceURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
print "Error while querying Service details."
return
else:
data = response.read()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
print "Error returned by Service Query operation. " + data
# Deserialize response into Python object
dataObj = json.loads(data)
httpConn.close()
if not 'fullExtent' in dataObj:
print "Unable to find Extent detail for '{0}'!".format( serviceURL)
print dataObj
elif not 'spatialReference' in dataObj[ 'fullExtent']:
print "Unable to find Spatial Reference for '{0}'!".format( serviceURL)
print "dataObj"
else:
return dataObj[ 'fullExtent']
return
#A function to create new Featureclass and return an Insert Cursor, used to store Map Query Extents.
def openCursor( workspace, featureclassName, srid):
if not arcpy.Exists( workspace):
print "Unable to find Workspace '{0}'...".format( workspace)
return
print "Creating output Featureclass..."
arcpy.CreateFeatureclass_management( workspace, featureclassName, "POLYGON", None, None, None, srid)
Featureclass = workspace + os.sep + featureclassName
print " Adding field(s)..."
arcpy.AddField_management( Featureclass, "EventDate", "DATE", None, None, None, None, "NULLABLE", "NON_REQUIRED")
arcpy.AddField_management( Featureclass, "Scale", "DOUBLE", 19, 2, None, None, "NULLABLE", "NON_REQUIRED")
arcpy.AddField_management( Featureclass, "InvScale", "DOUBLE", 19, 12, None, None, "NULLABLE", "NON_REQUIRED")
arcpy.AddField_management( Featureclass, "Width", "LONG", 9, None, None, None, "NULLABLE", "NON_REQUIRED")
arcpy.AddField_management( Featureclass, "Height", "LONG", 9, None, None, None, "NULLABLE", "NON_REQUIRED")
print " Opening Insert Cursor..."
return arcpy.InsertCursor( Featureclass)
#A function to generate a token given username, password and the adminURL.
def getToken(username, password, serverName, serverPort):
# Token URL is typically http://server[:port]/arcgis/admin/generateToken
tokenURL = "/arcgis/admin/generateToken"
# URL-encode the token parameters
params = urllib.urlencode({'username': username, 'password': password, 'client': 'requestip', 'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", tokenURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
print "Error while fetching tokens from admin URL. Please check the URL and try again."
return
else:
data = response.read()
httpConn.close()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
return
# Extract the token from it
token = json.loads(data)
return token['token']
#A function that checks that the input JSON object
# is not an error object.
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
print "Error: JSON object returns an error. " + str(obj)
return False
else:
return True
# Script start
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))