' IISLogAnalyzer.vbs
' 用法:cscript IISLogAnalyzer.vbs "日志文件路径" [输出文件路径]
Option Explicit
' 主函数
Sub Main()
Dim logPath, outputPath
Dim fso, logFile, outputFile
Dim line, fields, header
Dim stats, i
' 获取命令行参数
If WScript.Arguments.Count < 1 Then
WScript.Echo "用法: cscript IISLogAnalyzer.vbs ""日志文件路径"" [输出文件路径]"
WScript.Quit(1)
End If
logPath = WScript.Arguments(0)
If WScript.Arguments.Count > 1 Then
outputPath = WScript.Arguments(1)
Else
outputPath = "IISLogAnalysis_" & Replace(Replace(Now(), ":", ""), "/", "") & ".txt"
End If
' 创建文件系统对象
Set fso = CreateObject("Scripting.FileSystemObject")
' 检查日志文件是否存在
If Not fso.FileExists(logPath) Then
WScript.Echo "错误: 日志文件不存在 - " & logPath
WScript.Quit(1)
End If
' 初始化统计对象
Set stats = CreateObject("Scripting.Dictionary")
stats.CompareMode = 1 ' 文本比较(不区分大小写)
' 初始化统计数据
InitializeStats stats
WScript.Echo "正在分析 IIS 日志文件: " & logPath
WScript.Echo "输出文件: " & outputPath
' 读取日志文件
Set logFile = fso.OpenTextFile(logPath, 1, False, -1) ' 1=ForReading, -1=TristateUseDefault
' 读取文件头信息(前几行注释)
Do While Not logFile.AtEndOfStream
line = logFile.ReadLine
If Left(line, 1) = "#" Then
' 解析字段行
If InStr(line, "Fields:") > 0 Then
header = Mid(line, InStr(line, "Fields:") + 8)
stats("Fields") = Split(header)
End If
Else
' 后退一行,开始数据行处理
logFile.Skip(-Len(line) - 2) ' -2 for CRLF
Exit Do
End If
Loop
' 处理数据行
Dim lineCount : lineCount = 0
Do While Not logFile.AtEndOfStream
line = logFile.ReadLine
lineCount = lineCount + 1
' 显示进度
If lineCount Mod 1000 = 0 Then
WScript.Echo "已处理 " & lineCount & " 行..."
End If
ProcessLogLine line, stats
Loop
logFile.Close
WScript.Echo "分析完成,共处理 " & lineCount & " 行日志"
' 生成报告
GenerateReport outputPath, stats, lineCount
WScript.Echo "报告已生成: " & outputPath
End Sub
' 初始化统计数据结构
Sub InitializeStats(ByRef stats)
' 总请求数
stats("TotalRequests") = 0
' HTTP 方法统计
stats("Methods") = CreateObject("Scripting.Dictionary")
' HTTP 状态码统计
stats("StatusCodes") = CreateObject("Scripting.Dictionary")
' IP 地址统计(客户端)
stats("ClientIPs") = CreateObject("Scripting.Dictionary")
' URL 统计
stats("URLs") = CreateObject("Scripting.Dictionary")
' 用户代理统计
stats("UserAgents") = CreateObject("Scripting.Dictionary")
' 流量统计
stats("TotalBytesSent") = 0
stats("TotalBytesReceived") = 0
' 时间统计
stats("HourlyRequests") = CreateObject("Scripting.Dictionary")
For i = 0 To 23
stats("HourlyRequests")(CStr(i)) = 0
Next
' 响应时间统计
stats("ResponseTimes") = CreateObject("Scripting.Dictionary")
stats("ResponseTimes")("0-100ms") = 0
stats("ResponseTimes")("101-500ms") = 0
stats("ResponseTimes")("501-1000ms") = 0
stats("ResponseTimes")("1001-5000ms") = 0
stats("ResponseTimes")("5000+ms") = 0
End Sub
' 处理单行日志
Sub ProcessLogLine(ByVal line, ByRef stats)
Dim fields, i
Dim dateTime, method, uri, status, clientIP, userAgent, bytesSent, timeTaken
' 分割字段(IIS 日志使用空格分隔,但字段值可能包含空格,所以用引号处理)
fields = SplitLogLine(line)
If Not IsArray(stats("Fields")) Then
' 如果没有字段定义,使用默认顺序(根据 IIS 默认格式)
' date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username
' c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
If UBound(fields) >= 13 Then
dateTime = fields(0) & " " & fields(1)
clientIP = fields(8) ' c-ip
method = fields(4) ' cs-method
uri = fields(5) ' cs-uri-stem
status = fields(10) ' sc-status
userAgent = fields(9) ' cs(User-Agent)
bytesSent = fields(12) ' sc-bytes? 实际需要根据字段位置调整
timeTaken = fields(13) ' time-taken
End If
Else
' 根据字段定义解析(简化处理)
For i = 0 To UBound(stats("Fields"))
Select Case LCase(stats("Fields")(i))
Case "date"
dateTime = fields(i) & " " & dateTime
Case "time"
dateTime = dateTime & " " & fields(i)
Case "c-ip"
clientIP = fields(i)
Case "cs-method"
method = fields(i)
Case "cs-uri-stem"
uri = fields(i)
Case "sc-status"
status = fields(i)
Case "cs(user-agent)"
userAgent = fields(i)
Case "sc-bytes"
bytesSent = fields(i)
Case "time-taken"
timeTaken = fields(i)
End Select
Next
End If
' 更新统计
stats("TotalRequests") = stats("TotalRequests") + 1
' 统计 HTTP 方法
If method <> "" Then
If stats("Methods").Exists(method) Then
stats("Methods")(method) = stats("Methods")(method) + 1
Else
stats("Methods")(method) = 1
End If
End If
' 统计状态码
If status <> "" Then
If stats("StatusCodes").Exists(status) Then
stats("StatusCodes")(status) = stats("StatusCodes")(status) + 1
Else
stats("StatusCodes")(status) = 1
End If
End If
' 统计客户端 IP
If clientIP <> "" Then
If stats("ClientIPs").Exists(clientIP) Then
stats("ClientIPs")(clientIP) = stats("ClientIPs")(clientIP) + 1
Else
stats("ClientIPs")(clientIP) = 1
End If
End If
' 统计 URL(只统计前100个不同的URL)
If uri <> "" Then
If stats("URLs").Count < 100 Then
If stats("URLs").Exists(uri) Then
stats("URLs")(uri) = stats("URLs")(uri) + 1
Else
stats("URLs")(uri) = 1
End If
End If
End If
' 统计用户代理
If userAgent <> "" Then
' 简化用户代理字符串
Dim shortUA
shortUA = GetShortUserAgent(userAgent)
If stats("UserAgents").Exists(shortUA) Then
stats("UserAgents")(shortUA) = stats("UserAgents")(shortUA) + 1
Else
stats("UserAgents")(shortUA) = 1
End If
End If
' 统计每小时请求量
If dateTime <> "" Then
Dim hour
hour = GetHourFromDateTime(dateTime)
If hour >= 0 And hour <= 23 Then
stats("HourlyRequests")(CStr(hour)) = stats("HourlyRequests")(CStr(hour)) + 1
End If
End If
' 统计响应时间
If IsNumeric(timeTaken) Then
Dim timeNum
timeNum = CLng(timeTaken)
If timeNum <= 100 Then
stats("ResponseTimes")("0-100ms") = stats("ResponseTimes")("0-100ms") + 1
ElseIf timeNum <= 500 Then
stats("ResponseTimes")("101-500ms") = stats("ResponseTimes")("101-500ms") + 1
ElseIf timeNum <= 1000 Then
stats("ResponseTimes")("501-1000ms") = stats("ResponseTimes")("501-1000ms") + 1
ElseIf timeNum <= 5000 Then
stats("ResponseTimes")("1001-5000ms") = stats("ResponseTimes")("1001-5000ms") + 1
Else
stats("ResponseTimes")("5000+ms") = stats("ResponseTimes")("5000+ms") + 1
End If
End If
End Sub
' 分割日志行(处理带引号的字段)
Function SplitLogLine(ByVal line)
Dim result(), count, i, char, inQuotes, currentField
ReDim result(50) ' 假设最多50个字段
count = 0
inQuotes = False
currentField = ""
For i = 1 To Len(line)
char = Mid(line, i, 1)
If char = """" Then
inQuotes = Not inQuotes
ElseIf char = " " And Not inQuotes Then
If currentField <> "" Then
result(count) = currentField
count = count + 1
currentField = ""
End If
Else
currentField = currentField & char
End If
Next
' 添加最后一个字段
If currentField <> "" Then
result(count) = currentField
count = count + 1
End If
' 调整数组大小
ReDim Preserve result(count - 1)
SplitLogLine = result
End Function
' 获取简化用户代理字符串
Function GetShortUserAgent(ByVal userAgent)
Dim shortUA
shortUA = userAgent
' 截断过长的用户代理
If Len(userAgent) > 50 Then
shortUA = Left(userAgent, 50) & "..."
End If
GetShortUserAgent = shortUA
End Function
' 从日期时间字符串获取小时
Function GetHourFromDateTime(ByVal dateTime)
Dim hour
hour = -1
' 尝试解析时间格式,如 "2023-01-01 14:30:45"
If Len(dateTime) >= 13 Then
Dim timePart
timePart = Mid(dateTime, InStr(dateTime, " ") + 1)
If Len(timePart) >= 2 Then
hour = CInt(Left(timePart, 2))
End If
End If
GetHourFromDateTime = hour
End Function
' 生成报告
Sub GenerateReport(ByVal outputPath, ByRef stats, ByVal totalLines)
Dim fso, outFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set outFile = fso.CreateTextFile(outputPath, True)
outFile.WriteLine "IIS 日志分析报告"
outFile.WriteLine "生成时间: " & Now()
outFile.WriteLine "=========================================="
outFile.WriteLine
outFile.WriteLine "基本信息"
outFile.WriteLine "---------"
outFile.WriteLine "总日志行数: " & totalLines
outFile.WriteLine "总请求数: " & stats("TotalRequests")
outFile.WriteLine
' HTTP 方法统计
outFile.WriteLine "HTTP 方法统计"
outFile.WriteLine "--------------"
WriteDictionary outFile, stats("Methods"), stats("TotalRequests")
outFile.WriteLine
' HTTP 状态码统计
outFile.WriteLine "HTTP 状态码统计"
outFile.WriteLine "----------------"
WriteDictionary outFile, stats("StatusCodes"), stats("TotalRequests")
outFile.WriteLine
' 客户端 IP 统计(前20个)
outFile.WriteLine "客户端 IP 统计(前20个)"
outFile.WriteLine "----------------------"
WriteTopItems outFile, stats("ClientIPs"), 20, stats("TotalRequests")
outFile.WriteLine
' URL 统计(前20个)
outFile.WriteLine "URL 统计(前20个)"
outFile.WriteLine "-----------------"
WriteTopItems outFile, stats("URLs"), 20, stats("TotalRequests")
outFile.WriteLine
' 用户代理统计(前10个)
outFile.WriteLine "用户代理统计(前10个)"
outFile.WriteLine "--------------------"
WriteTopItems outFile, stats("UserAgents"), 10, stats("TotalRequests")
outFile.WriteLine
' 小时请求分布
outFile.WriteLine "小时请求分布"
outFile.WriteLine "-------------"
Dim hour
For hour = 0 To 23
Dim hourStr, count
hourStr = Right("0" & CStr(hour), 2) & ":00-" & Right("0" & CStr(hour), 2) & ":59"
count = stats("HourlyRequests")(CStr(hour))
Dim percentage
percentage = FormatNumber((count / stats("TotalRequests")) * 100, 2)
outFile.WriteLine hourStr & ": " & count & " 请求 (" & percentage & "%)"
Next
outFile.WriteLine
' 响应时间分布
outFile.WriteLine "响应时间分布"
outFile.WriteLine "-------------"
WriteDictionary outFile, stats("ResponseTimes"), stats("TotalRequests")
outFile.WriteLine
outFile.WriteLine "=========================================="
outFile.WriteLine "报告结束"
outFile.Close
End Sub
' 写入字典内容
Sub WriteDictionary(ByRef outFile, ByRef dict, ByVal total)
Dim key, count, percentage
Dim keys
keys = dict.Keys
For Each key In keys
count = dict(key)
If total > 0 Then
percentage = FormatNumber((count / total) * 100, 2)
outFile.WriteLine key & ": " & count & " (" & percentage & "%)"
Else
outFile.WriteLine key & ": " & count
End If
Next
End Sub
' 写入前N个项目
Sub WriteTopItems(ByRef outFile, ByRef dict, ByVal topN, ByVal total)
Dim items(), i, key, count
Dim keys
keys = dict.Keys
' 转换为数组便于排序
ReDim items(dict.Count - 1, 1)
i = 0
For Each key In keys
items(i, 0) = key
items(i, 1) = dict(key)
i = i + 1
Next
' 简单冒泡排序(按数量降序)
Dim j, tempKey, tempCount
For i = 0 To UBound(items, 1) - 1
For j = i + 1 To UBound(items, 1)
If items(i, 1) < items(j, 1) Then
tempKey = items(i, 0)
tempCount = items(i, 1)
items(i, 0) = items(j, 0)
items(i, 1) = items(j, 1)
items(j, 0) = tempKey
items(j, 1) = tempCount
End If
Next
Next
' 输出前N个
Dim outputCount
outputCount = topN
If UBound(items, 1) + 1 < outputCount Then
outputCount = UBound(items, 1) + 1
End If
For i = 0 To outputCount - 1
key = items(i, 0)
count = items(i, 1)
If total > 0 Then
Dim percentage
percentage = FormatNumber((count / total) * 100, 2)
outFile.WriteLine key & ": " & count & " (" & percentage & "%)"
Else
outFile.WriteLine key & ": " & count
End If
Next
End Sub
' 程序入口
Main
使用说明:
1. 基本用法:
cscript IISLogAnalyzer.vbs "C:\logs\iis\logfile.log"
2. 指定输出文件:
cscript IISLogAnalyzer.vbs "C:\logs\iis\logfile.log" "report.txt"
3. 功能特点:
- 解析标准 IIS 日志格式
- 支持字段自动检测
- 统计信息包括:
- HTTP 方法分布
- HTTP 状态码分布
- 客户端 IP 统计(前20个)
- 访问 URL 统计(前20个)
- 用户代理统计(前10个)
- 24小时请求分布
- 响应时间分布
4. 扩展建议:
增强版本可以添加以下功能:
' 添加错误统计
Sub AddErrorStats()
' 404错误统计
' 500错误统计
' 慢请求分析
End Sub
' 添加图表生成
Sub GenerateChart()
' 使用HTML输出带图表的报告
End Sub
' 添加多文件处理
Sub ProcessMultipleFiles()
' 批量处理多个日志文件
End Sub
' 添加时间范围过滤
Sub FilterByTimeRange()
' 按时间过滤日志记录
End Sub
5. 注意事项:
- IIS 日志格式可能有不同变体,可能需要根据实际情况调整字段解析
- 大日志文件可能需要较长时间处理
- 可以添加更多错误处理代码
这个工具提供了基本的 IIS 日志分析功能,可以根据需要进行扩展和定制。