-
Notifications
You must be signed in to change notification settings - Fork 1
/
activity_logger.pl
executable file
·153 lines (140 loc) · 4.74 KB
/
activity_logger.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/perl -w
use strict;
use IO::Handle;
use POSIX;
#use Proc::Daemon;
#Proc::Daemon::Init;
# Don't daemonize if you're running this as a launch agent!
use constant IDLE_TIMEOUT => 600; # seconds of inactivity after which an
# idle status is recognized
use constant SLEEP_TIME => 30; # seconds to sleep between polling status
use constant MAX_LOG_DELTA => 3600; # Put a point in the log file at least
# every so many seconds
my $monitor_user = 'goerz';
my $log_folder = '/Users/'. $monitor_user . '/.activity_logs';
sub get_logfilename{
my ($sec,$min,$hour,$mday,
$month,$year,$wday,$yday,$isdst) = gmtime(time);
$year += 1900;
$month = sprintf("%02i", $month+1);
return $log_folder . '/' . 'activity' . $year . '-' . $month . '.log';
}
sub lock_logfile{
my $log_file = shift;
if ( -f "$log_file.lock"){
open(LOCK, "$log_file.lock") or die ("Can't set lock\n");
my $pid = <LOCK>;
close LOCK;
my $locking_process = `ps -p $pid`;
if ($locking_process =~ /activity_logger/){
exit(1) # another process is writing to the log file
} else {
system("rm -f $log_file.lock");
}
}
open(LOCK, ">$log_file.lock") or die ("Can't set lock\n");
print LOCK $$;
close LOCK;
}
sub open_logfile{
my $log_file = shift;
lock_logfile($log_file);
my $mtime = (stat $log_file)[9];
open my($LOG), ">>", $log_file or die ("Can't open $log_file\n");
$LOG->autoflush(1);
if (defined($mtime)){
print $LOG int($mtime) . "\t-1\t\n";
}
return $LOG;
}
my $system_is_active = 0;
my $user_is_logged_in = 1;
my $log_file = get_logfilename();
my $LOG = open_logfile($log_file);
my $front_app = '';
sub finish_logger{
$LOG->close;
unlink("$log_file.lock");
exit;
}
$SIG{TERM} = \&finish_logger;
my $loop_timestamp = time;
my $last_logged = time;
while (1){
my $new_logfile_name = get_logfilename();
# start a new log file if we're passing to a new month
if ($new_logfile_name ne $log_file){
$LOG->close;
unlink("$log_file.lock");
$log_file = $new_logfile_name;
$LOG = open_logfile($log_file);
}
open(IOREG, 'ioreg -c IOHIDSystem|') or die("Can't read ioreg\n");
my $idle = 0.0;
while (<IOREG>){
if (/Idle.* ([0-9]+)$/){
$idle=$1 / 1e9; # idle time in seconds
last;
}
}
close(IOREG);
my $switched = 0;
my $now = time;
my $tz = strftime("%Z", localtime());
if ($now - $loop_timestamp > 2*SLEEP_TIME){
# computer must have just woken up from sleep mode (loop was paused)
print $LOG int($loop_timestamp + 1) . "\t-1\t\n";
$system_is_active = 0;
}
my $user = `stat -f%Su /dev/console`;
$user =~ s/^.* //;
$user =~ s/\s*$//;
if ($user ne $monitor_user){
if ($user_is_logged_in){
print $LOG int($now) . "\t$tz\t-1\t\n";
$last_logged = $now;
}
$user_is_logged_in = 0;
} else {
$user_is_logged_in = 1;
}
if ($user_is_logged_in){
if ($idle > IDLE_TIMEOUT){
if ($system_is_active){
# switch from active to idle
$switched = 1;
$system_is_active = 0;
print $LOG int($now - $idle) . "\t$tz\t0\t\n";
$last_logged = $now;
} elsif ($now - $last_logged > MAX_LOG_DELTA) {
# we were idle before and are still idle now, but we should put
# something in the log file just to keep it fresh
print $LOG int($now) . "\t$tz\t0\t\n";
$last_logged = $now;
}
} elsif ( ($idle <= IDLE_TIMEOUT) and not $system_is_active ) {
# switch from idle to active
$switched = 1;
$system_is_active = 1;
}
if ($system_is_active){
my $cur_front_app = `osascript -e 'tell application "System Events"' -e 'set frontApp to name of first application process whose frontmost is true' -e 'end tell'`;
$cur_front_app =~ s/\s*$//;
if (($cur_front_app ne $front_app) or ($switched)
or ($now - $last_logged > MAX_LOG_DELTA)){
$front_app = $cur_front_app;
print $LOG int($now - $idle - 1) . "\t$tz\t1\t".$front_app."\n";
$last_logged = $now;
}
}
} else {
# Even if the user is not actively logged in, we should keep the log
# file fresh
if ($now - $last_logged > MAX_LOG_DELTA){
print $LOG int($now) . "\t$tz\t-1\t\n";
$last_logged = $now;
}
}
$loop_timestamp = $now;
sleep SLEEP_TIME;
}