-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplot-smartctl.pl
More file actions
executable file
·173 lines (135 loc) · 4.67 KB
/
plot-smartctl.pl
File metadata and controls
executable file
·173 lines (135 loc) · 4.67 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/perl -w
use strict;
use File::Temp ();
#use File::Basename;
use Getopt::Std;
use File::Find;
#use Storable;
#use File::Spec;
#use Data::Dumper;
#local $Data::Dumper::Useqq = 1;
#local $Data::Dumper::Maxdepth = 3;
#local $Data::Dumper::Deepcopy = 1;
my (%opts);
$Getopt::Std::STANDARD_HELP_VERSION = 1;
###### Get command line options
getopts( 't:c:d:p:r:o:k', \%opts );
my $titlecolumn = ($opts{t} || 1); # zero based index
my $datacolumn = ($opts{c} || 3); # zero based index
# if smartctl files are not supplied on the command line...
my $directory = ($opts{d} || "."); # where to look for files
my $pattern = ($opts{p} || ""); # which pattern to look for
#gnuplot parameter
my $gp_res = ($opts{r} || "2560,720"); #where to write to
my $gp_output = ($opts{o} || "/tmp/foo.png"); #where to write to
my $keeptmp = ($opts{k} || 0 ); #keep temporary files
#here we supply the filenames on the comand line
my @smartfiles = @ARGV ;
#if/when that commandline gets too long (64k) we can switch to providing just a pattern and a directory to search.
my @directories=($directory);
if ($pattern) {
# Traverse desired filesystems
print {*STDERR} "running find ...\n";
File::Find::find({wanted => \&wanted}, @directories);
}
sub wanted {
if ($_ =~ m/$pattern/) {
push @smartfiles,$File::Find::name ;
}
return 1;
}
if (scalar @smartfiles == 0) {
print "Please call this script with some data files to work on.\n";
print "E.g. $0 /var/log/smart/*sata*\n";
print "Check out the examples... Read the source... Be nice to your parents.\n";
exit 1;
}
my $timestamp_first;
my $timestamp_last;
my $number_of_attributes;
# extract the column (zero based) from the attributes table
sub get_smart_attributes_column {
my $filename = shift;
my $column = shift;
my @ret;
open my $fh, '<', $filename or warn "Can't open '$filename': $!";
while (my $line = <$fh>) { last if $line =~ m/^ID# ATTRIBUTE_NAME/; }
while (<$fh>) {
last if $_ =~ m/^$/;
my @a=split;
push @ret,$a[$column];
}
close $fh;
return @ret;
}
sub prepare_gnuplot_file {
my $in = shift;
my $gpdata = <<"END";
##### prepare gnuplot
set terminal png size $gp_res
set xdata time
set timefmt "%Y-%m-%dT%H:%M:%S"
set format x "%Y-%m-%d\\n%H:%M:%S"
# time range must be in same format as data file
set xrange ["$timestamp_first":"$timestamp_last"]
set output "$gp_output"
# uncomment only one of the next two lines
#set logscale y 10
set yrange [0:]
set grid
set xlabel "Date\\nTime"
set ylabel "Value"
set title "Smart Attributes"
set key left box
set multiplot
plot for [i=2:$number_of_attributes] '$in' u 1:i w lp title columnheader(i)
END
my ($tempgpfh, $tempgpfn) = File::Temp::tempfile();
print {$tempgpfh} $gpdata;
close $tempgpfh;
return $tempgpfn;
}
#print Dumper(@smartfiles);
my ($tempdatafh, $tempdatafn) = File::Temp::tempfile();
##### get titles/headers from first file
print {$tempdatafh} "DateTime"."\t".join("\t",get_smart_attributes_column($smartfiles[0],$titlecolumn))."\n";
##### get data from all files
print {*STDERR} "Found ".scalar @smartfiles." candidate files.\n";
for my $file (sort @smartfiles) {
die "$file doesn't exist or it's not a file!\n" unless -f $file;
my $timestamp;
## by smartctl-a files carry an "date --iso-8601=seconds" timestamp in the filename
## but since gnuplot doesn't know about timezomes, we drop that
if ( $file =~ m/(\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d)[-+]\d\d\d\d$/ ) {
$timestamp = $1;
} else {
warn "Filename $file does not contain expected timestamp! Skipping file.\n";
next;
}
# keep track of timestamps
if (not defined $timestamp_first) {
$timestamp_first = $timestamp;
}
$timestamp_last = $timestamp;
my @attributes = get_smart_attributes_column($file,$datacolumn);
if (scalar @attributes <= 0) {
warn "Skipping $file. No smart attributes found.\n";
next;
}
#small check until this ist switched from an array to a hash
if (not defined $number_of_attributes) {
$number_of_attributes = scalar @attributes;
} elsif ( $number_of_attributes != scalar @attributes ) {
warn "Different number of attributes in file $file (".scalar @attributes." instead of $number_of_attributes). Skipping file.\n";
next;
}
print {$tempdatafh} $timestamp."\t".join("\t", @attributes)."\n";
}
close $tempdatafh;
my $tempgpfn = prepare_gnuplot_file($tempdatafn);
system ("gnuplot", $tempgpfn);
if ($keeptmp) {
print "Kept temporary data file in $tempdatafn and gnuplot file in $tempgpfn\n";
} else {
unlink ($tempdatafn, $tempgpfn) or warn "Could not unlink $tempdatafn or $tempgpfn: $!";
}