Из того, что я вижу здесь, выглядит так, как будто код (как сейчас) ищет пакеты до некоторого времени отключения и сохраняет ли он определенные условия в хэшах %n
и %v
.
Почему бы не присвоить дополнительный флаг вашей функции alarm
, которая называется $training
.Если это правда, просто учтите значения пакетов, в противном случае рассчитайте оценку для этой аномалии (если она есть) и верните это значение.Если аномалии нет или вы находитесь в режиме обучения, просто верните ноль:
sub alarm {
my ($key, $val, $training) = @_;
my $score = 0;
if ( $training ) {
...do your accounting...
} else {
...do your comparisons & set score accordingly...
}
return $score;
}
Бросьте свой большой while
в подпрограмму, и пусть эта подпрограмма примет имя файла и будет ли оноРежим обучения или нет.
sub examine {
my ($file, $training) = @_;
if ( open my $fh, '<', $file ) {
while (<$fh>) {
...this is your big while loop...
...pass $training along to your alarm() calls...
}
} else {
die "Failed to open $file: $!\n';
}
}
Ваша основная программа теперь:
use constant TRAINING => 1;
examine('file1', TRAINING);
examine('file2', !TRAINING);
Дополнительные примечания:
- Используйте
my()
вместо local
хотя это не оказывает существенного влияния на эту программу, это хорошая привычка. - Не используйте хорошо известное имя функции
alarm
, когда оно действительно ничего не делает, вместо этогоназовите это как check_packet_values
- или что-то, что имеет смысл для вас и вашей команды. Прекратите использовать магические числа
use constant {
CUTOFF_TIME => 10300000,
ANOMALY_SCORE => 30000
};
Используйтереальный анализатор даты / времени, чтобы ваши значения имели какое-то значение.str2time
из Date::Parse
даст вам время в секундах эпохи (секунды с 1 января 1970 года).
- Используйте имена переменных, которые что-то значат.
%n
и %v
трудно понять в этом коде, но %n_seen
и %value_seen
(а также %first_seen_time
вместо %t
).Помните, что ваш код не работает быстрее, если вы используете более короткие имена переменных. Прекратите использование глобальных переменных, когда это возможно.Счетчики могут быть глобальными, но ваш комментарий должен быть встроен только в процедуру, которая инициализирует и печатает комментарий.Итак, вместо того, чтобы делать то, что вы делаете, как:
$to_score = check_packet_value($to, $flags)
and push @comments, "$to=$flags";
...
$score = $to_score + $from_score + ...
if ( !$training && $score > ANOMALY_THRESHOLD ) {
print "blah blah blah @comments\n";
}
Кроме того, никогда, никогда не используйте $ `- это приводит к огромным потерям производительности во всем вашем сценарии (даже еслиона никогда не вызывает эту функцию).Вместо:
if ( $text =~ /\n\n/ ) { $text = $` }
Использовать
if ( $text =~ /(.*)\n\n/ ) {
$text = $1;
}
(Редактировать: добавлено предупреждение о $ `)