@@ -6,13 +6,16 @@ use warnings;
66use Getopt::Long;
77use Time::Local;
88use Time::Piece;
9+ use JSON::Tiny qw( encode_json decode_json) ;
10+ $JSON::Tiny::TRUE = 1;
11+ $JSON::Tiny::FALSE = 0;
912
1013use Helios::ObjectDriver;
1114use Helios::LogEntry::Levels ' :all' ;
1215use Helios::JobType;
1316use HeliosX::Logger::HiRes::LogEntry;
1417
15- our $VERSION = ' 0.10_2751 ' ;
18+ our $VERSION = ' 0.10_3270 ' ;
1619
1720our @LOG_PRIORITIES = qw( EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG) ;
1821our %LOG_PRIORITY_MAP = (
@@ -28,14 +31,16 @@ our %LOG_PRIORITY_MAP = (
2831our $LIMIT_DEFAULT = 50;
2932
3033our ($OPT_START_DATE , $OPT_END_DATE , $OPT_HOSTNAME , $OPT_PID , $OPT_JOBID ,
31- $OPT_JOBTYPE , $OPT_SERVICE , $ OPT_PRIORITY , $OPT_MESSAGE , $OPT_LIMIT ,
32- $OPT_SORT , $OPT_TAIL , $OPT_FOLLOW );
34+ $OPT_JOBTYPE , $OPT_SERVICE , @ OPT_PRIORITY , $OPT_MESSAGE , $OPT_LIMIT ,
35+ $OPT_SORT , $OPT_TAIL , $OPT_FOLLOW , $OPT_OUTPUT_FORMAT );
3336our ($OPT_HELP , $OPT_VERSION , $OPT_DEBUG );
3437
35- our $DEBUG_MODE = 0;
36- our $FOLLOW_MODE = 0;
37- our $TAIL_MODE = 0;
38- our $LAST_LOGID = 0;
38+ our $DEBUG_MODE = 0;
39+ our $FOLLOW_MODE = 0;
40+ our $TAIL_MODE = 0;
41+ our $LAST_LOGID = 0;
42+ our $OUTPUT_FORMAT = ' log' ;
43+ our $OUTPUT_SEPARATOR = ' ' ;
3944
4045GetOptions(
4146 " start-date=s" => \$OPT_START_DATE ,
@@ -47,13 +52,15 @@ GetOptions(
4752 " jobtype=s" => \$OPT_JOBTYPE ,
4853 " service=s" => \$OPT_SERVICE ,
4954 " message=s" => \$OPT_MESSAGE ,
50- " priority=s" => \$ OPT_PRIORITY ,
55+ " priority=s" => \@ OPT_PRIORITY ,
5156
5257 " n|lines|limit=i" => \$OPT_LIMIT ,
5358 " sort=s" => \$OPT_SORT ,
5459 " tail" => \$OPT_TAIL ,
5560 " follow" => \$OPT_FOLLOW ,
5661
62+ " output-format=s" => \$OPT_OUTPUT_FORMAT ,
63+
5764 " help" => \$OPT_HELP ,
5865 " version" => \$OPT_VERSION ,
5966 " debug" => \$OPT_DEBUG ,
@@ -94,45 +101,89 @@ if ($OPT_PID) {
94101}
95102
96103if ($OPT_JOBID ) {
97- $search_opts {jobid } = $OPT_JOBID ;
104+ if ($OPT_JOBID !~ / \D / ) {
105+ $search_opts {jobid } = $OPT_JOBID ;
106+ } else {
107+ print STDERR " ERROR: Not a valid jobid: " ,$OPT_JOBID ," \n " ;
108+ exit (1);
109+ }
98110}
99111
100112if ($OPT_HOSTNAME ) {
101- $search_opts {host } = $OPT_HOSTNAME ;
113+ if ( length ($OPT_HOSTNAME ) < 256 ) {
114+ $search_opts {host } = $OPT_HOSTNAME ;
115+ } else {
116+ print STDERR " ERROR: Not a valid hostname: " , $OPT_HOSTNAME ," \n " ;
117+ exit (1);
118+ }
102119}
103120
104121if ($OPT_SERVICE ) {
105- $search_opts {service } = $OPT_SERVICE ;
122+ if ($OPT_SERVICE =~ / ^[A-Za-z]([A-Za-z0-9_\- ]|:{2})*[A-Za-z0-9_\- ]$ / ) {
123+ $search_opts {service } = $OPT_SERVICE ;
124+ } else {
125+ print STDERR " ERROR: Not a valid service name: " ,$OPT_SERVICE ," \n " ;
126+ exit (1);
127+ }
106128}
107129
108130if ($OPT_JOBTYPE ) {
109- my $jt = Helios::JobType-> lookup(name => $OPT_JOBTYPE );
110- $search_opts {jobtypeid } = $jt -> getJobtypeid();
131+ eval {
132+ if (length ($OPT_JOBTYPE ) > 255) { die (" Jobtype too long." ); }
133+ my $jt = Helios::JobType-> lookup(name => $OPT_JOBTYPE );
134+ if (!defined ($jt )) { die (" Jobtype not found." ); }
135+ $search_opts {jobtypeid } = $jt -> getJobtypeid();
136+ 1;
137+ } or do {
138+ print STDERR " ERROR: Not a valid jobtype: " , $OPT_JOBTYPE ," \n " ;
139+ exit (1);
140+ };
111141}
112142
113- if ($OPT_PRIORITY ) {
114- my $p = uc ($OPT_PRIORITY );
115- if ( defined $LOG_PRIORITY_MAP {$p } ) {
116- $search_opts {priority } = $LOG_PRIORITY_MAP {$p };
117-
118- }
143+ if ( scalar @OPT_PRIORITY ) {
144+ my @p = split (/ ,/ , join (' ,' => @OPT_PRIORITY ) );
145+ if (scalar @p == 1) {
146+ if ( defined $LOG_PRIORITY_MAP {$p [0]} ) {
147+ $search_opts {priority } = $LOG_PRIORITY_MAP {$p [0]};
148+ } else {
149+ print STDERR " ERROR: Not a valid priority: " ,$p [0]," \n " ;
150+ exit (1);
151+ }
152+ } elsif ( scalar @p > 1) {
153+ my @p_opts ;
154+ foreach my $p (@p ) {
155+ $p = uc ($p );
156+ if ( defined $LOG_PRIORITY_MAP {$p } ) {
157+ push (@p_opts , $LOG_PRIORITY_MAP {$p });
158+ } else {
159+ print STDERR " ERROR: Not a valid priority: " ,$p ," \n " ;
160+ exit (1);
161+ }
162+ }
163+ $search_opts {priority } = \@p_opts ;
164+ } else {
165+ print STDERR " ERROR: Not a valid priority: " ,join (' ,' => @OPT_PRIORITY )," \n " ;
166+ exit (1);
167+ }
119168}
120169
170+ # set the default limit NOW, before we process the date and
171+ # other options that can modify the limit
121172my $limit = $LIMIT_DEFAULT ;
122173
123174if ($OPT_START_DATE || $OPT_END_DATE ) {
124175 my $sd_epoch = ' ' ;
125176 my $ed_epoch = ' ' ;
126177
127- if ($OPT_START_DATE ) {
178+ if ($OPT_START_DATE && $OPT_START_DATE =~ / ^ \d {4}- \d {2}- \d {2}[T ] \d {2}: \d {2}: \d {2} $ / ) {
128179 # convert Ts and Zs to spaces
129180 my ($sd , $st ) = split (/ [ T]/ , $OPT_START_DATE );
130181 my ($yyyy , $mm , $dd ) = split (' -' , $sd );
131182 my ($hh24 , $mi , $ss ) = split (' :' , $st );
132183 $sd_epoch = timelocal($ss , $mi , $hh24 , $dd , $mm - 1, $yyyy );
133184 }
134185
135- if ($OPT_END_DATE ) {
186+ if ($OPT_END_DATE && $OPT_END_DATE =~ / ^ \d {4}- \d {2}- \d {2}[T ] \d {2}: \d {2}: \d {2} $ / ) {
136187 # convert Ts and Zs to spaces
137188 my ($ed , $et ) = split (/ [ T]/ , $OPT_END_DATE );
138189 my ($yyyy , $mm , $dd ) = split (' -' , $ed );
@@ -155,9 +206,15 @@ if ($OPT_START_DATE || $OPT_END_DATE) {
155206
156207}
157208
158-
209+ # handle -n/--limit/--lines
159210if ($OPT_LIMIT ) {
160- $limit = $OPT_LIMIT ;
211+ if ($OPT_LIMIT !~ / \D / ) {
212+ $limit = $OPT_LIMIT ;
213+ } else {
214+ print STDERR " ERROR: Not a valid limit: " ,$OPT_LIMIT ," \n " ;
215+ exit (1);
216+ }
217+
161218}
162219
163220# Follow Mode
@@ -173,16 +230,43 @@ if ($FOLLOW_MODE) {
173230 }
174231}
175232
233+ # output format switches
234+ if ($OPT_OUTPUT_FORMAT ) {
235+ my $fmt = uc ($OPT_OUTPUT_FORMAT );
236+ SWITCH : {
237+ if ($fmt eq ' PIPE' ) {
238+ $OUTPUT_FORMAT = ' pipe' ;
239+ $OUTPUT_SEPARATOR = ' |' ;
240+ last ;
241+ }
242+ if ($fmt eq ' TAB' ) {
243+ $OUTPUT_FORMAT = ' tab' ;
244+ $OUTPUT_SEPARATOR = " \t " ;
245+ last ;
246+ }
247+ if ($fmt eq ' JSON' ) {
248+ $OUTPUT_FORMAT = ' json' ;
249+ last ;
250+ }
251+ # default
252+ print STDERR " ERROR: Not a valid output format: " ,$OPT_OUTPUT_FORMAT ," \n " ;
253+ exit (1);
254+ }
255+ if ($FOLLOW_MODE ) {
256+ print STDERR " ERROR: --follow will not work with --output-format=" ,$OPT_OUTPUT_FORMAT ," \n " ;
257+ exit (1);
258+ }
259+
260+ }
176261
177- # [] t
262+ # []t
178263if ($DEBUG_MODE ) {
179264 print " SEARCH OPTIONS:\n " ;
180265 foreach my $opt (sort keys %search_opts ) {
181- print $opt ,' => ' ,$search_opts {opt }," \n " ;
266+ print $opt ,' => ' ,$search_opts {$ opt }," \n " ;
182267 }
183268}
184269
185-
186270eval {
187271 my $drvr = Helios::ObjectDriver-> getDriver();
188272 my @logs = $drvr -> search(' HeliosX::Logger::HiRes::LogEntry' =>
@@ -194,19 +278,51 @@ eval {
194278 @logs = reverse @logs ;
195279 }
196280
281+ # we have results; get them to the user
197282 foreach ( @logs ) {
283+ # fix up some of the info to make it presentable
198284 my $tp = localtime $_ -> log_time;
199285 my ($sec , $fract ) = split (/ \. / , $_ -> log_time);
200286 my $date = $tp -> ymd.' ' .$tp -> hms.' .' .$fract ;
201287 my $jobinfo = $_ -> jobid ? ' [Jobid ' .$_ -> jobid.' ]' : ' ' ;
202288 $LAST_LOGID = $_ -> logid;
203- print $_ -> logid.' ' if $DEBUG_MODE ; # []t
204- print ' [' ,$date ,' ] ' ,$_ -> host,' ' ,$_ -> service,' [' ,$_ -> pid,' ]: ' ,$LOG_PRIORITIES [$_ -> priority],$jobinfo ,' ' ,$_ -> message," \n " ;
205- }
206-
289+
290+ # output the log message in the format the user asked for
291+ SWITCH: {
292+
293+ # output: JSON
294+ if ($OUTPUT_FORMAT eq ' json' ) {
295+
296+ my $log_struct = {
297+ logid => $_ -> logid,
298+ logdate => $date ,
299+ host => $_ -> host,
300+ service => $_ -> service,
301+ pid => $_ -> pid,
302+ priority => $LOG_PRIORITIES [$_ -> priority],
303+ jobid => $_ -> jobid,
304+ message => $_ -> message,
305+ };
306+ print encode_json($log_struct )," \n " ;
307+ last ;
308+ }
309+
310+ # output: delimited values
311+ if ($OUTPUT_FORMAT eq ' tab' || $OUTPUT_FORMAT eq ' pipe' ) {
312+ print $_ -> logid.$OUTPUT_SEPARATOR if $DEBUG_MODE ;
313+ print join ($OUTPUT_SEPARATOR => ($date , $_ -> host, $_ -> service, $_ -> pid, $LOG_PRIORITIES [$_ -> priority], $_ -> jobid ? $_ -> jobid : ' ' , $_ -> message)), " \n " ;
314+ last ;
315+ }
316+
317+ # default output: log
318+ print $_ -> logid.' ' if $DEBUG_MODE ; # []t
319+ print ' [' ,$date ,' ] ' ,$_ -> host,' ' ,$_ -> service,' [' ,$_ -> pid,' ]: ' ,$LOG_PRIORITIES [$_ -> priority],$jobinfo ,' ' ,$_ -> message," \n " ;
320+
321+ }
322+ }
207323 1;
208324} or do {
209- print STDERR $@ ," \n " ;
325+ print STDERR ' ERROR: ' , $@ ," \n " ;
210326 exit (42);
211327};
212328
@@ -230,10 +346,10 @@ if ($FOLLOW_MODE) {
230346 }
231347 1;
232348 } or do {
233- print STDERR $@ , " \n " ;
234- exit (42 );
349+ print STDERR ' ERROR: ' , $@ , " \n " ;
350+ exit (1 );
235351 };
236- sleep 1 ;
352+ sleep 5 ;
237353 }
238354}
239355
@@ -250,7 +366,7 @@ heliosx_logger_hires_search - search the Helios high resolution log
250366 heliosx_logger_hires_search --jobid=12345
251367
252368 # heliosx_logger_hires_search normally displays only the first 50 messages
253- # use the -n option to increase/decrease that limit
369+ # use the -n or --lines option to increase/decrease that limit
254370 heliosx_logger_hires_search --jobid=12345 -n 100
255371
256372 # display the last 10 MyService errors, sorted by most recent first
@@ -267,7 +383,7 @@ heliosx_logger_hires_search - search the Helios high resolution log
267383
268384 # display the last 100 log messages logged by MyService,
269385 # then follow the log and display any new MyService messages
270- heliosx_logger_hires_search --service=MyService -- t -n 100 -f
386+ heliosx_logger_hires_search --service=MyService -t -n 100 -f
271387
272388=head1 DESCRIPTION
273389
@@ -354,7 +470,7 @@ include NOTICE messages logged by the service agent daemon; if you want to
354470limit the messages to those associated with a particular job, use --service
355471with the --jobtype switch.
356472
357- =head2 --priority=priority_name
473+ =head2 --priority=priority_name[,priority_name][,priority_name]...
358474
359475Display only log messages of a given priority. The priority names are:
360476
@@ -378,6 +494,9 @@ Display only log messages of a given priority. The priority names are:
378494
379495=back
380496
497+ To search for log messages of multiple, specific priorities, separate them on
498+ the command line by spaces or specify multiple --priority options.
499+
381500=head1 AUTHOR
382501
383502Andrew Johnson, E<lt> lajandy at cpan dot orgE<gt>
0 commit comments