2021-02-01 15:05:57 +08:00
|
|
|
# _helper.pm - A simple test suite helper
|
|
|
|
|
2022-03-19 00:45:17 +08:00
|
|
|
# Copyright (c) 2007-2022 imacat.
|
2021-02-06 19:34:55 +08:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
2021-02-01 15:05:57 +08:00
|
|
|
|
|
|
|
package _helper;
|
|
|
|
use 5.005;
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use base qw(Exporter);
|
2021-02-06 19:34:55 +08:00
|
|
|
our ($VERSION, @EXPORT);
|
2021-02-01 15:05:57 +08:00
|
|
|
$VERSION = "0.01";
|
2021-02-06 19:34:55 +08:00
|
|
|
@EXPORT = qw(
|
|
|
|
read_file read_raw_file write_file write_raw_file
|
|
|
|
run_cmd where_is file_type list_files preserve_source clean_up
|
2022-03-19 00:45:17 +08:00
|
|
|
has_no_file has_no_gzip has_no_bzip2 has_no_xz
|
2021-02-06 19:34:55 +08:00
|
|
|
make_log_file
|
|
|
|
make_apache_log_file make_syslog_log_file
|
|
|
|
make_ntp_log_file make_apache_ssl_log_file make_modified_iso_log_file
|
|
|
|
random_word
|
2022-03-19 00:45:17 +08:00
|
|
|
TYPE_TEXT TYPE_GZIP TYPE_BZIP2 TYPE_XZ
|
2021-02-06 19:34:55 +08:00
|
|
|
@LOG_FORMATS @SOURCE_TYPES @RESULT_TYPES @KEEP_MODES @OVERRIDE_MODES);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Prototype declaration
|
2021-02-06 19:34:55 +08:00
|
|
|
sub this_file();
|
|
|
|
sub read_file($);
|
|
|
|
sub read_raw_file($);
|
|
|
|
sub write_file($$);
|
|
|
|
sub write_raw_file($$);
|
|
|
|
sub run_cmd($@);
|
|
|
|
sub where_is($);
|
|
|
|
sub file_type($);
|
|
|
|
sub list_files($);
|
|
|
|
sub preserve_source($);
|
|
|
|
sub clean_up($$$);
|
|
|
|
sub has_no_file();
|
|
|
|
sub has_no_gzip();
|
|
|
|
sub has_no_bzip2();
|
2022-03-19 00:45:17 +08:00
|
|
|
sub has_no_xz();
|
2021-02-06 19:34:55 +08:00
|
|
|
sub make_log_file($$$@);
|
|
|
|
sub make_apache_log_file($;$);
|
|
|
|
sub make_syslog_log_file($;$);
|
|
|
|
sub make_ntp_log_file($;$);
|
|
|
|
sub make_apache_ssl_log_file($;$);
|
|
|
|
sub make_modified_iso_log_file($;$);
|
|
|
|
sub month_range($);
|
|
|
|
sub random_month_ranges();
|
2021-02-01 15:05:57 +08:00
|
|
|
sub split_months(\@);
|
|
|
|
sub insert_malformed(\@);
|
2021-02-06 19:34:55 +08:00
|
|
|
sub random_word();
|
|
|
|
sub random_ip();
|
|
|
|
sub random_domain();
|
2021-02-01 15:05:57 +08:00
|
|
|
|
|
|
|
use Data::Dumper;
|
|
|
|
use ExtUtils::MakeMaker qw();
|
|
|
|
use Fcntl qw(:seek);
|
|
|
|
use File::Basename qw(basename);
|
|
|
|
use File::Copy qw(copy);
|
|
|
|
use File::Path qw(mkpath rmtree);
|
|
|
|
use File::Spec::Functions qw(splitdir catdir catfile path);
|
|
|
|
use File::Temp qw(tempfile);
|
|
|
|
use Time::Local qw(timelocal);
|
|
|
|
$Data::Dumper::Indent = 1;
|
|
|
|
|
2022-03-19 00:45:17 +08:00
|
|
|
our (%WHERE_IS, $HAS_NO_FILE, $HAS_NO_GZIP, $HAS_NO_BZIP2, $HAS_NO_XZ);
|
2021-02-06 19:34:55 +08:00
|
|
|
%WHERE_IS = qw();
|
|
|
|
undef $HAS_NO_FILE;
|
|
|
|
undef $HAS_NO_GZIP;
|
|
|
|
undef $HAS_NO_BZIP2;
|
2022-03-19 00:45:17 +08:00
|
|
|
undef $HAS_NO_XZ;
|
2021-02-01 15:05:57 +08:00
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
use constant TYPE_TEXT => "text/plain";
|
2021-02-01 15:05:57 +08:00
|
|
|
use constant TYPE_GZIP => "application/x-gzip";
|
|
|
|
use constant TYPE_BZIP2 => "application/x-bzip2";
|
2022-03-19 00:45:17 +08:00
|
|
|
use constant TYPE_XZ => "application/x-xz";
|
2021-02-01 15:05:57 +08:00
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
our (@LOG_FORMATS, @SOURCE_TYPES, @RESULT_TYPES, @KEEP_MODES, @OVERRIDE_MODES);
|
2021-02-01 15:05:57 +08:00
|
|
|
# All the log format information
|
2021-02-06 19:34:55 +08:00
|
|
|
@LOG_FORMATS = (
|
|
|
|
{ "title" => "Apache access log",
|
|
|
|
"sub" => \&make_apache_log_file, },
|
|
|
|
{ "title" => "Syslog",
|
|
|
|
"sub" => \&make_syslog_log_file, },
|
|
|
|
{ "title" => "NTP",
|
|
|
|
"sub" => \&make_ntp_log_file, },
|
|
|
|
{ "title" => "Apache SSL engine log",
|
|
|
|
"sub" => \&make_apache_ssl_log_file, },
|
|
|
|
{ "title" => "modified ISO 8601 date/time",
|
|
|
|
"sub" => \&make_modified_iso_log_file, }, );
|
2021-02-01 15:05:57 +08:00
|
|
|
# All the source type information
|
2021-02-06 19:34:55 +08:00
|
|
|
@SOURCE_TYPES = (
|
|
|
|
{ "title" => "plain text source",
|
|
|
|
"type" => TYPE_TEXT,
|
|
|
|
"suf" => "",
|
|
|
|
"skip" => 0, },
|
|
|
|
{ "title" => "gzip source",
|
|
|
|
"type" => TYPE_GZIP,
|
|
|
|
"suf" => ".gz",
|
|
|
|
"skip" => has_no_gzip, },
|
|
|
|
{ "title" => "bzip2 source",
|
|
|
|
"type" => TYPE_BZIP2,
|
|
|
|
"suf" => ".bz2",
|
2022-03-19 00:45:17 +08:00
|
|
|
"skip" => has_no_bzip2, },
|
|
|
|
{ "title" => "xz source",
|
|
|
|
"type" => TYPE_XZ,
|
|
|
|
"suf" => ".xz",
|
|
|
|
"skip" => has_no_xz, }, );
|
2021-02-01 15:05:57 +08:00
|
|
|
# All the result type information
|
2021-02-06 19:34:55 +08:00
|
|
|
@RESULT_TYPES = (
|
|
|
|
{ "title" => "default compress",
|
|
|
|
"type" => TYPE_GZIP,
|
|
|
|
"suf" => ".gz",
|
|
|
|
"skip" => has_no_gzip,
|
|
|
|
"opts" => [], },
|
|
|
|
{ "title" => "gzip compress",
|
|
|
|
"type" => TYPE_GZIP,
|
|
|
|
"suf" => ".gz",
|
|
|
|
"skip" => has_no_gzip,
|
|
|
|
"opts" => [qw(-c g)], },
|
|
|
|
{ "title" => "bzip2 compress",
|
|
|
|
"type" => TYPE_BZIP2,
|
|
|
|
"suf" => ".bz2",
|
|
|
|
"skip" => has_no_bzip2,
|
|
|
|
"opts" => [qw(-c b)], },
|
2022-03-19 00:45:17 +08:00
|
|
|
{ "title" => "xz compress",
|
|
|
|
"type" => TYPE_XZ,
|
|
|
|
"suf" => ".xz",
|
|
|
|
"skip" => has_no_xz,
|
|
|
|
"opts" => [qw(-c x)], },
|
2021-02-06 19:34:55 +08:00
|
|
|
{ "title" => "no compress",
|
|
|
|
"type" => TYPE_TEXT,
|
|
|
|
"suf" => "",
|
|
|
|
"skip" => 0,
|
|
|
|
"opts" => [qw(-c n)], }, );
|
|
|
|
# All the keep mode information
|
|
|
|
@KEEP_MODES = (
|
|
|
|
{ "title" => "keep default",
|
|
|
|
"opts" => [],
|
|
|
|
"tm" => 1,
|
|
|
|
"del" => 0,
|
|
|
|
"tmp" => 1,
|
|
|
|
"stdin" => 0, },
|
|
|
|
{ "title" => "keep all",
|
|
|
|
"opts" => [qw(-k a)],
|
|
|
|
"tm" => 0,
|
|
|
|
"del" => 0,
|
|
|
|
"tmp" => 0,
|
|
|
|
"stdin" => 0, },
|
|
|
|
{ "title" => "keep delete",
|
|
|
|
"opts" => [qw(-k d)],
|
|
|
|
"tm" => 0,
|
|
|
|
"del" => 1,
|
|
|
|
"tmp" => 1,
|
|
|
|
"stdin" => 0, },
|
|
|
|
{ "title" => "keep restart",
|
|
|
|
"opts" => [qw(-k r)],
|
|
|
|
"tm" => 0,
|
|
|
|
"del" => 0,
|
|
|
|
"tmp" => 1,
|
|
|
|
"stdin" => 0, },
|
|
|
|
{ "title" => "keep this month",
|
|
|
|
"opts" => [qw(-k t)],
|
|
|
|
"tm" => 1,
|
|
|
|
"del" => 0,
|
|
|
|
"tmp" => 1,
|
|
|
|
"stdin" => 0, },
|
|
|
|
{ "title" => "keep STDIN",
|
|
|
|
"opts" => [],
|
|
|
|
"tm" => 0,
|
|
|
|
"del" => 0,
|
|
|
|
"tmp" => 0,
|
|
|
|
"stdin" => 1, }, );
|
|
|
|
# All the override mode information
|
|
|
|
@OVERRIDE_MODES = (
|
|
|
|
{ "title" => "override no existing",
|
|
|
|
"opts" => [],
|
|
|
|
"exists" => 0,
|
|
|
|
"ok" => 1,
|
|
|
|
"ce" => sub { $_[1]; }, },
|
|
|
|
{ "title" => "override default",
|
|
|
|
"opts" => [],
|
|
|
|
"exists" => 1,
|
|
|
|
"ok" => 0,
|
|
|
|
"ce" => sub { $_[0]; }, },
|
|
|
|
{ "title" => "override overwrite",
|
|
|
|
"opts" => [qw(-o o)],
|
|
|
|
"exists" => 1,
|
|
|
|
"ok" => 1,
|
|
|
|
"ce" => sub { $_[1]; }, },
|
|
|
|
{ "title" => "override append",
|
|
|
|
"opts" => [qw(-o a)],
|
|
|
|
"exists" => 1,
|
|
|
|
"ok" => 1,
|
|
|
|
"ce" => sub { $_[0] . $_[1]; }, },
|
|
|
|
{ "title" => "override ignore",
|
|
|
|
"opts" => [qw(-o i)],
|
|
|
|
"exists" => 1,
|
|
|
|
"ok" => 1,
|
|
|
|
"ce" => sub { $_[0] || $_[1]; }, },
|
|
|
|
{ "title" => "override fail",
|
|
|
|
"opts" => [qw(-o f)],
|
|
|
|
"exists" => 1,
|
|
|
|
"ok" => 0,
|
|
|
|
"ce" => sub { $_[0]; }, }, );
|
|
|
|
|
|
|
|
# Return the name of this file
|
|
|
|
sub this_file() { basename($0); }
|
|
|
|
|
|
|
|
# A simple reader to read a log file in any supported format
|
|
|
|
sub read_file($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($file, $content);
|
|
|
|
$file = $_[0];
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# non-existing file
|
|
|
|
return undef if !-e $file;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a gzip compressed file
|
|
|
|
if ($file =~ /\.gz$/) {
|
2022-03-19 09:23:39 +08:00
|
|
|
# IO::Uncompress::Gunzip
|
|
|
|
if (eval { require IO::Uncompress::Gunzip; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $gz;
|
2021-02-01 15:05:57 +08:00
|
|
|
$content = "";
|
2022-03-19 09:41:43 +08:00
|
|
|
$gz = IO::Uncompress::Gunzip->new($file)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Uncompress::Gunzip::GunzipError";
|
2022-03-19 09:38:15 +08:00
|
|
|
$content = join "", <$gz>;
|
2022-03-19 09:23:39 +08:00
|
|
|
$gz->close or die this_file . ": $file: $IO::Uncompress::Gunzip::GunzipError";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# gzip executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
2021-02-06 19:34:55 +08:00
|
|
|
$CMD = where_is "gzip";
|
2021-02-01 15:05:57 +08:00
|
|
|
$CMD = "\"$CMD\" -cd \"$file\"";
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "$CMD |" or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
$content = join "", <$PH>;
|
2021-02-06 19:34:55 +08:00
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a bzip compressed file
|
|
|
|
} elsif ($file =~ /\.bz2$/) {
|
2022-03-19 09:23:39 +08:00
|
|
|
# IO::Uncompress::Bunzip2
|
|
|
|
if (eval { require IO::Uncompress::Bunzip2; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $bz;
|
2021-02-01 15:05:57 +08:00
|
|
|
$content = "";
|
2022-03-19 09:41:43 +08:00
|
|
|
$bz = IO::Uncompress::Bunzip2->new($file)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Uncompress::Bunzip2::Bunzip2Error";
|
2022-03-19 09:38:15 +08:00
|
|
|
$content = join "", <$bz>;
|
2022-03-19 09:23:39 +08:00
|
|
|
$bz->close or die this_file . ": $file: $IO::Uncompress::Bunzip2::Bunzip2Error";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# bzip2 executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
2021-02-06 19:34:55 +08:00
|
|
|
$CMD = where_is "bzip2";
|
2021-02-01 15:05:57 +08:00
|
|
|
$CMD = "bzip2 -cd \"$file\"";
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "$CMD |" or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
$content = join "", <$PH>;
|
2021-02-06 19:34:55 +08:00
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2022-03-19 00:45:17 +08:00
|
|
|
# an xz compressed file
|
2022-03-19 08:39:49 +08:00
|
|
|
} elsif ($file =~ /\.xz$/) {
|
2022-03-19 00:45:17 +08:00
|
|
|
# IO::Uncompress::UnXz
|
|
|
|
if (eval { require IO::Uncompress::UnXz; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $xz;
|
2022-03-19 00:45:17 +08:00
|
|
|
$content = "";
|
2022-03-19 09:41:43 +08:00
|
|
|
$xz = IO::Uncompress::UnXz->new($file)
|
2022-03-19 00:45:17 +08:00
|
|
|
or die this_file . ": $file: $IO::Uncompress::UnXz::UnXzError";
|
2022-03-19 09:38:15 +08:00
|
|
|
$content = join "", <$xz>;
|
2022-03-19 00:45:17 +08:00
|
|
|
$xz->close or die this_file . ": $file: $IO::Uncompress::UnXz::UnXzError";
|
|
|
|
return $content;
|
|
|
|
|
|
|
|
# xz executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
|
|
|
$CMD = where_is "xz";
|
|
|
|
$CMD = "xz -cd \"$file\"";
|
|
|
|
open $PH, "$CMD |" or die this_file . ": $CMD: $!";
|
|
|
|
$content = join "", <$PH>;
|
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a plain text file
|
|
|
|
} else {
|
|
|
|
my $FH;
|
2021-02-06 19:34:55 +08:00
|
|
|
open $FH, $file or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
$content = join "", <$FH>;
|
2021-02-06 19:34:55 +08:00
|
|
|
close $FH or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# A raw file reader
|
|
|
|
sub read_raw_file($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($file, $content, $FH, $size);
|
|
|
|
$file = $_[0];
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# non-existing file
|
|
|
|
return undef if !-e $file;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$size = (stat $file)[7];
|
2021-02-06 19:34:55 +08:00
|
|
|
open $FH, $file or die this_file . ": $file: $!";
|
|
|
|
binmode $FH or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
(read($FH, $content, $size) == $size)
|
2021-02-06 19:34:55 +08:00
|
|
|
or die this_file . ": $file: $!";
|
|
|
|
close $FH or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# A simple writer to write a log file in any supported format
|
|
|
|
sub write_file($$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($file, $content);
|
|
|
|
($file, $content) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a gzip compressed file
|
|
|
|
if ($file =~ /\.gz$/) {
|
2022-03-19 09:23:39 +08:00
|
|
|
# IO::Compress::Gzip
|
|
|
|
if (eval { require IO::Compress::Gzip; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $gz;
|
|
|
|
$gz = IO::Compress::Gzip->new($file)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Gzip::GzipError";
|
2022-03-19 09:35:03 +08:00
|
|
|
($gz->write($content) == length $content)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Gzip::GzipError";
|
|
|
|
$gz->close or die this_file . ": $file: $IO::Compress::Gzip::GzipError";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# gzip executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
2021-02-06 19:34:55 +08:00
|
|
|
$CMD = where_is "gzip";
|
2021-02-01 15:05:57 +08:00
|
|
|
$CMD = "\"$CMD\" -c9f > \"$file\"";
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "| $CMD" or die this_file . ": $CMD: $!";
|
|
|
|
print $PH $content or die this_file . ": $CMD: $!";
|
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a bzip compressed file
|
|
|
|
} elsif ($file =~ /\.bz2$/) {
|
2022-03-19 09:23:39 +08:00
|
|
|
# IO::Compress::Bzip2
|
|
|
|
if (eval { require IO::Compress::Bzip2; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $bz;
|
|
|
|
$bz = IO::Compress::Bzip2->new($file)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Bzip2::Bzip2Error";
|
2022-03-19 09:35:03 +08:00
|
|
|
($bz->write($content) == length $content)
|
2022-03-19 09:23:39 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Bzip2::Bzip2Error";
|
|
|
|
$bz->close or die this_file . ": $file: $IO::Compress::Bzip2::Bzip2Error";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# bzip2 executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
2021-02-06 19:34:55 +08:00
|
|
|
$CMD = where_is "bzip2";
|
2021-02-01 15:05:57 +08:00
|
|
|
$CMD = "\"$CMD\" -9f > \"$file\"";
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "| $CMD" or die this_file . ": $CMD: $!";
|
|
|
|
print $PH $content or die this_file . ": $CMD: $!";
|
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2022-03-19 00:45:17 +08:00
|
|
|
# an xz compressed file
|
2022-03-19 09:42:11 +08:00
|
|
|
} elsif ($file =~ /\.xz$/) {
|
2022-03-19 00:45:17 +08:00
|
|
|
# IO::Compress::Xz
|
|
|
|
if (eval { require IO::Compress::Xz; 1; }) {
|
2022-03-19 09:41:43 +08:00
|
|
|
my $xz;
|
|
|
|
$xz = IO::Compress::Xz->new($file)
|
2022-03-19 00:45:17 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Xz::XzError";
|
2022-03-19 09:35:03 +08:00
|
|
|
($xz->write($content) == length $content)
|
2022-03-19 00:45:17 +08:00
|
|
|
or die this_file . ": $file: $IO::Compress::Xz::XzError";
|
|
|
|
$xz->close or die this_file . ": $file: $IO::Compress::Xz::XzError";
|
|
|
|
return;
|
|
|
|
|
|
|
|
# xz executable
|
|
|
|
} else {
|
|
|
|
my ($PH, $CMD);
|
|
|
|
$CMD = where_is "xz";
|
|
|
|
$CMD = "\"$CMD\" -9f > \"$file\"";
|
|
|
|
open $PH, "| $CMD" or die this_file . ": $CMD: $!";
|
|
|
|
print $PH $content or die this_file . ": $CMD: $!";
|
|
|
|
close $PH or die this_file . ": $CMD: $!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# a plain text file
|
|
|
|
} else {
|
|
|
|
my $FH;
|
2021-02-06 19:34:55 +08:00
|
|
|
open $FH, ">$file" or die this_file . ": $file: $!";
|
|
|
|
print $FH $content or die this_file . ": $file: $!";
|
|
|
|
close $FH or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# A raw file writer
|
|
|
|
sub write_raw_file($$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($file, $content, $FH);
|
|
|
|
($file, $content) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
|
|
|
open $FH, ">$file" or die this_file . ": $file: $!";
|
|
|
|
binmode $FH or die this_file . ": $file: $!";
|
|
|
|
print $FH $content or die this_file . ": $file: $!";
|
|
|
|
close $FH or die this_file . ": $file: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Run a command and return the result
|
|
|
|
sub run_cmd($@) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($ret_no, $out, $err, $in, @cmd, $cmd, $OUT, $ERR, $STDOUT, $STDERR, $PH);
|
2021-02-01 15:05:57 +08:00
|
|
|
($in, @cmd) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$err = "Running " . join(" ", map "\"$_\"", @cmd) . "\n";
|
|
|
|
$out = "";
|
2021-02-06 19:34:55 +08:00
|
|
|
|
|
|
|
open $STDOUT, ">&", \*STDOUT or die this_file . ": STDOUT: $!";
|
|
|
|
open $STDERR, ">&", \*STDERR or die this_file . ": STDERR: $!";
|
|
|
|
$OUT = tempfile or die this_file . ": tempfile: $!";
|
|
|
|
binmode $OUT or die this_file . ": tempfile: $!";
|
|
|
|
$ERR = tempfile or die this_file . ": tempfile: $!";
|
|
|
|
binmode $ERR or die this_file . ": tempfile: $!";
|
|
|
|
open STDOUT, ">&", $OUT or die this_file . ": tempfile: $!";
|
|
|
|
binmode STDOUT or die this_file . ": tempfile: $!";
|
|
|
|
open STDERR, ">&", $ERR or die this_file . ": tempfile: $!";
|
|
|
|
binmode STDERR or die this_file . ": tempfile: $!";
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$cmd = join " ", map "\"$_\"", @cmd;
|
|
|
|
if ($^O eq "MSWin32") {
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "| $cmd" or die this_file . ": $cmd: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
open $PH, "|-", @cmd or die this_file . ": $cmd: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
binmode $PH or die this_file . ": $cmd: $!";
|
|
|
|
print $PH $in or die this_file . ": $cmd: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
close $PH;
|
2021-02-06 19:34:55 +08:00
|
|
|
$ret_no = $?;
|
|
|
|
|
|
|
|
open STDOUT, ">&", $STDOUT or die this_file . ": tempfile: $!";
|
|
|
|
open STDERR, ">&", $STDERR or die this_file . ": tempfile: $!";
|
|
|
|
|
|
|
|
seek $OUT, 0, SEEK_SET or die this_file . ": tempfile: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
$out = join "", <$OUT>;
|
2021-02-06 19:34:55 +08:00
|
|
|
close $OUT or die this_file . ": tempfile: $!";
|
|
|
|
seek $ERR, 0, SEEK_SET or die this_file . ": tempfile: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
$err = join "", <$ERR>;
|
2021-02-06 19:34:55 +08:00
|
|
|
close $ERR or die this_file . ": tempfile: $!";
|
|
|
|
|
|
|
|
return ($ret_no, $out, $err);
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Find an executable
|
2021-02-01 15:05:57 +08:00
|
|
|
# Code inspired from CPAN::FirstTime
|
2021-02-06 19:34:55 +08:00
|
|
|
sub where_is($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($file, $path);
|
|
|
|
$file = $_[0];
|
2021-02-06 19:34:55 +08:00
|
|
|
return $WHERE_IS{$file} if exists $WHERE_IS{$file};
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach my $dir (path) {
|
2021-02-06 19:34:55 +08:00
|
|
|
return ($WHERE_IS{$file} = $path)
|
2021-02-01 15:05:57 +08:00
|
|
|
if defined($path = MM->maybe_command(catfile($dir, $file)));
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
return ($WHERE_IS{$file} = undef);
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Find the file type
|
|
|
|
sub file_type($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my $file;
|
|
|
|
$file = $_[0];
|
|
|
|
return undef unless -e $file;
|
|
|
|
# Use File::MMagic
|
|
|
|
if (eval { require File::MMagic; 1; }) {
|
2021-02-06 19:34:55 +08:00
|
|
|
$_ = File::MMagic->new->checktype_filename($file);
|
2021-02-01 15:05:57 +08:00
|
|
|
return "application/x-gzip" if /gzip/;
|
|
|
|
return "application/x-bzip2" if /bzip2/;
|
2022-03-19 00:45:17 +08:00
|
|
|
return "application/x-xz" if /xz/;
|
2021-02-01 15:05:57 +08:00
|
|
|
# All else are text/plain
|
|
|
|
return "text/plain";
|
|
|
|
}
|
|
|
|
# Use file executable
|
2021-02-06 19:34:55 +08:00
|
|
|
if (defined($_ = where_is "file")) {
|
2021-02-01 15:05:57 +08:00
|
|
|
$_ = join "", `"$_" "$file"`;
|
|
|
|
return "application/x-gzip" if /gzip/;
|
|
|
|
return "application/x-bzip2" if /bzip2/;
|
2022-03-19 00:45:17 +08:00
|
|
|
return "application/x-xz" if /: XZ/;
|
2021-02-01 15:05:57 +08:00
|
|
|
# All else are text/plain
|
|
|
|
return "text/plain";
|
|
|
|
}
|
|
|
|
# No type checker available
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Obtain the files list in a directory
|
|
|
|
sub list_files($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($dir, $DH);
|
|
|
|
$dir = $_[0];
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
opendir $DH, $dir or die this_file . ": $dir: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
while (defined($_ = readdir $DH)) {
|
|
|
|
next if $_ eq "." || $_ eq ".." || !-f "$dir/$_";
|
|
|
|
push @_, $_;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
closedir $DH or die this_file . ": $dir: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return join " ", sort @_;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Preserve the source test files
|
|
|
|
sub preserve_source($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($dir, $DH);
|
|
|
|
$dir = $_[0];
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
opendir $DH, $dir or die this_file . ": $dir: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
while (defined($_ = readdir $DH)) {
|
|
|
|
next if $_ eq "." || $_ eq ".." || !-f "$dir/$_";
|
|
|
|
push @_, $_;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
closedir $DH or die this_file . ": $dir: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
rmtree "$dir/source";
|
|
|
|
mkpath "$dir/source";
|
2021-02-06 19:34:55 +08:00
|
|
|
write_raw_file "$dir/source/$_", read_raw_file "$dir/$_"
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach @_;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Clean up the test files
|
|
|
|
sub clean_up($$$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($r, $dir, $test_no, $test_name, $c);
|
|
|
|
($r, $dir, $test_no) = @_;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Nothing to clean up
|
|
|
|
return unless -e $dir;
|
|
|
|
# Success
|
|
|
|
if ($r) {
|
|
|
|
rmtree $dir;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
# Fail - keep the test files for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$test_name = basename((caller)[1]);
|
|
|
|
$test_name =~ s/\.t$//;
|
2021-02-01 15:05:57 +08:00
|
|
|
$c = 1;
|
2021-02-06 19:34:55 +08:00
|
|
|
$c++ while -e ($_ = "$dir.$test_name.$test_no.$c");
|
|
|
|
rename $dir, $_ or die this_file . ": $dir, $_: $!";
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# If we have the file type checker somewhere
|
|
|
|
sub has_no_file() {
|
|
|
|
$HAS_NO_FILE = eval { require File::MMagic; 1; }
|
|
|
|
|| defined where_is "file"?
|
2021-02-01 15:05:57 +08:00
|
|
|
0: "File::MMagic or file executable not available"
|
2021-02-06 19:34:55 +08:00
|
|
|
if !defined $HAS_NO_FILE;
|
|
|
|
return $HAS_NO_FILE;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# If we have gzip support somewhere
|
|
|
|
sub has_no_gzip() {
|
2022-03-19 09:23:39 +08:00
|
|
|
$HAS_NO_GZIP = eval { require IO::Compress::Gzip; require IO::Uncompress::Gunzip; 1; }
|
2021-02-06 19:34:55 +08:00
|
|
|
|| defined where_is "gzip"?
|
2022-03-19 09:23:39 +08:00
|
|
|
0: "IO::Compress::Gzip or gzip executable not available"
|
2021-02-06 19:34:55 +08:00
|
|
|
if !defined $HAS_NO_GZIP;
|
|
|
|
return $HAS_NO_GZIP;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# If we have bzip2 support somewhere
|
|
|
|
sub has_no_bzip2() {
|
2022-03-19 09:23:39 +08:00
|
|
|
$HAS_NO_BZIP2 = eval { require IO::Compress::Bzip2; require IO::Uncompress::Bunzip2; 1; }
|
2021-02-06 19:34:55 +08:00
|
|
|
|| defined where_is "bzip2"?
|
2022-03-19 09:23:39 +08:00
|
|
|
0: "IO::Compress::Bzip2 v2 or bzip2 executable not available"
|
2021-02-06 19:34:55 +08:00
|
|
|
if !defined $HAS_NO_BZIP2;
|
|
|
|
return $HAS_NO_BZIP2;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2022-03-19 00:45:17 +08:00
|
|
|
# If we have xz support somewhere
|
|
|
|
sub has_no_xz() {
|
|
|
|
$HAS_NO_XZ = eval { require IO::Compress::Xz; require IO::Uncompress::UnXz; 1; }
|
|
|
|
|| defined where_is "xz"?
|
|
|
|
0: "IO::Compress::Xz or xz executable not available"
|
|
|
|
if !defined $HAS_NO_XZ;
|
|
|
|
return $HAS_NO_XZ;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random existing log file
|
|
|
|
sub make_log_file($$$@) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($make_log_file, $dir, $filename_pattern, @months, %contents);
|
|
|
|
($make_log_file, $dir, $filename_pattern, @months) = @_;
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Find a non-decided month and have an existing log
|
|
|
|
$_{$_[int rand @_]} = 1 if (@_ = grep !exists $_{$_}, @months) > 0;
|
|
|
|
# Find a non-decided month and not have an existing log
|
|
|
|
$_{$_[int rand @_]} = 0 if (@_ = grep !exists $_{$_}, @months) > 0;
|
|
|
|
# Decide the remain months randomly
|
|
|
|
$_{$_} = int rand 2 foreach grep !exists $_{$_}, @months;
|
|
|
|
%contents = qw();
|
|
|
|
foreach my $m (@months) {
|
|
|
|
my ($file, $path);
|
2021-02-06 19:34:55 +08:00
|
|
|
$file = sprintf($filename_pattern, $m);
|
2021-02-01 15:05:57 +08:00
|
|
|
$path = catfile($dir, $file);
|
|
|
|
if ($_{$m}) {
|
2021-02-06 19:34:55 +08:00
|
|
|
$contents{$file} = (&$make_log_file($path, $m))[0];
|
2021-02-01 15:05:57 +08:00
|
|
|
} else {
|
|
|
|
$contents{$file} = "";
|
|
|
|
}
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
return %contents;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random Apache access log file
|
|
|
|
sub make_apache_log_file($;$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($file, $month, @logs, $content, @ranges, %months, $var_dump, $tz);
|
2021-02-01 15:05:57 +08:00
|
|
|
($file, $month) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
@logs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time zone
|
|
|
|
$tz = (-12 + (int rand 53) / 2) * 3600;
|
|
|
|
# To be removed
|
|
|
|
#$tz = -12 + (int rand 53) / 2;
|
|
|
|
#$tz = sprintf "%+05d", int($tz) * 100 + ($tz - int($tz)) * 60;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of a month
|
|
|
|
if (defined $month) {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = month_range $month;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = random_month_ranges;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
for (my $i = 0; $i + 1 < @ranges; $i++) {
|
2021-02-01 15:05:57 +08:00
|
|
|
my $hosts;
|
|
|
|
# 2-5 hosts
|
|
|
|
$hosts = 2 + int rand 4;
|
|
|
|
# Generate the visit time of each host
|
|
|
|
for (my $j = 0; $j < $hosts; $j++) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($host, $t, $user, $http_ver, @host_logs, $count);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Host type: 1: IP, 0: domain name
|
2021-02-06 19:34:55 +08:00
|
|
|
$host = int rand 2? random_ip: random_domain;
|
|
|
|
$t = $ranges[$i] + int rand($ranges[$i + 1] - $ranges[$i]);
|
|
|
|
$user = (0, 0, 1)[int rand 3]? "-": random_word;
|
|
|
|
$http_ver = (qw(HTTP/1.1 HTTP/1.1 HTTP/1.1 HTTP/1.0))[int rand 4];
|
2021-02-01 15:05:57 +08:00
|
|
|
# 3-5 log records for each host
|
2021-02-06 19:34:55 +08:00
|
|
|
$count = 3 + int rand 3;
|
|
|
|
@host_logs = qw();
|
|
|
|
while (@host_logs < $count) {
|
|
|
|
my ($time, $method, $url, $dirs, @dirs, $type, $status, $size);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time text
|
|
|
|
@_ = gmtime($t + $tz);
|
|
|
|
$_[5] += 1900;
|
|
|
|
$_[4] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$_[4]];
|
2021-02-06 19:34:55 +08:00
|
|
|
$time = sprintf "%02d/%s/%04d:%02d:%02d:%02d %+05d",
|
2021-02-01 15:05:57 +08:00
|
|
|
@_[3,4,5,2,1,0],
|
|
|
|
int($tz / 3600) * 100 + ($tz - int($tz / 3600) * 3600) / 60;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$method = (qw(GET GET GET HEAD POST))[int rand 5];
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Generate a random URL
|
|
|
|
# 0-3 levels of directories
|
|
|
|
$dirs = int rand 4;
|
|
|
|
@dirs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @dirs, "/" . random_word while @dirs < $dirs;
|
2021-02-01 15:05:57 +08:00
|
|
|
$type = ("", qw(html html txt css png jpg))[int rand 7];
|
|
|
|
if ($type eq "") {
|
|
|
|
$url = join("", @dirs) . "/";
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
$url = join("", @dirs) . "/" . random_word . ".$type";
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$status = (200, 200, 200, 200, 304, 400, 403, 404)[int rand 8];
|
|
|
|
if ($status == 304) {
|
|
|
|
$size = 0;
|
|
|
|
} else {
|
|
|
|
$size = 200 + int rand 35000;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @host_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("%s - %s [%s] \"%s %s %s\" %d %d\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$host, $user, $time,
|
|
|
|
$method, $url, $http_ver, $status, $size),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# 0-2 seconds later
|
|
|
|
$t += int rand 3;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @logs, @host_logs;
|
2021-02-01 15:05:57 +08:00
|
|
|
# 0-5 seconds later
|
|
|
|
$t += int rand 6;
|
|
|
|
}
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Sort by time
|
|
|
|
# A series of requests from a same host may run cross the next host
|
|
|
|
# So we need to sort again
|
|
|
|
@logs = sort { $$a{"time"} <=> $$b{"time"} } @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Variables used, for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$var_dump = Data::Dumper->Dump([\@logs, $tz], [qw($logs $tz)]);
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Split by months
|
|
|
|
%months = split_months @logs;
|
|
|
|
# Drop the time and keep the records
|
|
|
|
@logs = map $$_{"record"}, @logs;
|
|
|
|
# Insert 1-2 malformed lines
|
|
|
|
insert_malformed @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Compose the content
|
|
|
|
$content = join "", @logs;
|
|
|
|
# Output the file
|
2021-02-06 19:34:55 +08:00
|
|
|
write_file($file, $content);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Return the content
|
2021-02-06 19:34:55 +08:00
|
|
|
return $content, $var_dump, %months;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random Syslog log file
|
|
|
|
sub make_syslog_log_file($;$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($file, $month, @logs, $content, @ranges, %months, $var_dump);
|
2021-02-01 15:05:57 +08:00
|
|
|
my (@hosts, $hosts);
|
|
|
|
($file, $month) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
@logs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# 3-5 hosts
|
|
|
|
$hosts = 3 + int rand 3;
|
|
|
|
@hosts = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @hosts, random_word while @hosts < $hosts;
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of a month
|
|
|
|
if (defined $month) {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = month_range $month;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = random_month_ranges;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
for (my $i = 0; $i + 1 < @ranges; $i++) {
|
|
|
|
my (@month_logs, $count, @t);
|
2021-02-01 15:05:57 +08:00
|
|
|
# 5-12 log records for each month
|
2021-02-06 19:34:55 +08:00
|
|
|
$count = 5 + int rand 8;
|
|
|
|
@month_logs = qw();
|
2021-02-01 15:05:57 +08:00
|
|
|
# Generate the time of each record
|
|
|
|
@t = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @t, $ranges[$i] + int rand($ranges[$i + 1] - $ranges[$i])
|
|
|
|
while @t < $count;
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach my $t (sort @t) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($time, $host, $app, $pid, $msg);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time text
|
|
|
|
@_ = localtime $t;
|
|
|
|
$_[5] += 1900;
|
|
|
|
$_[4] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$_[4]];
|
2021-02-06 19:34:55 +08:00
|
|
|
$time = sprintf "%s %2d %02d:%02d:%02d", @_[4,3,2,1,0];
|
2021-02-01 15:05:57 +08:00
|
|
|
$host = $hosts[int rand scalar @hosts];
|
2021-02-06 19:34:55 +08:00
|
|
|
$app = (qw(kernel sendmail sshd su CRON), random_word, random_word)[int rand 5];
|
2021-02-01 15:05:57 +08:00
|
|
|
# PID 2-65535 (PID 1 is init)
|
|
|
|
$pid = 2 + int rand 65533;
|
|
|
|
# 3-12 words for each message
|
|
|
|
$_ = 3 + int rand 10;
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @_, random_word while @_ < $_;
|
2021-02-01 15:05:57 +08:00
|
|
|
$msg = join " ", @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("%s %s %s[%d] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $host, $app, $pid, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @logs, @month_logs;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Variables used, for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$var_dump = Data::Dumper->Dump([\@logs], [qw($logs)]);
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Split by months
|
|
|
|
%months = split_months @logs;
|
|
|
|
# Drop the time and keep the records
|
|
|
|
@logs = map $$_{"record"}, @logs;
|
|
|
|
# Insert 1-2 malformed lines
|
|
|
|
insert_malformed @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Compose the content
|
|
|
|
$content = join "", @logs;
|
|
|
|
# Output the file
|
2021-02-06 19:34:55 +08:00
|
|
|
write_file($file, $content);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Return the content
|
2021-02-06 19:34:55 +08:00
|
|
|
return $content, $var_dump, %months;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random NTP log file
|
|
|
|
sub make_ntp_log_file($;$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($file, $month, @logs, $content, @ranges, %months, $var_dump);
|
2021-02-01 15:05:57 +08:00
|
|
|
my ($pid, $peers, @peers, $refs, @refs);
|
|
|
|
($file, $month) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
@logs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# PID 2-65535 (PID 1 is init)
|
|
|
|
$pid = 2 + int rand 65533;
|
|
|
|
# 3-5 peers
|
|
|
|
$peers = 3 + int rand 3;
|
|
|
|
@peers = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @peers, random_ip while @peers < $peers;
|
2021-02-01 15:05:57 +08:00
|
|
|
# 2-3 references
|
|
|
|
$refs = 2 + int rand 2;
|
2021-02-06 19:34:55 +08:00
|
|
|
push @refs, random_ip while @refs < $refs;
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of a month
|
|
|
|
if (defined $month) {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = month_range $month;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = random_month_ranges;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
for (my $i = 0; $i + 1 < @ranges; $i++) {
|
|
|
|
my (@month_logs, $count, @t);
|
2021-02-01 15:05:57 +08:00
|
|
|
# 5-12 log records for each month
|
2021-02-06 19:34:55 +08:00
|
|
|
$count = 5 + int rand 8;
|
|
|
|
@month_logs = qw();
|
2021-02-01 15:05:57 +08:00
|
|
|
# Generate the time of each record
|
|
|
|
@t = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @t, $ranges[$i] + int rand($ranges[$i + 1] - $ranges[$i])
|
|
|
|
while @t < $count;
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach my $t (sort @t) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($time, $type, $msg);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time text
|
|
|
|
@_ = localtime $t;
|
|
|
|
$_[5] += 1900;
|
|
|
|
$_[4] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$_[4]];
|
2021-02-06 19:34:55 +08:00
|
|
|
$time = sprintf "%2d %s %02d:%02d:%02d", @_[3,4,2,1,0];
|
2021-02-01 15:05:57 +08:00
|
|
|
# PID change - chance 2.73%, 50% change to total 25 records
|
|
|
|
$pid = 2 + int rand 65533
|
|
|
|
if rand() < 0.0273;
|
|
|
|
$type = int rand 3;
|
|
|
|
# Type 0 - peer reachability
|
|
|
|
if ($type == 0) {
|
|
|
|
my ($peer, $events);
|
|
|
|
# 1-15 events
|
|
|
|
$events = 1 + int rand 15;
|
|
|
|
$peer = $peers[int rand @peers];
|
|
|
|
# Reachable
|
|
|
|
if (int rand 5 > 1) {
|
|
|
|
$msg = "peer $peer event 'event_reach' (0x84) status 'unreach, conf, auth, $events events, event_reach' (0xe0f4)";
|
|
|
|
# Unreachable
|
|
|
|
} else {
|
|
|
|
$msg = "peer $peer event 'event_unreach' (0x83) status 'unreach, conf, auth, $events events, event_unreach' (0xe0f3)";
|
|
|
|
}
|
|
|
|
# Type 1 - reference host
|
|
|
|
} elsif ($type == 1) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($ref_host, $stratum);
|
|
|
|
$ref_host = $refs[int rand @refs];
|
2021-02-01 15:05:57 +08:00
|
|
|
# Stratum 2-4
|
|
|
|
$stratum = 2 + int rand 2;
|
2021-02-06 19:34:55 +08:00
|
|
|
$msg = "synchronized to $ref_host, stratum $stratum";
|
2021-02-01 15:05:57 +08:00
|
|
|
# Type 2 - clock set
|
|
|
|
} elsif ($type == 2) {
|
|
|
|
my ($off, $freq, $err, $poll);
|
|
|
|
$off = (rand() - 0.5) / 10;
|
|
|
|
$freq = rand() * -10;
|
|
|
|
$err = rand() / 20;
|
|
|
|
# poll 4-10
|
|
|
|
$poll = 4 + int rand 7;
|
|
|
|
$msg = sprintf "offset %8.6f sec freq %6.3f ppm error %8.6f poll %d",
|
|
|
|
$off, $freq, $err, $poll;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("%s ntpd[%d] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @logs, @month_logs;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Variables used, for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$var_dump = Data::Dumper->Dump([\@logs], [qw($logs)]);
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Split by months
|
|
|
|
%months = split_months @logs;
|
|
|
|
# Drop the time and keep the records
|
|
|
|
@logs = map $$_{"record"}, @logs;
|
|
|
|
# Insert 1-2 malformed lines
|
|
|
|
insert_malformed @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Compose the content
|
|
|
|
$content = join "", @logs;
|
|
|
|
# Output the file
|
2021-02-06 19:34:55 +08:00
|
|
|
write_file($file, $content);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Return the content
|
2021-02-06 19:34:55 +08:00
|
|
|
return $content, $var_dump, %months;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random Apache SSL engine log file
|
|
|
|
sub make_apache_ssl_log_file($;$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($file, $month, @logs, $content, @ranges, %months, $var_dump);
|
2021-02-01 15:05:57 +08:00
|
|
|
my $host;
|
|
|
|
($file, $month) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
@logs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
|
|
|
|
$host = random_domain;
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of a month
|
|
|
|
if (defined $month) {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = month_range $month;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = random_month_ranges;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
for (my $i = 0; $i + 1 < @ranges; $i++) {
|
|
|
|
my (@month_logs, $count, @t);
|
2021-02-01 15:05:57 +08:00
|
|
|
# 3-5 visitors for each month
|
2021-02-06 19:34:55 +08:00
|
|
|
$count = 3 + int rand 3;
|
|
|
|
@month_logs = qw();
|
2021-02-01 15:05:57 +08:00
|
|
|
# Generate the time of each record
|
|
|
|
@t = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @t, $ranges[$i] + int rand($ranges[$i + 1] - $ranges[$i])
|
|
|
|
while @t < $count;
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach my $t (sort @t) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($time, $pid, $remote, $priority, $child, $msg);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time text
|
|
|
|
@_ = localtime $t;
|
|
|
|
$_[5] += 1900;
|
|
|
|
$_[4] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$_[4]];
|
2021-02-06 19:34:55 +08:00
|
|
|
$time = sprintf "%02d/%s/%04d %02d:%02d:%02d", @_[3,4,5,2,1,0];
|
2021-02-01 15:05:57 +08:00
|
|
|
# PID 2-65535 (PID 1 is init)
|
|
|
|
$pid = 2 + int rand 65533;
|
|
|
|
# Remote client
|
2021-02-06 19:34:55 +08:00
|
|
|
$remote = random_ip;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Child number
|
|
|
|
$child = int rand 15;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Error
|
|
|
|
if (int rand 5 == 1) {
|
|
|
|
$priority = "error";
|
|
|
|
$msg = "SSL handshake failed (server $host:443, client $remote) (OpenSSL library error follows)";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
$msg = "OpenSSL: error:1408E0F4:SSL routines:SSL3_GET_MESSAGE:unexpected message";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Info
|
|
|
|
} else {
|
|
|
|
$priority = "info";
|
|
|
|
$msg = "Connection to child $child established (server $host:443, client $remote)";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
$msg = "Seeding PRNG with 1164 bytes of entropy";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
# 1: bad
|
|
|
|
if (int rand 2) {
|
|
|
|
$msg = "Spurious SSL handshake interrupt[Hint: Usually just one of those OpenSSL confusions!?]";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
# 2: success
|
|
|
|
} else {
|
|
|
|
my $reqs;
|
|
|
|
# 1-5 requests
|
|
|
|
$reqs = 1 + int rand 5;
|
|
|
|
for (my $j = 1; $j <= $reqs; $j++) {
|
|
|
|
if ($j == 1) {
|
|
|
|
$msg = "Initial (No.$j) HTTPS request received for child $child ($host:443)"
|
|
|
|
} else {
|
|
|
|
$msg = "Subsequent (No.$j) HTTPS request received for child $child ($host:443)"
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
$msg = "Connection to child $child closed with standard shutdown (server $host:443, client $remote)";
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s %05d] [%s] %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $pid, $priority, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @logs, @month_logs;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Variables used, for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$var_dump = Data::Dumper->Dump([\@logs], [qw($logs)]);
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Split by months
|
|
|
|
%months = split_months @logs;
|
|
|
|
# Drop the time and keep the records
|
|
|
|
@logs = map $$_{"record"}, @logs;
|
|
|
|
# Insert 1-2 malformed lines
|
|
|
|
insert_malformed @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Compose the content
|
|
|
|
$content = join "", @logs;
|
|
|
|
# Output the file
|
2021-02-06 19:34:55 +08:00
|
|
|
write_file($file, $content);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Return the content
|
2021-02-06 19:34:55 +08:00
|
|
|
return $content, $var_dump, %months;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Create a random modified ISO 8861 date/time log file
|
|
|
|
sub make_modified_iso_log_file($;$) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($file, $month, @logs, $content, @ranges, %months, $var_dump, $tz);
|
2021-02-01 15:05:57 +08:00
|
|
|
($file, $month) = @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
@logs = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time zone
|
|
|
|
$tz = (-12 + (int rand 53) / 2) * 3600;
|
|
|
|
# To be removed
|
|
|
|
#$tz = -12 + (int rand 53) / 2;
|
|
|
|
#$tz = sprintf "%+05d", int($tz) * 100 + ($tz - int($tz)) * 60;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of a month
|
|
|
|
if (defined $month) {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = month_range $month;
|
2021-02-01 15:05:57 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
} else {
|
2021-02-06 19:34:55 +08:00
|
|
|
@ranges = random_month_ranges;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
for (my $i = 0; $i + 1 < @ranges; $i++) {
|
|
|
|
my (@month_logs, $count, @t);
|
2021-02-01 15:05:57 +08:00
|
|
|
# 5-12 log records for each month
|
2021-02-06 19:34:55 +08:00
|
|
|
$count = 3 + int rand 3;
|
|
|
|
@month_logs = qw();
|
2021-02-01 15:05:57 +08:00
|
|
|
# Generate the time of each record
|
|
|
|
@t = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @t, $ranges[$i] + int rand($ranges[$i + 1] - $ranges[$i])
|
|
|
|
while @t < $count;
|
2021-02-01 15:05:57 +08:00
|
|
|
foreach my $t (sort @t) {
|
2021-02-06 19:34:55 +08:00
|
|
|
my ($time, $id, $msg);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Time text
|
|
|
|
@_ = gmtime($t + $tz);
|
|
|
|
$_[5] += 1900;
|
|
|
|
$_[4]++;
|
2021-02-06 19:34:55 +08:00
|
|
|
$time = sprintf "%04d-%02d-%02d %02d:%02d:%02d %+05d",
|
|
|
|
@_[5,4,3,2,1,0],
|
2021-02-01 15:05:57 +08:00
|
|
|
int($tz / 3600) * 100 + ($tz - int($tz / 3600) * 3600) / 60;
|
|
|
|
# identity
|
2021-02-06 19:34:55 +08:00
|
|
|
$id = random_word;
|
2021-02-01 15:05:57 +08:00
|
|
|
# 3-12 words for each message
|
|
|
|
$_ = 3 + int rand 10;
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @_, random_word while @_ < $_;
|
2021-02-01 15:05:57 +08:00
|
|
|
$msg = join " ", @_;
|
2021-02-06 19:34:55 +08:00
|
|
|
push @month_logs, {
|
2021-02-01 15:05:57 +08:00
|
|
|
"time" => $t,
|
|
|
|
"record" => sprintf("[%s] %s: %s\n",
|
2021-02-06 19:34:55 +08:00
|
|
|
$time, $id, $msg),
|
2021-02-01 15:05:57 +08:00
|
|
|
};
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
push @logs, @month_logs;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Variables used, for failure investigation
|
2021-02-06 19:34:55 +08:00
|
|
|
$var_dump = Data::Dumper->Dump([\@logs, $tz], [qw($logs $tz)]);
|
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Split by months
|
|
|
|
%months = split_months @logs;
|
|
|
|
# Drop the time and keep the records
|
|
|
|
@logs = map $$_{"record"}, @logs;
|
|
|
|
# Insert 1-2 malformed lines
|
|
|
|
insert_malformed @logs;
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
# Compose the content
|
|
|
|
$content = join "", @logs;
|
|
|
|
# Output the file
|
2021-02-06 19:34:55 +08:00
|
|
|
write_file($file, $content);
|
2021-02-01 15:05:57 +08:00
|
|
|
# Return the content
|
2021-02-06 19:34:55 +08:00
|
|
|
return $content, $var_dump, %months;
|
2021-02-01 15:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Get the range of a specific month
|
|
|
|
sub month_range($) {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($month, @range);
|
|
|
|
$month = $_[0];
|
|
|
|
# Sanity check
|
|
|
|
return unless $month =~ /^(\d{4})(\d{2})$/;
|
|
|
|
@range = qw();
|
|
|
|
# The beginning of the month
|
|
|
|
@_ = (0, 0, 0, 1, $2 - 1, $1 - 1900);
|
|
|
|
return unless defined($_ = timelocal(@_[0...6]));
|
|
|
|
push @range, $_;
|
|
|
|
# The beginning of the next month
|
|
|
|
$_[4]++;
|
|
|
|
if ($_[4] > 11) {
|
|
|
|
$_[4] = 0;
|
|
|
|
$_[5]++;
|
|
|
|
}
|
|
|
|
return unless defined($_ = timelocal(@_[0...6]));
|
|
|
|
push @range, $_;
|
|
|
|
return @range;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Get the range of some previous months
|
|
|
|
sub random_month_ranges() {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
my ($num, @range);
|
|
|
|
# 1-3 previous months
|
|
|
|
$num = 1 + int rand 3;
|
|
|
|
@range = qw();
|
|
|
|
unshift @range, time;
|
|
|
|
@_ = (0, 0, 0, 1, (localtime)[4,5]);
|
|
|
|
unshift @range, timelocal(@_);
|
|
|
|
for (my $i = 0; $i < $num; $i++) {
|
|
|
|
$_[4]--;
|
|
|
|
if ($_[4] < 0) {
|
|
|
|
$_[4] = 11;
|
|
|
|
$_[5]--;
|
|
|
|
}
|
|
|
|
unshift @range, timelocal(@_);
|
|
|
|
}
|
|
|
|
return @range;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Split the log records by months
|
2021-02-01 15:05:57 +08:00
|
|
|
sub split_months(\@) {
|
|
|
|
local ($_, %_);
|
|
|
|
my ($logs, %months);
|
|
|
|
$logs = $_[0];
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
%months = qw();
|
|
|
|
foreach (@$logs) {
|
|
|
|
my $month;
|
|
|
|
@_ = localtime $$_{"time"};
|
|
|
|
$month = sprintf "%04d%02d", $_[5] + 1900, $_[4] + 1;
|
|
|
|
$months{$month} = "" if !exists $months{$month};
|
|
|
|
$months{$month} .= $$_{"record"};
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
return %months;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Insert 1-2 malformed lines
|
2021-02-01 15:05:57 +08:00
|
|
|
sub insert_malformed(\@) {
|
|
|
|
local ($_, %_);
|
|
|
|
my ($logs, $malformed);
|
|
|
|
$logs = $_[0];
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
$malformed = 1 + int rand 2;
|
|
|
|
while ($malformed > 0) {
|
|
|
|
my $line;
|
|
|
|
# Generate the random malformed line
|
|
|
|
$_ = 3 + int rand 5;
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @_, random_word while @_ < $_;
|
2021-02-01 15:05:57 +08:00
|
|
|
$line = join(" ", @_) . ".\n";
|
|
|
|
$line =~ s/^(.)/uc $1/e;
|
|
|
|
# The position to insert the line
|
|
|
|
# The position cannot be 0 - or we cannot judge the log format
|
2021-02-06 19:34:55 +08:00
|
|
|
$_ = 1 + int rand(@$logs - 1);
|
2021-02-01 15:05:57 +08:00
|
|
|
$logs = [@$logs[0...$_], $line, @$logs[$_+1...$#$logs]];
|
|
|
|
$malformed--;
|
|
|
|
}
|
2021-02-06 19:34:55 +08:00
|
|
|
|
2021-02-01 15:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Supply a random English word
|
|
|
|
sub random_word() {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
@_ = qw(
|
2021-02-06 19:34:55 +08:00
|
|
|
hard-to-find striped poor scene miniature marble error shelter clear settle
|
|
|
|
march breath tested symptomatic delicate road punish grain fabulous camp
|
|
|
|
authority love system placid bake maddening sleep precious crabby lovely jolly
|
|
|
|
wrist park common volleyball tick judicious degree alluring hydrant oatmeal
|
|
|
|
aboard light spare delirious unwritten unnatural existence deadpan cagey
|
|
|
|
disastrous station fear dam adorable grape event silent extra-large shame meaty
|
|
|
|
husky drag religion extra-small pot valuable deceive obese seed history
|
|
|
|
wholesale tremble delightful leather cabbage death tub loss twig hate noxious
|
|
|
|
trashy sleet bleach quizzical familiar nappy teaching private yak turkey foolish
|
|
|
|
concentrate reject tacit goofy men ajar communicate);
|
2021-02-01 15:05:57 +08:00
|
|
|
return $_[int rand @_];
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Supply a random IP
|
|
|
|
sub random_ip() {
|
2021-02-01 15:05:57 +08:00
|
|
|
return join ".", (int rand 255, int rand 255,
|
|
|
|
int rand 255, 1 + int rand 254);
|
|
|
|
}
|
|
|
|
|
2021-02-06 19:34:55 +08:00
|
|
|
# Supply a random domain
|
|
|
|
sub random_domain() {
|
2021-02-01 15:05:57 +08:00
|
|
|
local ($_, %_);
|
|
|
|
# Generate a random domain name
|
|
|
|
# 3-5 levels, end with net or com
|
|
|
|
$_ = 2 + int rand 3;
|
|
|
|
@_ = qw();
|
2021-02-06 19:34:55 +08:00
|
|
|
push @_, random_word while @_ < $_;
|
2021-02-01 15:05:57 +08:00
|
|
|
push @_, (qw(net com))[int rand 2];
|
|
|
|
return join ".", @_;
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|