Я сделал скрипт, который поможет мне анализировать файлы журнала доступа без SSH к серверу (у меня есть только файл). Он подсчитывает и сортирует количество управляемых сайтов по IP-адресам, но я обнаружил, что для больших файлов это занимает слишком много времени (это ОЧЕНЬ элементарно). Я не хотел использовать скомпилированное приложение и не иметь SSH к серверу, поэтому я обратился к Powershell.

$sw = [Diagnostics.Stopwatch]::StartNew()
$input_path = ‘c:\temp\access_log2’
$ip_file = ‘c:\temp\IPs.txt’
$output_file = ‘c:\temp\SORTED.txt’
$regex = '\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b'
select-string -Path $input_path -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } > $ip_file
get-content $ip_file | group-object -noelement | Sort-Object count -descending > $output_file
get-Content $output_file -First 25
$sw.Stop()
$sw.Elapsed

Я тоже пробовал

$regex = ‘\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b’

для файла размером 5 МБ (14,4 КБ) это заняло 18 минут, для файла размером 37 МБ (158,5 КБ) - более 3 часов

Секундомер только для моего тестирования. Сценарий предназначен только для извлечения IP-адреса, их подсчета и сортировки по наиболее часто встречающимся. Возможно, запись в файл - самое большое замедление, но я не слишком знаком с переменными, хранящимися в оперативной памяти. Я думаю, что есть лучший способ извлечь IP-адреса (может быть, просто использовать первые 15 символов в строке?). Вот пример строк, объединенный формат журнала

21.198.52.3 - - [06/Aug/2017:11:31:54 -0400] "GET / HTTP/1.0" 301 452 "-" "-"
154.212.178.24 - - [06/Aug/2017:11:10:44 -0400] "GET /images/12345.jpg HTTP/1.1" 200 212443 "-" "Mozilla/5.0 (compatible; AhrefsBot/5.2; +http://ahrefs.com/robot/)"

Любой совет?

2 ответа2

0

Почему вы записываете свои данные в промежуточный файл ($ip_file)? Почему бы не передать его напрямую из Group-Object? Возможно, что-то подобное?

$sw = [Diagnostics.Stopwatch]::StartNew()

$input_path  = ‘c:\temp\access_log2’
$ip_file     = ‘c:\temp\IPs.txt’
$output_file = ‘c:\temp\SORTED.txt’
$regex       = '\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b'

Select-String -Path $input_path -Pattern $regex -AllMatches |
  ForEach-Object { $_.Matches } |
  ForEach-Object { $_.Value } |
  Group-Object -noelement |
  Sort-Object count -descending > $output_file
Get-Content $output_file -First 25

$sw.Stop()
$sw.Elapsed

Если это не ускорит процесс, вам следует попытаться выяснить, какая часть вашего сценария является медленной.

Может быть, начать просто делать что-то вроде этого. Затем добавьте функциональность немного назад, чтобы увидеть, где медлительность.

$sw = [Diagnostics.Stopwatch]::StartNew()
$input_path  = ‘c:\temp\access_log2’
$regex       = '\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b'
Select-String -Path $input_path -Pattern $regex -AllMatches | Out-Null
$sw.Stop()
$sw.Elapsed

Если вы хотите предположить, что файл журнала всегда правильно отформатирован, вы, вероятно, могли бы ускорить процесс и просто взять первый столбец. (Это обработало файл журнала Apache размером 233 МБ, 1 000 749 строк на моем компьютере примерно за 15 секунд)

Get-Content c:\temp\access_log2 | ForEach-Object { $_.split(' ')[0] } |
Group-Object -NoElement |
Sort-Object Count
0

Существует более простой (надеюсь, более быстрый подход), если ip лидирует в каждой строке. Простое разделение на пространство должно отделить IP.

При обработке строк вы можете увеличивать хеш-таблицу, адресованную ip

$sw = [Diagnostics.Stopwatch]::StartNew()
$input_path  = 'c:\Temp\access_log2'

$Hash = @{} 
ForEach ($Line in (Get-Content $Input_path)) {
    ++$Hash[$Line.split(' ')[0]]
} 
$Hash.GetEnumerator() | sort -Property Value -desc |Select -First 25
$sw.Stop()
$sw.Elapsed

Пример вывода с реплицированными только вашими строками:

Name                           Value
----                           -----
154.212.178.24                 5
21.198.52.3                    4

Ticks             : 121118
Days              : 0
Hours             : 0
Milliseconds      : 12
Minutes           : 0
Seconds           : 0
TotalDays         : 1,4018287037037E-07
TotalHours        : 3,36438888888889E-06
TotalMilliseconds : 12,1118
TotalMinutes      : 0,000201863333333333
TotalSeconds      : 0,0121118

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .