'Script to get number of erros by each hour from the IIS site
'Author: Felipe Ferreira , contact fel.h2o'AT'gmail.com
'Date: 16/06/2010
'Version: 5
'REQUIREMENTS: MSUtil.LogQuery logparser.dll (IIS)
'tested on Win2003 IIS 6

'For Nagios:
'OK Ouput just one line ex: 
'OK - WARNING - 2000 erros of type 404 in IIS log |  2000,500,4000
'OK Get Parameters, WARN,CRIT,site,ERRORTYPE

'TODO: 
'get query from last X minutes not from entire hour
'OK - get current time convert to GMT and subtract - X time

'PROBELM: query takes to long to execute, plus uses high CPU
'SOLUTIOn: execute every hour, and nagios just collect log info and report

'Option Explicit
Const ForReading=1,ForWriting=2,ForAppending=3
Const intOK = 0
Const intWarning = 1
Const intCritical = 2
Const intError = 3
Const intUnknown = 3
Dim objLogParser,objInputFormat,objOutputFormat,strQuery
Dim fso,logfile,outputlog,logday,pathlogfile,terros
Dim debug,log,aSites(1)
Dim aTxt,logname,RunTime,logOutputFileName
Dim t1 : t1 = Timer  'time the script
Dim logOutputFile 'Arquivo Final de Log 
Dim intDia        'De que dia olhar os logs, 0 = hoje, 1 = ontem etc...
Dim line,hora,intGMToff,hourTarget,intMinDiff,intHourDiff
Dim WARN,CRIT,strSite,ERRORTYPE,strFinalOutput,erros
Dim argcountcommand,arg(9)



'#################VARS##################
logsroot = "E:\Logs-Sites\"   'the top level place where IIS save logs, default c:\windows\system32\logfiles
debug = 0       '1 for debug,            0 for silent
intDia = 0	    ' 0 = hoje, 1 = ontem etc...
WARN = 30       ' Apartir desse numero de erros p/ hora ira pro log
log = 1 	    '1 for logging to a file, 0 for silent
intGMToff = 3   'Diferença entre hora GMT e local time, nosso caso +3
intMinDiff = 30 'Quantos Minutos atras iremos olhar no Log
intHourDiff = 0 'Quantas Horas atras iremos olhar no Log
'Default settings:
erros = 0
erros1 = 0
CRIT=2000
strSite="site"
Errortype="404"
'#################VARS##################

Set fso = CreateObject("Scripting.FileSystemObject")

call getArgs()
call getArgsSet()
logday = getday(date)
logOutputFileName = "c:\scripts\logs\LogIIS_Check_"&logday&".txt"
Set logOutputFile = fso.OpenTextFile(logOutputFileName, ForWriting, True)'status output for running as a daily scheduled task

hora = getTime(time)
'pt "NOW(GMT):" & hora
'pt "TARGET:" & hourTarget


pt "Parameters, SITE= "& strSite & " WARNING= " & WARN & " ERRORTYPE= " & ErrorType
pt "Querying IIS Logs - Start time: "& Time 


