Created
May 25, 2016 17:24
-
-
Save kuronekomichael/2dc265adc0a73593d3f3714766880fd6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -w | |
use strict; | |
use warnings; | |
use Time::Local 'timelocal'; | |
$| = 1; | |
my $config = { | |
# ログの検索条件(ユーザIDを指定することになるはず) | |
criterion => undef, | |
# 探索するApacheログの格納パス | |
logs => '~/logs', | |
# ここで指定した秒数を超えてアクセスがない場合は、サービスから離れたとみなす | |
threshold_sec => 300, # デフォルト5分(300sec) | |
}; | |
my $MONTH = {Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11}; | |
die "usage: perl ./who_is_unsleeper.pl --target=<target-viewer-id>\nexample)117965337" unless ($ARGV[0]); | |
$config->{criterion} = $ARGV[0]; | |
main(); | |
sub main { | |
my $stat = { | |
criterion => $config->{criterion}, | |
date_logs => {}, | |
intervals => [] | |
}; | |
my @files = list_apache_accesslog_files($config->{logs}); | |
# my $file = pop @files; | |
# check_logfile($stat, $file); | |
foreach my $file (@files) { | |
check_logfile($stat, $file); | |
} | |
output_report($stat); | |
} | |
sub check_logfile { | |
my $stat = shift or die; | |
my $file = shift or die; | |
print "Reading... '$file' \n"; | |
if ($file =~ m/\.gz$/) { | |
check_gz_logfile($stat, $file); | |
} elsif ($file =~ m/\.log$/) { | |
check_txt_logfile($stat, $file); | |
} else { | |
die "Unknown logfile format: $file"; | |
} | |
} | |
sub check_gz_logfile { | |
my $stat = shift or die; | |
my $file = shift or die; | |
open my $fh, "zcat $file 2>/dev/null |" or die "Cannot zcat '$file' for reading: $!"; | |
while (<$fh>) { | |
next unless (m/$stat->{criterion}/); | |
# ログが残された日時を取得 | |
die unless (m/(\d{2})\/([A-Z][a-z]{2})\/(\d{4}):(\d{2}):(\d{2}):(\d{2})\s\+\d{4}/); | |
my ($sec, $min, $hour, $mday, $month, $year) = (int($6), int($5), int($4), int($1), $MONTH->{$2}, int($3)); | |
my $time = timelocal($sec, $min, $hour, $mday, $month, $year - 1900); | |
my $date = sprintf("%04d-%02d-%02d", $year, $month + 1, $mday); | |
# ログ日付の統計情報がなければ、この時点で作成する | |
unless (exists $stat->{'date_logs'}->{$date}) { | |
$stat->{'date_logs'}->{$date} = { | |
access_count => 0, | |
access_list => [], | |
lasttime => 0, | |
}; | |
foreach (0..23) { | |
push @{$stat->{'date_logs'}->{$date}->{access_list}}, { access_count => 0, interval_sec => [] }; | |
} | |
} | |
# 前日の日付を取得 | |
my $prev_time = timelocal(0, 0, 0, $mday, $month, $year - 1900) - (24 * 60 * 60); | |
my ($prev_day, $prev_month, $prev_year) = (localtime($prev_time))[3..5]; | |
my $lastdate = sprintf("%04d-%02d-%02d", $prev_year + 1900, $prev_month + 1, $prev_day); | |
# 当日のアクセスログがある場合→それと比較 | |
# 当日のアクセスログがない場合→前日分をみて、あれば比較 | |
# アクセス時間差を取る | |
my $lasttime = undef; | |
if ($stat->{'date_logs'}->{$date}->{'lasttime'} > 0) { | |
$lasttime = $stat->{'date_logs'}->{$date}->{'lasttime'}; | |
} elsif (exists $stat->{'date_logs'}->{$lastdate} && $stat->{'date_logs'}->{$lastdate}->{'lasttime'} > 0) { | |
$lasttime = $stat->{'date_logs'}->{$lastdate}->{'lasttime'}; | |
} | |
if ($lasttime) { | |
my $interval_sec = $time - $lasttime; | |
if ($interval_sec > $config->{threshold_sec}) { | |
# 休息をカウント | |
push @{$stat->{'date_logs'}->{$date}->{access_list}[$hour]->{interval_sec}}, $interval_sec; | |
push @{$stat->{intervals}}, { | |
rest_start => $lasttime, | |
rest_end => $time | |
}; | |
} | |
} | |
#TODO: アクセス数をカウント | |
$stat->{'date_logs'}->{$date}->{access_count}++; | |
$stat->{'date_logs'}->{$date}->{access_list}[$hour]->{access_count}++; | |
if ($stat->{'date_logs'}->{$date}->{'lasttime'} < $time) { | |
$stat->{'date_logs'}->{$date}->{'lasttime'} = $time; | |
} | |
#print $_; | |
} | |
close $fh; | |
} | |
# 指定したディレクトリ配下のapacheログファイル名をリストアップして返す | |
sub list_apache_accesslog_files { | |
my $dir = shift or die; | |
my @files = (); | |
opendir DIR, $dir or die "Cannot open '$dir' accesslog dir: $!"; | |
foreach (readdir(DIR)) { | |
next unless (m/apache\.(?:sp\.)?accesslog\.\d{8}\.log\.gz/); | |
push @files, $config->{logs}.'/'.$_; | |
} | |
closedir DIR; | |
return sort { | |
my $a_date = $1 if ($a =~ m/(\d{8})/); | |
my $b_date = $1 if ($b =~ m/(\d{8})/); | |
return 1 if ($a_date > $b_date); | |
return -1 if ($a_date < $b_date); | |
return 0; | |
} @files; | |
} | |
# Apacheログの日付形式をエポック秒に変換して返す | |
# 例) '09/May/2016:00:00:02 +0900' => 1462719602 | |
sub str_to_epochtime { | |
die unless ($_[0] =~ m/(\d{2})\/([A-Z][a-z]{2})\/(\d{4}):(\d{2}):(\d{2}):(\d{2})\s\+\d{4}/); | |
return timelocal(int($6), int($5), int($4), int($1), $MONTH->{$2}, (int($3) - 1900)); | |
} | |
sub epochtime_to_str { | |
my ($sec, $min, $hour, $mday, $mon, $year) = localtime($_[0]); | |
return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec); | |
} | |
#sub get_yesterday { | |
# my $date = shift or die; | |
# die unless ($date =~ m/^(\d{4})(\d{2})(\d{2})$/); | |
# my $time = timelocal(0, 0, 0, $3, $2 - 1, $1 - 1900) - (24 * 60 * 60); | |
# my ($day, $month, $year) = (localtime($time))[3..5]; | |
# return sprintf("%04d%02d%02d", $year + 1900, $month + 1, $day); | |
#} | |
sub output_report { | |
my $stat = shift or die; | |
my $date_logs = $stat->{date_logs}; | |
foreach my $date (sort keys %$date_logs) { | |
print "[$date]\n"; | |
print "\tアクセス数: $date_logs->{$date}->{access_count}\n"; | |
print "\t最終アクセス: ".epochtime_to_str($date_logs->{$date}->{lasttime})."\n"; | |
foreach my $hour (0..23) { | |
print "\t\t".sprintf("%02d", $hour).": ".sprintf("%4d", $date_logs->{$date}->{access_list}[$hour]->{access_count}); | |
#print ", 5分以上の休憩:".($#{$date_logs->{$date}->{access_list}[$hour]->{interval_sec}} + 1); | |
print "\n"; | |
} | |
} | |
print "\n"; | |
print "[休憩時間]\n"; | |
foreach my $interval (@{$stat->{intervals}}) { | |
my $diff = ($interval->{rest_end} - $interval->{rest_start}); | |
my $hour = int($diff / 60 / 60); | |
$diff -= ($hour * 60 * 60); | |
my $min = int($diff / 60); | |
my $sec = $diff - ($min * 60); | |
print sprintf("\t%d時間%02d分%02d秒", $hour, $min, $sec), "\t(", epochtime_to_str($interval->{rest_start})." 〜 ".epochtime_to_str($interval->{rest_end}), ")\n"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment