示例:将请求的地图范围写入要素类
本示例显示了如何组合 ArcGIS Server Administrator API 和 ArcGIS 地理处理功能以读取服务器日志从而构造一个包含了对服务器进行的所有地图请求的范围的要素类。这可帮助您了解人们查看您的服务的整体空间模式。
要使用此脚本,您必须首先将 ArcGIS Server 日志记录至少设置为“精细 (FINE)”级别。然后,在您的服务器满足了一些来自客户端的地图请求后,您可以运行此脚本将请求的所有范围写入要素类。所记录的每个范围都有时间戳信息,该信息也将写入到要素类,可允许您在 ArcGIS 中使用时间滑块回放所有请求。
此脚本需要一个已经存在的文件地理数据库。不过,它会为您创建要素类。
此脚本没有处理自定义空间参考(无法用熟知的 ID (wkid) 来表示的空间参考)。
# 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 Extent detail for service
print "\nLooking up Service details..."
fullExtent = getFullExtent( serverName, serverPort, serviceURL)
if not fullExtent:
return
print " Spatial Reference: {0}".format( fullExtent[ 'spatialReference'][ 'wkid'])
# 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
# 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)
elif not 'spatialReference' in dataObj[ 'fullExtent']:
print "Unable to find Spatial Reference for '{0}'!".format( serviceURL)
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:]))
9/15/2013