'autoget location of IIS log files
	call getPath(logsroot & strSite &"\")
	'pt pathlogfile
	logfile = pathlogfile  & "ex" & logday & ".log"
	'pt logfile
	outputlog = "c:\scripts\logs\Logs_"& strSite & ".csv"

	pt vbcrlf & "Processing file : " & logfile & " Start time : " & Time 		
	Set objLogParser = CreateObject("MSUtil.LogQuery") 'these will fail if you haven't registered the .dll
	Set objInputFormat = CreateObject("MSUtil.LogQuery.IISW3CInputFormat")'set input type as Event Logs
	Set objOutputFormat = CreateObject("MSUtil.LogQuery.CSVOutputFormat")'set output type as CSV
	objOutputFormat.headers=False 'no header row
	
'date time s-ip cs-method cs-uri-stem cs-uri-query cs-username c-ip cs(User-Agent) cs(Cookie) cs(Referer) sc-status sc-substatus sc-win32-status sc-bytes time-taken 		
	strQuery="select date as Date, QUANTIZE(time, 3600) AS Hour, sc-status as Status, count(*) AS ErrorCount " &_
	"from " & chr(39) & logfile & chr(39) & " to " & chr(39) & outputlog & chr(39)& _
	" WHERE  sc-status >= " & Errortype &"  AND Hour >= " & chr(39) & hourTarget & chr(39) & " and Hour <= " & chr(39) & hora & chr(39) & " GROUP BY date, hour,sc-status HAVING ErrorCount > " & WARN &  " ORDER BY ErrorCount DESC"
	
	
	pt "Query = " & vbcrlf &  strQuery & vbcrlf
	'pt ""	
	objLogParser.ExecuteBatch strQuery, objInputFormat, objOutputFormat 'run the query	

	If Err.Number <> 0 Then'write any errors to the status file
		pt "ERROR - " & strSite & Time & " - "&Err.Number & " - "&Err.Description & " - "&Err.Source
		Err.Clear
	End If	
	Set objOutputFormat = nothing
	Set objInputFormat = nothing
	Set objLogParser = nothing	
	
	'Should parse the file and throw all in just one log
	pt "Chamando Parser: " & outputlog & ", " & strSite	
	call ParseResult(outputlog)
	
logOutputFile.Close

'Print Message to Screen
If (erros > WARN) and (erros < CRIT) Then
	strFinalOutput = "WARNING - "		
	intExit = intWarning
Elseif (erros > CRIT)  Then
	strFinalOutput = "CRITICAL - "			
	intExit = intCritical
Elseif erros <= WARN Then
	strFinalOutput = "OK - "
	intExit = intOK
end if  
'EX: WARNING - 2000 erros of type 404 in IIS log |  2000,500,4000
'"CRTICAL - Existem $cnterros erros no IIS do oglobo!|IIS Erros:  $cnterros , $WARN, $CRIT"

wscript.echo strFinalOutput & erros & " erros no site do " & strSite & " |IIS Erros: " & erros & ", " & WARN & ", " & CRIT
wscript.quit(intExit)



'################################  SUBS AND FUNCTIONS #####################################################

Function ParseResult(inFile)
'Parse logparser output and put into one single txt log
  on error resume next
  Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
  Dim oFileIn,strLine
  
'Open In File For Reading
    If objFSO.FileExists(inFile) = true Then  
	 pt "______________________________________________________"
	 pt strSite & vbcrlf 
        set	oFileIn = objFso.OpenTextFile(inFile, ForReading)       
	    Do While Not oFileIn.AtEndOfStream	
			strLine = cstr(oFileIn.ReadLine)		
			totalErr = split(strLine,",")
	'Parse and Get Last DIgits = total errors found		
			erros1 = cint(totalErr(3))			
			pt strLine & " - ErrorCount:" & erros1
			erros = erros + erros1
		Loop						
	End If 'inFile Check 
	pt "______________________________________________________"
	oFileIn.Close 'close scan txt	
end Function

sub getPath(folderspec)	
  'On error resume next
  Dim oFSO, oFolder, oFileCollection,copyto
  Dim oFolderCollection, oSubFolder,fs,folder  
  'pt "PATH=" & folderspec
  Set oFSO = CreateObject("Scripting.FileSystemObject")
  Set fs = CreateObject("Scripting.FileSystemObject")
  Set oFolder = oFSO.GetFolder(folderspec)   
   Set oFolderCollection = oFolder.SubFolders
		For Each folder in oFolderCollection					
		    'pt folder.name
			if instr(folder.name,"W3SVC") then							
				pathlogfile = folderspec & folder.name & "\"
				pt "Source=" & pathlogfile													
			end if			
		next	
	set fs = nothing
	set oFSO = nothing
end sub

Function getday(inputDate)
	Dim intMonth : intMonth = Right("00" & Month(inputDate), 2)
	Dim intDay : intDay = Right("00" & Day(inputDate), 2) 
	Dim intYear : intYear = Right("00" & Year(inputDate), 2)
	 'Forçar Dia
	intDay = intDay - intDia 	 
	if len(intDay) = 1 then
	 intDay = 0 & intDay  
	end if 
	getday = intYear & intMonth & intDay
End Function

Function getTime(inputTime)
'get current hour, set miuntes start to 00 and end to 59
	Dim intMin : intMin = Right("00" & minute(inputTime), 2)	
	Dim intHour : intHour = Right("00" & hour(inputTime), 2)
	intHour = cint(intHour)
	intGMToff = cint(intGMToff)
	intHour = intHour + intGMToff 
	pt intHour	
	getTime   = intHour &":59:00"
	hourTarget = intHour &":00:00"
end function


sub GetArgsSet()
	if argcountcommand=1 or argcountcommand=0 then
		call help()
	else 
		'pt "Getting Values"
		strSite = GetOneArg("-s")		  
		errortype = cstr(GetOneArg("-t"))
		WARN = cint(GetOneArg("-w"))
		CRIT = cint(GetOneArg("-c"))
	end if	
end sub

Function Help()
'Prints out help 	
		Dim str
		Dim strScriptFile : strScriptFile = "parselog_iis.vbs"
  		str="Check the Log Files os IIS server and output error count of current hour." & vbcrlf
		str=str&"Requires logparser.dll, customized to be used by Nagios" &vbCrlF
		str=str&vbCrlF
  		str=str&"cscript "& strScriptFile &" -s SiteName -t Tipo de Erro -w warning -c critical"&vbCrlF
		str=str&vbCrlF & "Example:" & vbcrlf
		str=str&"cscript "& strScriptFile &" -s myweb -t 404 -w 50 -c 100"&vbCrlF
  		str=str&vbCrlF
  		str=str&"-h [--help]                 Help."&vbCrlF
  		str=str&"-s sitename                 Website name in IIS 6 "&vbCrlF  
		str=str&"-t ErrorType                IIS errortype:400,404,501,500 etc... "&vbCrlF  
  		str=str&vbCrlF
  		str=str&"By Felipe Ferreira May 2010, version 3.0." & vbCrlF
  		wscript.echo str
		wscript.quit		
End Function

Function GetOneArg(strName)
	On Error Resume Next
	Dim i
	for i=0 to argcountcommand-1
		if (Ucase(arg(i))=Ucase(strName)) then
			GetOneArg=arg(i+1)
			Exit Function
		end if
	next		
End Function

Function GetArgs()
'Get ALL arguments passed to the script
	On Error Resume Next		
	Dim i		
	argcountcommand=WScript.Arguments.Count		
	for i=0 to argcountcommand-1
		arg(i)=WScript.Arguments(i)
       ' wscript.echo i & " - " & arg(i)
	next		
End Function

function pt(txt)
	if debug = 1 and log = 1 then
		wscript.echo txt
		logOutputFile.WriteLine txt
	elseif debug = 0 and log = 1 then
		logOutputFile.WriteLine txt
	elseif debug = 1 and log = 0 then
		wscript.echo txt
	end if
end function
