2 * Copyright (c) Zmanda, Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 %module "Amanda::Logfile"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
29 #include "diskfile.h" /* for the gross hack, below */
35 Amanda::Logfile - manage Amanda trace logs
39 use Amanda::Logfile qw(:logtype_t); # XXX change
40 use Amanda::Config qw( :getconf config_dir_relative );
42 for my $logfile (Amanda::Logfile::find_log()) {
43 $logfile = config_dir_relative(getconf($CNF_LOGDIR)) . "/" . $logfile;
45 my $hdl = Amanda::Logfile::open_logfile($logfile);
46 while (my ($type, $prog, $str) = Amanda::Logfile::get_logline($hdl)) {
47 if ($type == $L_INFO) {
48 my $pname = Amanda::Logfile::program_t_to_string($prog);
49 print "Found info line from $pname: $str\n";
52 Amanda::Logfile::close_logfile($log);
54 my @dumps = Amanda::Logfile::search_logfile("TapeLabel-001", "19780615", $logfile);
56 my @matching = Amanda::Logfile::dumps_match([@dumps], "myhost", "/usr", undef, undef, 0);
57 for my $dump (@matching) {
58 print "$dump->{'label'}:$dump->{'filenum'} = $dump->{'hostname'}:$dump->{'disk'}\n";
66 =head1 RAW LOGFILE ACCESS
68 This section corresponds to the C C<logfile> module.
70 Raw access to logfiles is accomplished by opening a logfile and
71 fetching log lines one by one via the C<get_logline> function.
73 A log line is represented by a list C<($type, $prog, $string)>
74 where C<$type> is one of the C<L_*> constants (available in export
75 tag C<logtype_t>), C<$prog> is one of the C<P_*> constants (available
76 in export tag C<program_t>), and C<$str> is the remainder of the line.
78 Both families of constants can be converted to symbolic names with
79 C<logtype_t_to_string> and C<program_t_to_string>, respectively.
85 =item C<open_logfile($filename)>
87 Opens a logfile for reading, returning an opaque log file handle.
89 =item C<close_logfile($handle)>
91 Closes a log file handle.
93 =item C<get_logline($handle)>
95 Return a list as described above representing the next log line in
96 C<$handle>, or nothing at the end of the logfile.
100 All of these functions can be imported by name if desired.
102 =head1 Amanda::Find::find_result_t objects
104 These objects contain information about dumps, as read from logfiles.
105 Instance variables are:
127 =head1 HIGHER-LEVEL FUNCTIONS
129 Functions in this section extract information from logfiles.
135 Return a list of logfiles for active tapes. The tapelist must be loaded before
136 this function is called (see L<Amanda::Tapelist>).
138 =item C<search_logfile($label, $datestamp, $logfile, $add_missing_disks)>
140 Return all results in C<$logfile> matching C<$label> and C<$datestamp>.
141 If C<$add_missing_disks> is true, then any disks in the logfile
142 not present in the disklist are added to the disklist; otherwise,
143 such dumps are skipped.
145 =item C<dumps_match([@results], $hostname, $diskname, $datestamp, $level, $ok)>
147 Return a filtered version of C<@results> containing only results that match the
148 given expressions. If C<$ok> is true, don't match partial results. Note that
149 C<$level> is given as a string, since it is a match expression.
151 All of these functions can be imported by name.
157 open_logfile get_logline close_logfile
161 amglue_add_enum_tag_fns(logtype_t);
162 amglue_add_constant(L_BOGUS, logtype_t);
163 amglue_add_constant(L_FATAL, logtype_t);
164 amglue_add_constant(L_ERROR, logtype_t);
165 amglue_add_constant(L_WARNING, logtype_t);
166 amglue_add_constant(L_INFO, logtype_t);
167 amglue_add_constant(L_SUMMARY, logtype_t);
168 amglue_add_constant(L_START, logtype_t);
169 amglue_add_constant(L_FINISH, logtype_t);
170 amglue_add_constant(L_DISK, logtype_t);
171 amglue_add_constant(L_DONE, logtype_t);
172 amglue_add_constant(L_PART, logtype_t);
173 amglue_add_constant(L_PARTPARTIAL, logtype_t);
174 amglue_add_constant(L_SUCCESS, logtype_t);
175 amglue_add_constant(L_PARTIAL, logtype_t);
176 amglue_add_constant(L_FAIL, logtype_t);
177 amglue_add_constant(L_STRANGE, logtype_t);
178 amglue_add_constant(L_CHUNK, logtype_t);
179 amglue_add_constant(L_CHUNKSUCCESS, logtype_t);
180 amglue_add_constant(L_STATS, logtype_t);
181 amglue_add_constant(L_MARKER, logtype_t);
182 amglue_add_constant(L_CONT, logtype_t);
184 amglue_add_enum_tag_fns(program_t);
185 amglue_add_constant(P_UNKNOWN, program_t);
186 amglue_add_constant(P_PLANNER, program_t);
187 amglue_add_constant(P_DRIVER, program_t);
188 amglue_add_constant(P_REPORTER, program_t);
189 amglue_add_constant(P_DUMPER, program_t);
190 amglue_add_constant(P_CHUNKER, program_t);
191 amglue_add_constant(P_TAPER, program_t);
192 amglue_add_constant(P_AMFLUSH, program_t);
194 /* TODO: support for writing logfiles is omitted for the moment. */
197 /* open_ and close_logfile are both simple wrappers around fopen/fclose. */
198 typedef FILE loghandle;
200 loghandle *open_logfile(char *filename) {
201 return fopen(filename, "r");
206 void close_logfile(loghandle *logfile) {
207 if (logfile) fclose(logfile);
211 /* We fake the return type of get_logline, and use a typemap to
212 * slurp curstr, curprog, and curlog into a return value. */
214 typedef int LOGLINE_RETURN;
216 %typemap(out) LOGLINE_RETURN {
219 $result = sv_2mortal(newSViv(curlog));
221 $result = sv_2mortal(newSViv(curprog));
223 $result = sv_2mortal(newSVpv(curstr, 0));
226 /* otherwise (end of logfile) return an empty list */
228 LOGLINE_RETURN get_logline(FILE *logfile);
234 find_result_t *selfp = self;
235 free_find_result(&selfp);
251 /* This typemap is used in a few functions. It converts a linked list of find_result_t's
252 * into an array of same, de-linking the list in the process. This gives ownership of the
253 * objects to perl, which is consistent with the C interface to this module.
255 %typemap(out) find_result_t * {
259 /* measure the list and make room on the perl stack */
260 for (len=0, iter=$1; iter; iter=iter->next) len++;
266 /* Let SWIG take ownership of the object */
267 $result = SWIG_NewPointerObj(iter, $descriptor(find_result_t *), SWIG_OWNER | SWIG_SHADOW);
270 /* null out the 'next' field */
277 /* Similarly, on input we link an array full of find_result_t's. The list is then
278 * unlinked on return. Note that the array is supplied as an arrayref (since it's
279 * usually the first argument).
281 %typemap(in) find_result_t * {
284 find_result_t *head = NULL, *tail = NULL;
286 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
287 SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
290 av = (AV *)SvRV($input);
291 len = av_len(av) + 1;
293 for (i = 0; i < len; i++) {
294 SV **val = av_fetch(av, i, 0);
297 if (!val || SWIG_ConvertPtr(*val, (void **)&r, $descriptor(find_result_t *), 0) == -1) {
298 SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
311 /* point to the head of that list */
315 %typemap(freearg) find_result_t * {
316 find_result_t *iter = $1, *next;
318 /* undo all the links we added earlier */
326 %typemap(out) char ** {
330 /* measure the length of the array and make sure perl has enough room */
331 for (len=0, iter=$1; *iter; iter++) len++;
334 /* now copy it to the perl stack */
335 for (i=0, iter=$1; *iter; iter++, i++) {
336 $result = sv_2mortal(newSVpv(*iter, 0));
342 find_log search_logfile dumps_match
345 char **find_log(void);
347 %rename(search_logfile) search_logfile_wrap;
349 find_result_t *search_logfile_wrap(char *label, char *datestamp,
350 char *logfile, int add_missing_disks) {
351 find_result_t *rv = NULL;
353 /* We use a static variable to collect any unrecognized disks */
354 static disklist_t unrecognized_disks = { NULL, NULL };
356 search_logfile(&rv, label, datestamp, logfile,
357 add_missing_disks? &unrecognized_disks : NULL);
363 find_result_t *dumps_match(find_result_t *output_find, char *hostname,
364 char *diskname, char *datestamp, char *level, int ok);