How many time did your service been hit?


One day some one, could be your manager, customer or some one else, asked you if you could give them metric on how many time in a month or week your services have been hit. There are many ways to answer this and many tools available out there. Here, I would like to give you a free tool or you could say it as script where you can run and give an idea to your requester how many hits on your ArcGIS services.You can also modify this script to not only produce a csv file but also input into database, so everyone can access the data.

 

Good Luck,

 


#-------------------------------------------------------------------------------
# Name: HitStat.py
# Purpose: Gather hit statistics info in the last 24 hours. the statistics will be stored in DB and csv file
# Since there is limitation in Esri side how it pulls the data to max. 10,000 records from log file,
# We divide to an hour in 24 hours time frame. Even though each our has max 10,000 records at least
# it can show a close accurate data. The steps are: Pul each hour data into a temp csv and read the
# data from there and store in csv and database.
# Queries the logs and writes statistics on map service activity during the past 24 hours
# Sends email if no log data, indicating someone has changed ArcGIS Server Log settings
# The data is based on CODE = 100004 and 8521
#
# Author: mlou1_p
#
# Created: 04/13/2016
# Copyright: (c) mlou1_p 2016
# Licence: <your licence>
#-------------------------------------------------------------------------------


# For Http calls
import httplib, urllib, json

# CSV Module
import csv

# Datetime module
import datetime

# For system tools
#import arcserver
import sys, time, arcserver, arcpy, re

# For sending email
import smtplib
import mimetypes
import email
import email.mime.application

# For reading passwords without echoing
import getpass


#Get the current date
now = datetime.datetime.now()

#Defines the entry point into the script
def main(argv=None):
# Print some info
print
print "This tool is a script that queries the ArcGIS Server logs and writes a report"
print " summarizing all map service draws within the past 24 hours."
print


# ########################################################################################################################################
#--- START OF VARIABLE--------------------------------------------------------------------------------------------------------------------
# ########################################################################################################################################


# Ask for admin/publisher user name and password
#username = raw_input("Enter user name: ")
username = "ARCGISADMIN"
#password = getpass.getpass("Enter password: ")
password = "Abc123$"


# Ask for server name
#serverName = raw_input("Enter Server name: ")
serverName = "ARCGISSERVER01"
serverPort = 6080

# Connect to Oracle to put the data
##tbl = r"\\stlArcGISsvr\GIS_Data\data\ADM\GEOSPATIAL@GEORACLE.sde\GEOSPATIAL.HIT_STATISTICS" #turn off for testing

# Ask for text file path
filePath = "//stlArcGISsvr//d$//temp//HitStat//HitStat_" + str(now.year) + str(now.month) + str(now.day) + ".txt"
rawPath = "//stlArcGISsvr//d$//temp//HitStat//raw.csv"


# For email purposes
From = "noreply@esri.com"
Receivers = ["DL-DOOOH@esri.com"] # must be a list
EmailBody = "No Draw Time Log for DEV environment. Check ArcGIS Server Log Settings."

# For Testing Purpose please use this to look for specific date
#Date time start with
date_time = '04.12.2016 00:00:01'
pattern = '%m.%d.%Y %H:%M:%S'
##startTime = int(time.mktime(time.strptime(date_time, pattern))*1000)

startTime = int(round(time.time() * 1000)) # Current time and date


#millisecondsToQuery = 86400000 # One day
##millisecondsToQuery = 3600000 # One hour in millisecond
##n = 24 #1 hours X 24 = a day
millisecondsToQuery = 1800000 # half an hour in millisecond (30 minutes)
n = 48 # 30 min X 48 = a day


# ########################################################################################################################################
#--- END OF VARIABLE--------------------------------------------------------------------------------------------------------------------
# ########################################################################################################################################



hitDict = {}
counter = 0
timeStamp = '%04d' % now.year + '%02d' % now.month + '%02d' % now.day


# Open text file and write header line
summaryFile = open(filePath, "w")
header = "Now;Service;Number of hits\n"

#Raw Data
rawData = open(rawPath,"w")
rawData.write("Service;Code"+"\n")


# Get a token
token = getToken(username, password, serverName, serverPort)
if token == "":
print "Could not generate a token with the username and password provided."
return

#insert cursor variables in Oracle
##fields = ["TIME", "SERVICE", "HITS"] #turn off for testing

#insert cursor
##insCur = arcpy.da.InsertCursor(tbl, fields) # turn off insCur for testing purposes



# Construct URL to query the logs
logQueryURL = "/arcgis/admin/logs/query"

##endTime = startTime - millisecondsToQuery

# Need these variables to calculate average draw time for an ExportMapImage call
mapDraws = 0
totalDrawTime = 0
timecount = 0

while (timecount < n):

if timecount <> 0:
rawData = open(rawPath,"a")

timecount = timecount + 1
print "time count = " +str(timecount)
xTime = millisecondsToQuery * timecount
#startTime = millisecondsToQuery + endTime
endTime = startTime - millisecondsToQuery
print "xTime = " + str(xTime)
print "Start Time = " + str(startTime)
print "End Time = " + str(endTime)


#logFilter = "{'services':'*','server':'*','machines':'*'}"
logFilter = "{'codes':[100004, 8521],'services':'*','server':'*','machines':'*'}" #Correct Code: 100004, changed to 12345 for test purposes

params = urllib.urlencode({'level': 'FINE', 'startTime': startTime, 'endTime': endTime, 'filter':logFilter, 'token': token, 'pageSize': 10000, '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", 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 at " + str(timecount) + " hour"

# Deserialize response into Python object
dataObj = json.loads(data)
httpConn.close()

# Iterate over messages
for item in dataObj["logMessages"]:

# if item["message"] == "End ExportMapImage":
##elapsed = float(item["elapsed"])
keyCheck = item["source"]
code = str(item["code"])

msg = item["message"]
##print "Ori msg : " + msg

# If Code is 100004
if '8521' not in code:
rawData.write(keyCheck+ ";" + str(code) + "\n")
print "KeyCheck = " +keyCheck

#Input the result into temporary dictionary (hitDict)
if keyCheck in hitDict:
stats = hitDict[keyCheck]

# Add 1 to tally of hits
stats[0] += 1

else:
# Add key with one hit and total elapsed time
hitDict[keyCheck] = [1]


# If Code is 8521
else:
if 'services/' in msg:
if 'Server' in msg:

# Trim/Slice data to get Service Name

astrVerify = "arcgis/rest/services/"
a = msg.find(astrVerify)
msg = msg[a+len(astrVerify):]

bstrVerify = "Server"
b = msg.find(bstrVerify)
msg = msg[0:b+6]

# Replace the message that has second / with .
msg = re.sub(r'^((.*?/.*?){1})/', r'\1.', msg)

rawData.write(msg + ";" + str(code) + "\n")
print "KeyCheck = " +msg
keyCheck = msg



#Input the result into temporary dictionary (hitDict)
if keyCheck in hitDict:
stats = hitDict[keyCheck]

# Add 1 to tally of hits
stats[0] += 1

else:
# Add key with one hit and total elapsed time
hitDict[keyCheck] = [1]


startTime = endTime
rawData.close()



## #If no data, send email to GEOSPATIAL
## if hitDict == {}:
## EmailSubject = "No Draw Times found in log."
## for address in Receivers:
## EmailAttachments(address, From, EmailSubject, EmailBody)
##
## print "no draw times found!"



#Read the Raw Data
# Open text file and write header line
summaryFile = open(filePath, "w")
header = "Now;Service;Number of hits\n"
summaryFile.write(header)
print hitDict


# Read through dictionary and write totals into file
for key in sorted(hitDict.iterkeys()):

# Calculate average elapsed time
totalDraws = hitDict[key][0]

# Construct and write the comma-separated line
line = timeStamp +"," + key + "," + str(totalDraws) + "\n"

fields = ["TIME", "SERVICE", "HITS"]
##insCur.insertRow(( timeStamp, key, str(totalDraws) )) # comment out for testing


summaryFile.write(line)

summaryFile.close()
return








# ########################################################################################################################################
#--- DEFINED ALL FUNCTIONS----------------------------------------------------------------------------------------------------------------
# ########################################################################################################################################



# 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 toke 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



# A function to send email
def EmailAttachments(address, From, EmailSubject, EmailBody):
sender = From
receiver = address

# Create a text/plain message
msg = email.mime.Multipart.MIMEMultipart()
msg['Subject'] = EmailSubject
msg['From'] = sender
msg['To'] = receiver


# The main body is just another attachment
body = email.mime.Text.MIMEText(EmailBody)
msg.attach(body)

# Send the message via our own SMTP server, but don't include the
# envelope header.
smtpObj = smtplib.SMTP('mail.monsanto.com')
smtpObj.sendmail(sender, address, msg.as_string())
smtpObj.quit()



# Script start
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))</pre>
<pre>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s