File Coverage

blib/lib/BGPmon/Log.pm
Criterion Covered Total %
statement 475 495 95.9
branch 74 82 90.2
condition 14 21 66.6
subroutine 111 111 100.0
pod 5 5 100.0
total 679 714 95.1


line stmt bran cond sub pod time code
1             package BGPmon::Log;
2             our $VERSION = '2.0';
3              
4 1     1   83069 use 5.14.0;
  1         5  
  1         132  
5 1     1   6 use strict;
  1         1  
  1         32  
6 1     1   6 use warnings;
  1         2  
  1         38  
7 1     1   5 use Carp;
  1         2  
  1         66  
8 1     1   7 use Sys::Syslog; # for writing to syslog
  1         2  
  1         72  
9 1     1   6 use POSIX; # for date/time parsing with strftime
  1         2  
  1         8  
10 1     1   3121 use Sys::Hostname; # to get the hostname
  1         2  
  1         206  
11              
12             require Exporter;
13             our %EXPORT_TAGS = ( "all" => [ qw(log_init log_close
14             log_emerg log_emergency log_alert
15             log_fatal log_crit log_critical
16             log_err log_error
17             log_warn log_warning log_notice log_info
18             log_debug debug get_error_code
19             get_error_message get_error_msg) ] );
20             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
21             our @ISA = qw(Exporter);
22              
23             # ----- The Different Logging levels and their matching functions ---
24 1     1   6 use constant LOG_EMERG => 0; # log_emerg
  1         1  
  1         75  
25 1     1   4 use constant LOG_EMERGENCY => 0; # log_emergency
  1         2  
  1         41  
26 1     1   12 use constant LOG_ALERT => 1; # log_alert
  1         2  
  1         44  
27 1     1   4 use constant LOG_FATAL => 2; # log_fatal
  1         2  
  1         37  
28 1     1   5 use constant LOG_CRIT => 2; # log_crit
  1         1  
  1         51  
29 1     1   5 use constant LOG_CRITICAL => 2; # log_critical
  1         2  
  1         66  
30 1     1   5 use constant LOG_ERR => 3; # log_err
  1         2  
  1         129  
31 1     1   6 use constant LOG_ERROR => 3; # log_error
  1         11  
  1         51  
32 1     1   5 use constant LOG_WARNING => 4; # log_warning
  1         2  
  1         41  
33 1     1   6 use constant LOG_WARN => 4; # log_warn
  1         2  
  1         46  
34 1     1   5 use constant LOG_NOTICE => 5; # log_notice
  1         2  
  1         40  
35 1     1   5 use constant LOG_INFO => 6; # log_info
  1         1  
  1         52  
36 1     1   4 use constant LOG_DEBUG => 7; # log_debug
  1         2  
  1         130  
37              
38             # ----- The Different Logging facilities ---
39             # we simply repeat the syslog module settings
40 1     1   16 use constant LOG_KERN => Sys::Syslog::LOG_KERN;
  1         2  
  1         51  
41 1     1   5 use constant LOG_USER => Sys::Syslog::LOG_USER;
  1         2  
  1         54  
42 1     1   5 use constant LOG_MAIL => Sys::Syslog::LOG_MAIL;
  1         2  
  1         46  
43 1     1   5 use constant LOG_DAEMON => Sys::Syslog::LOG_DAEMON;
  1         1  
  1         54  
44 1     1   6 use constant LOG_SECURITY => Sys::Syslog::LOG_SECURITY;
  1         1  
  1         59  
45 1     1   6 use constant LOG_SYSLOG => Sys::Syslog::LOG_SYSLOG;
  1         2  
  1         60  
46 1     1   5 use constant LOG_LPR => Sys::Syslog::LOG_LPR;
  1         2  
  1         47  
47 1     1   6 use constant LOG_NEWS => Sys::Syslog::LOG_NEWS;
  1         2  
  1         55  
48 1     1   5 use constant LOG_UUCP => Sys::Syslog::LOG_UUCP;
  1         2  
  1         130  
49 1     1   5 use constant LOG_AUTH => Sys::Syslog::LOG_AUTH;
  1         2  
  1         54  
50 1     1   5 use constant LOG_AUTHPRIV => Sys::Syslog::LOG_AUTHPRIV;
  1         20  
  1         44  
51 1     1   5 use constant LOG_FTP => Sys::Syslog::LOG_FTP;
  1         3  
  1         53  
52 1     1   5 use constant LOG_NTP => Sys::Syslog::LOG_NTP;
  1         1  
  1         53  
53 1     1   12 use constant LOG_AUDIT => Sys::Syslog::LOG_AUDIT;
  1         2  
  1         269  
54 1     1   7 use constant LOG_CONSOLE => Sys::Syslog::LOG_CONSOLE;
  1         2  
  1         64  
55 1     1   5 use constant LOG_INSTALL => Sys::Syslog::LOG_INSTALL;
  1         2  
  1         66  
56 1     1   6 use constant LOG_LAUNCHD => Sys::Syslog::LOG_LAUNCHD;
  1         1  
  1         57  
57 1     1   5 use constant LOG_LFMT => Sys::Syslog::LOG_LFMT;
  1         2  
  1         63  
58 1     1   6 use constant LOG_NETINFO => Sys::Syslog::LOG_NETINFO;
  1         2  
  1         50  
59 1     1   5 use constant LOG_RAS => Sys::Syslog::LOG_RAS;
  1         2  
  1         148  
60 1     1   6 use constant LOG_REMOTEAUTH => Sys::Syslog::LOG_REMOTEAUTH;
  1         1  
  1         63  
61 1     1   7 use constant LOG_CRON => Sys::Syslog::LOG_CRON;
  1         1  
  1         49  
62 1     1   6 use constant LOG_LOCAL0 => Sys::Syslog::LOG_LOCAL0;
  1         1  
  1         56  
63 1     1   4 use constant LOG_LOCAL1 => Sys::Syslog::LOG_LOCAL1;
  1         2  
  1         53  
64 1     1   5 use constant LOG_LOCAL2 => Sys::Syslog::LOG_LOCAL2;
  1         1  
  1         63  
65 1     1   6 use constant LOG_LOCAL3 => Sys::Syslog::LOG_LOCAL3;
  1         4  
  1         52  
66 1     1   5 use constant LOG_LOCAL4 => Sys::Syslog::LOG_LOCAL4;
  1         1  
  1         147  
67 1     1   6 use constant LOG_LOCAL5 => Sys::Syslog::LOG_LOCAL5;
  1         1  
  1         54  
68 1     1   5 use constant LOG_LOCAL6 => Sys::Syslog::LOG_LOCAL6;
  1         2  
  1         57  
69 1     1   5 use constant LOG_LOCAL7 => Sys::Syslog::LOG_LOCAL7;
  1         1  
  1         46  
70              
71             # ----- The default log settings ---
72 1     1   4 use constant DEFAULT_LOG_LEVEL => LOG_WARNING;
  1         8  
  1         45  
73 1     1   6 use constant DEFAULT_LOG_FACILITY => LOG_LOCAL1;
  1         1  
  1         43  
74 1     1   11 use constant DEFAULT_USE_SYSLOG => 0;
  1         1  
  1         48  
75 1     1   5 use constant DEFAULT_USE_GMT => 1;
  1         1  
  1         107  
76 1     1   6 use constant MAX_STRING_LEN => 256;
  1         2  
  1         81  
77              
78             # --- constants used to indicate error codes and messages---
79 1     1   5 use constant NO_ERROR_CODE => 0;
  1         2  
  1         43  
80 1         47 use constant NO_ERROR_MSG =>
81 1     1   4 'No Error';
  1         2  
82 1     1   5 use constant NO_FUNCTION_SPECIFIED_CODE => 1;
  1         2  
  1         51  
83 1         36 use constant NO_FUNCTION_SPECIFIED_MSG =>
84 1     1   5 'Error reporting function called without specifying the function.';
  1         1  
85 1     1   4 use constant INVALID_FUNCTION_SPECIFIED_CODE => 2;
  1         2  
  1         46  
86 1         49 use constant INVALID_FUNCTION_SPECIFIED_MSG =>
87 1     1   6 'Error reporting function called with invalid function name';
  1         1  
88 1     1   5 use constant LOG_INIT_NO_HOSTNAME_CODE => 3;
  1         2  
  1         38  
89 1         50 use constant LOG_INIT_NO_HOSTNAME_MSG =>
90 1     1   5 'Unable to get the hostname';
  1         72  
91 1     1   4 use constant LOG_INIT_PROG_SIZE_CODE => 4;
  1         2  
  1         51  
92 1         44 use constant LOG_INIT_PROG_SIZE_MSG =>
93 1     1   6 'Program name exceeds maximum length of '.MAX_STRING_LEN;
  1         1  
94 1     1   4 use constant LOG_INIT_PROG_PRINTABLE_CODE => 5;
  1         1  
  1         50  
95 1         35 use constant LOG_INIT_PROG_PRINTABLE_MSG =>
96 1     1   5 'Program name contains non-printable characters';
  1         2  
97 1     1   5 use constant LOG_INIT_LEVEL_NOT_NUM_CODE => 6;
  1         2  
  1         43  
98 1         36 use constant LOG_INIT_LEVEL_NOT_NUM_MSG =>
99 1     1   5 'Log level must be a postive integer';
  1         2  
100 1     1   5 use constant LOG_INIT_LEVEL_RANGE_CODE => 7;
  1         2  
  1         138  
101 1         57 use constant LOG_INIT_LEVEL_RANGE_MSG =>
102 1     1   6 'Log level must be between '.LOG_EMERG.' and '.LOG_DEBUG;
  1         1  
103 1     1   5 use constant LOG_INIT_FACILITY_NOT_NUM_CODE => 8;
  1         2  
  1         38  
104 1         43 use constant LOG_INIT_FACILITY_NOT_NUM_MSG =>
105 1     1   5 'Log facility must be a postive integer';
  1         1  
106 1     1   40 use constant LOG_INIT_FILE_SIZE_CODE => 9;
  1         2  
  1         51  
107 1         40 use constant LOG_INIT_FILE_SIZE_MSG =>
108 1     1   6 'Log file exceeds maximum length of '.MAX_STRING_LEN;
  1         1  
109 1     1   7 use constant LOG_INIT_FILE_PRINTABLE_CODE => 10;
  1         2  
  1         53  
110 1         50 use constant LOG_INIT_FILE_PRINTABLE_MSG =>
111 1     1   4 'Log file contains non-printable characters';
  1         2  
112 1     1   5 use constant LOG_INIT_SYSLOG_NOT_NUM_CODE => 11;
  1         2  
  1         108  
113 1         47 use constant LOG_INIT_SYSLOG_NOT_NUM_MSG =>
114 1     1   5 'use_syslog must be 0 or 1';
  1         1  
115 1     1   4 use constant LOG_INIT_SYSLOG_RANGE_CODE => 12;
  1         2  
  1         44  
116 1         48 use constant LOG_INIT_SYSLOG_RANGE_MSG =>
117 1     1   5 'use_syslog must be 0 or 1';
  1         2  
118 1     1   5 use constant LOG_INIT_GMT_NOT_NUM_CODE => 13;
  1         1  
  1         50  
119 1         34 use constant LOG_INIT_GMT_NOT_NUM_MSG =>
120 1     1   5 'use_syslog must be 0 or 1';
  1         2  
121 1     1   4 use constant LOG_INIT_GMT_RANGE_CODE => 14;
  1         2  
  1         48  
122 1         36 use constant LOG_INIT_GMT_RANGE_MSG =>
123 1     1   5 'use_gmt must be 0 or 1';
  1         1  
124 1     1   4 use constant LOG_INIT_GMT_SYSLOG_CODE => 15;
  1         2  
  1         44  
125 1         139 use constant LOG_INIT_GMT_SYSLOG_MSG =>
126 1     1   5 'use_gmt not allowed when use_syslog = 1';
  1         1  
127 1     1   5 use constant LOG_INIT_SYSLOG_AND_FILE_CODE => 16;
  1         2  
  1         43  
128 1         49 use constant LOG_INIT_SYSLOG_AND_FILE_MSG =>
129 1     1   5 'Unable to both use_syslog and write to a file';
  1         2  
130 1     1   5 use constant LOG_INIT_SYSLOG_OPEN_CODE => 17;
  1         1  
  1         47  
131 1         44 use constant LOG_INIT_SYSLOG_OPEN_MSG =>
132 1     1   4 'Unable to open syslog';
  1         2  
133 1     1   4 use constant LOG_INIT_FILE_OPEN_CODE => 18;
  1         1  
  1         47  
134 1         39 use constant LOG_INIT_FILE_OPEN_MSG =>
135 1     1   5 'Unable to open log file';
  1         1  
136 1     1   5 use constant LOG_NOT_INITIALIZED_CODE => 19;
  1         2  
  1         44  
137 1         36 use constant LOG_NOT_INITIALIZED_MSG =>
138 1     1   4 'Logging not initialized. Use init_log() prior to calling log_*("msg")';
  1         2  
139 1     1   76 use constant LOG_UNKNOWN_FUNCTION_CODE => 20;
  1         2  
  1         71  
140 1         46 use constant LOG_UNKNOWN_FUNCTION_MSG =>
141 1     1   6 'No such log function';
  1         9  
142 1     1   5 use constant LOG_MISSING_MSG_CODE => 21;
  1         2  
  1         50  
143 1         47 use constant LOG_MISSING_MSG_MSG =>
144 1     1   5 'Log function called with no log message';
  1         3  
145 1     1   5 use constant LOG_MSG_SIZE_CODE => 22;
  1         2  
  1         64  
146 1         49 use constant LOG_MSG_SIZE_MSG =>
147 1     1   6 'Log message exceeds maximum length of '.MAX_STRING_LEN;
  1         2  
148 1     1   5 use constant LOG_MSG_PRINTABLE_CODE => 23;
  1         2  
  1         132  
149 1         48 use constant LOG_MSG_PRINTABLE_MSG =>
150 1     1   7 'Message contains non-printable characters';
  1         2  
151 1     1   6 use constant LOG_WRITE_FAILED_CODE => 24;
  1         2  
  1         55  
152 1         3860 use constant LOG_WRITE_FAILED_MSG =>
153 1     1   5 'Unable to write log messsage';
  1         2  
154              
155             # --- error code/message ---
156             my %error_code;
157             my %error_msg;
158             # init the error codes for all functions
159             my @function_names = ("log_init", "log_close",
160             "log_emerg", "log_emergency", "log_alert",
161             "log_fatal", "log_crit", "log_critical", "log_err",
162             "log_error", "log_warn", "log_warning", "log_notice",
163             "log_info", "log_debug", "debug");
164             for my $function_name (@function_names) {
165             $error_code{$function_name} = NO_ERROR_CODE;
166             $error_msg{$function_name} = NO_ERROR_MSG;
167             }
168              
169             # ----- The Different Logging levels and their matching functions ---
170             our %function_level; # maps function names to levels
171             our %function_description; # maps function names to descriptions
172             $function_level{"log_emerg"} = LOG_EMERG;
173             $function_description{"log_emerg"} = "[LOG_EMERG]";
174             $function_level{"log_emergency"} = LOG_EMERGENCY;
175             $function_description{"log_emergency"} = "[LOG_EMERGENCY]";
176             $function_level{"log_alert"} = LOG_ALERT;
177             $function_description{"log_alert"} = "[LOG_ALERT]";
178             $function_level{"log_fatal"} = LOG_FATAL;
179             $function_description{"log_fatal"} = "[LOG_FATAL]";
180             $function_level{"log_crit"} = LOG_CRIT;
181             $function_description{"log_crit"} = "[LOG_CRIT]";
182             $function_level{"log_critical"} = LOG_CRITICAL;
183             $function_description{"log_critical"} = "[LOG_CRITICAL]";
184             $function_level{"log_err"} = LOG_ERR;
185             $function_description{"log_err"} = "[LOG_ERR]";
186             $function_level{"log_error"} = LOG_ERR;
187             $function_description{"log_error"} = "[LOG_ERROR]";
188             $function_level{"log_warning"} = LOG_WARNING;
189             $function_description{"log_warning"} = "[LOG_WARNING]";
190             $function_level{"log_warn"} = LOG_WARN;
191             $function_description{"log_warn"} = "[LOG_WARN]";
192             $function_level{"log_notice"} = LOG_NOTICE;
193             $function_description{"log_notice"} = "[LOG_NOTICE]";
194             $function_level{"log_info"} = LOG_INFO;
195             $function_description{"log_info"} = "[LOG_INFO]";
196             $function_level{"log_debug"} = LOG_INFO;
197             $function_description{"log_debug"} = "[LOG_DEBUG]";
198             $function_level{"debug"} = LOG_INFO;
199             $function_description{"debug"} = "[DEBUG]";
200              
201             # --- User configurable log settings --
202             my $prog_name = $0;
203             my $log_level = DEFAULT_LOG_LEVEL;
204             my $log_facility = DEFAULT_LOG_FACILITY;
205             my $log_file;
206             my $use_syslog = DEFAULT_USE_SYSLOG;
207             my $use_gmt = DEFAULT_USE_GMT;
208              
209             # --- internal state of the log module --
210             my $pid = $$;
211             my $hostname = "not initialized";
212             my $log_initialized = 0;
213             my $use_stderr = 0;
214             my $log_fh;
215              
216             =head1 NAME
217              
218             BGPmon::Log - BGPmon Logging
219              
220             This module implements logging for BGPmon clients. The module can log messages
221             to syslog, STDERR, or a user specified log file. It allows the user to
222             specify a log level and write log messages using different log levels.
223              
224             =cut
225              
226             =head1 SYNOPSIS
227              
228             After initializing the log, the user can log messages at different log levels.
229              
230             use BGPmon::Log qw (debug
231             log_debug
232             log_info
233             log_notice
234             log_warn log_warning
235             log_err log_error
236             log_fatal log_crit log_critical
237             log_alert
238             log_emerg log_emergency
239             );
240              
241             my %log_param = ( prog_name => "my name",
242             log_level => BGPmon::Log::LOG_DEBUG(),
243             log_facility => BGPmon::Log::LOG_LOCAL0(),
244             log_file => "./mylog",
245             use_syslog => 0,
246             use_gmt => 0,
247             );
248              
249             if (BGPmon::Log::log_init(%log_param) ) {
250             my $code = BGPmon::Log::get_error_code("log_init");
251             my $msg = BGPmon::Log::get_error_message("log_init");
252             print STDERR "Error initializing log: $code - $msg\n";
253             exit 1;
254             }
255              
256             debug("Log a message with level BGPmon::Log::LOG_DEBUG");
257              
258             log_debug("Also log a message with level BGPmon::Log::LOG_DEBUG");
259              
260             log_info("Log a message, level BGPmon::Log::LOG_INFO");
261              
262             log_notice("Log a message, level BGPmon::Log::LOG_NOTICE");
263              
264             log_warn("Log a message, level BGPmon::Log::LOG_WARN");
265              
266             log_warning("Log a message, level BGPmon::Log::LOG_WARNING");
267              
268             log_err("Log a message, level BGPmon::Log::LOG_ERR");
269              
270             log_error("Log a message, level BGPmon::Log::LOG_ERROR");
271              
272             log_fatal("Log a message, level BGPmon::Log::LOG_FATAL");
273              
274             log_crit("Log a message, level BGPmon::Log::LOG_CRIT");
275              
276             log_critical("Log a message, level BGPmon::Log::LOG_CRITICAL");
277              
278             log_alert("Log a message, level BGPmon::Log::LOG_ALERT");
279              
280             log_emergency("Log a message, level BGPmon::Log::LOG_EMERGENCY");
281              
282             log_emerg("Log a message, level BGPmon::Log::LOG_EMERG");
283              
284             BGPmon::Log::log_close();
285              
286             =head1 EXPORT
287              
288             log_init
289             log_close
290             log_emerg
291             log_emergency
292             log_alert
293             log_fatal
294             log_crit
295             log_critical
296             log_err
297             log_error
298             log_warn
299             log_warning
300             log_notice
301             log_info
302             log_debug
303             debug
304             get_errror_code
305             get_error_message
306             get_error_msg
307              
308             =head1 SUBROUTINES/METHODS
309              
310             =head2 log_init
311              
312             Initialize the logging facility. This function must be called prior to using
313             any log_* functions.
314              
315             Input : The log settings
316             1. prog_name - The program name
317             2. log_level - the log level
318             3. log_facility - the log facility
319             4. log_file - the file where log messages will be written
320             5. use_syslog - flag indicating whether to use syslog, 1 = use syslog,
321             5. use_gmt - flag indicating whether to GMT for time or use local time,
322             1 = use GMT, use_gmt can only be set when use_syslog = 0
323             Output: returns 0 on success, 1 on error and setserror_message and error_code
324              
325             If use_syslog=1, all log messages are written to syslog.
326             if the user sets both use_syslog=1 and provides a log_file, the log_file
327             is ignored.
328              
329             If use_syslog != 1, log messages are written to the log_file, if provided
330             if no log file is provided to init, all messages are written to STDERR
331              
332             =cut
333             sub log_init {
334 25     25 1 11208 my %args = @_;
335              
336             # set function name for error reporting
337 25         49 my $function_name = $function_names[0];
338              
339             # reset configurable values to their defaults
340 25         53 $prog_name = $0;
341 25         35 $log_level = DEFAULT_LOG_LEVEL;
342 25         36 $log_facility = DEFAULT_LOG_FACILITY;
343 25         32 $use_syslog = DEFAULT_USE_SYSLOG;
344 25         26 $use_gmt = DEFAULT_USE_GMT;
345             # reset the internal log variables
346 25         28 $log_initialized = 0;
347 25         51 $pid = $$;
348 25         75 $hostname = Sys::Hostname::hostname;
349 25 50       603 if (!defined($hostname)) {
350 0         0 $error_code{$function_name} = LOG_INIT_NO_HOSTNAME_CODE;
351 0         0 $error_msg{$function_name} = LOG_INIT_NO_HOSTNAME_MSG;
352 0         0 return 1;
353             }
354 25         32 $log_file = undef;
355 25         31 $use_stderr = 0;
356 25         132 $log_fh = undef;
357              
358             # parse the init arguements and over-ride any defaults
359 25 100       88 if (defined($args{prog_name})) {
360 8 100       85 if ($args{prog_name} =~ /^[[:print:]]*$/) {
361 7 100       27 if (length($args{prog_name}) > MAX_STRING_LEN ) {
362 1         5 $error_code{$function_name} = LOG_INIT_PROG_SIZE_CODE;
363 1         2 $error_msg{$function_name} = LOG_INIT_PROG_SIZE_MSG;
364 1         5 return 1;
365             }
366 6         14 $prog_name = $args{prog_name};
367             } else {
368             # prog_name contains non-printable characters
369 1         3 $error_code{$function_name} = LOG_INIT_PROG_PRINTABLE_CODE;
370 1         3 $error_msg{$function_name} = LOG_INIT_PROG_PRINTABLE_MSG;
371 1         5 return 1;
372             }
373             }
374 23 100       55 if (defined($args{log_level})) {
375             # make sure it is a number
376 9 100       47 if ($args{log_level} =~ /\D/) {
377             # not a number or out of range
378 2         5 $error_code{$function_name} = LOG_INIT_LEVEL_NOT_NUM_CODE;
379 2         4 $error_msg{$function_name} = LOG_INIT_LEVEL_NOT_NUM_MSG;
380 2         7 return 1;
381             }
382             # make sure it is in range
383 7 100 66     53 if ($args{log_level} < LOG_EMERG || $args{log_level} > LOG_DEBUG) {
384 1         3 $error_code{$function_name} = LOG_INIT_LEVEL_RANGE_CODE;
385 1         2 $error_msg{$function_name} = LOG_INIT_LEVEL_RANGE_MSG;
386 1         4 return 1;
387             }
388 6         11 $log_level = $args{log_level};
389             }
390 20 100       44 if (defined($args{log_facility})) {
391             # make sure it is a number
392 8 100       37 if ($args{log_facility} =~ /\D/) {
393             # not a number or out of range
394 2         5 $error_code{$function_name} = LOG_INIT_FACILITY_NOT_NUM_CODE;
395 2         5 $error_msg{$function_name} = LOG_INIT_FACILITY_NOT_NUM_MSG;
396 2         7 return 1;
397             }
398 6         11 $log_facility = $args{log_facility};
399             }
400 18 100       74 if (defined($args{log_file})) {
401 11 100       207 if ($args{log_file} =~ /^[[:print:]]*$/) {
402 10 100       29 if (length($args{log_file}) > MAX_STRING_LEN ) {
403 1         4 $error_code{$function_name} = LOG_INIT_FILE_SIZE_CODE;
404 1         3 $error_msg{$function_name} = LOG_INIT_FILE_SIZE_MSG;
405 1         5 return 1;
406             }
407 9         23 $log_file = $args{log_file};
408             } else {
409             # prog_name contains non-printable characters
410 1         4 $error_code{$function_name} = LOG_INIT_FILE_PRINTABLE_CODE;
411 1         3 $error_msg{$function_name} = LOG_INIT_FILE_PRINTABLE_MSG;
412 1         4 return 1;
413             }
414             }
415 16 100       44 if (defined($args{use_syslog})) {
416             # make sure it is a number
417 10 100       45 if ($args{use_syslog} =~ /\D/) {
418             # not a number or out of range
419 1         3 $error_code{$function_name} = LOG_INIT_SYSLOG_NOT_NUM_CODE;
420 1         3 $error_msg{$function_name} = LOG_INIT_SYSLOG_NOT_NUM_MSG;
421 1         5 return 1;
422             }
423             # make sure it is in range
424 9 100 100     49 if ($args{use_syslog} != 0 && $args{use_syslog} != 1) {
425 1         4 $error_code{$function_name} = LOG_INIT_SYSLOG_RANGE_CODE;
426 1         3 $error_msg{$function_name} = LOG_INIT_SYSLOG_RANGE_MSG;
427 1         4 return 1;
428             }
429 8         20 $use_syslog = $args{use_syslog};
430             }
431 14 100       32 if (defined($args{use_gmt})) {
432             # make sure it is a number
433 8 100       31 if ($args{use_gmt} =~ /\D/) {
434             # not a number or out of range
435 1         3 $error_code{$function_name} = LOG_INIT_GMT_NOT_NUM_CODE;
436 1         3 $error_msg{$function_name} = LOG_INIT_GMT_NOT_NUM_MSG;
437 1         4 return 1;
438             }
439             # make sure it is in range
440 7 100 100     41 if ($args{use_gmt} != 0 && $args{use_gmt} != 1) {
441 1         3 $error_code{$function_name} = LOG_INIT_GMT_RANGE_CODE;
442 1         3 $error_msg{$function_name} = LOG_INIT_GMT_RANGE_MSG;
443 1         11 return 1;
444             }
445 6 100       19 if ($use_syslog == 1) {
446 1         10 $error_code{$function_name} = LOG_INIT_GMT_SYSLOG_CODE;
447 1         3 $error_msg{$function_name} = LOG_INIT_GMT_SYSLOG_MSG;
448 1         4 return 1;
449             }
450 5         22 $use_gmt = $args{use_gmt};
451             }
452              
453             # error if the specified both use_syslog and log to a file
454 11 100 66     44 if (($use_syslog == 1) && (defined($log_file)) ) {
455 2         7 $error_code{$function_name} = LOG_INIT_SYSLOG_AND_FILE_CODE;
456 2         5 $error_msg{$function_name} = LOG_INIT_SYSLOG_AND_FILE_MSG;
457 2         10 return 1;
458             }
459              
460             # open syslog if use_syslog set
461 9 50       22 if ($use_syslog == 1) {
462 0 0       0 if (! Sys::Syslog::openlog($prog_name, "ndelay,pid", $log_facility)) {
463 0         0 $error_code{$function_name} = LOG_INIT_SYSLOG_OPEN_CODE;
464 0         0 $error_msg{$function_name} = LOG_INIT_SYSLOG_OPEN_MSG;
465 0         0 return 1;
466             }
467 0         0 $log_initialized = 1;
468 0         0 $error_code{$function_name} = NO_ERROR_CODE;
469 0         0 $error_msg{$function_name} = NO_ERROR_MSG;
470 0         0 return 0;
471             }
472              
473             # open file if file was provided
474 9 100       25 if (defined($log_file)) {
475 7 100       613 if (! open($log_fh, ">>$log_file") ) {
476 1         3 $error_code{$function_name} = LOG_INIT_FILE_OPEN_CODE;
477 1         3 $error_msg{$function_name} = LOG_INIT_FILE_OPEN_MSG;
478 1         4 return 1;
479             }
480 6         14 $log_initialized = 1;
481 6         17 $error_code{$function_name} = NO_ERROR_CODE;
482 6         12 $error_msg{$function_name} = NO_ERROR_MSG;
483 6         29 return 0;
484             }
485              
486             # no use_syslog and no log file so write to STDERR
487 2         5 $log_initialized = 1;
488 2         3 $use_stderr = 1;
489 2         6 $log_fh = *STDERR;
490 2         6 $error_code{$function_name} = NO_ERROR_CODE;
491 2         5 $error_msg{$function_name} = NO_ERROR_MSG;
492 2         6 return 0;
493             }
494              
495             =head2 log_close
496              
497             Closes the logfile so no further log messages can be written
498             You must call log_init again to re-enable logging.
499              
500             Typically called at the end of program to cleanly close the log file
501             or cleanly close the connection to syslog.
502              
503             Input: None
504             Output: None
505             =cut
506             sub log_close {
507              
508             # set function name for error reporting
509 9     9 1 10977 my $function_name = $function_names[1];
510              
511             # if already closed, just return
512 9 100       39 if ($log_initialized) {
513              
514             # set initialized back to 0
515 8         17 $log_initialized = 0;
516              
517             # close the log
518 8 50       35 if ($use_syslog) {
    100          
519 0         0 closelog();
520             } elsif (!$use_stderr) {
521 6         126 close($log_fh);
522             }
523             }
524              
525 9         25 $error_code{$function_names[7]} = NO_ERROR_CODE;
526 9         18 $error_msg{$function_names[7]} = NO_ERROR_MSG;
527 9         23 return 0;
528             }
529              
530             =head2 log_emerg
531              
532             Logs an emergency message. Log levels LOG_EMERG
533              
534             Input: Message to be printed.
535             Output: returns 0 on success, 1 on error and sets error_message and error_code
536             =cut
537             # implemented using AUTOLOADER
538              
539             =head2 log_emergency
540              
541             Logs an emergency message. Log levels LOG_EMERGENCY
542              
543             This function is identical to log_emerg
544             =cut
545             # implemented using AUTOLOADER
546              
547             =head2 log_alert
548              
549             Logs an alert message. Log levels LOG_ALERT
550              
551             Input: Message to be printed.
552             Output: returns 0 on success, 1 on error and sets error_message and error_code
553             =cut
554             # implemented using AUTOLOADER
555              
556             =head2 log_fatal
557             Logs a fatal error message. Log levels LOG_CRIT
558              
559             Input: Message to be printed.
560             Output: returns 0 on success, 1 on error and sets error_message and error_code
561             =cut
562             # implemented using AUTOLOADER
563              
564             =head2 log_crit
565             Logs a critical error message. Log levels LOG_CRIT
566              
567             This function is identical to log_fatal
568             =cut
569             # implemented using AUTOLOADER
570              
571             =head2 log_critical
572              
573             Logs a critical error message. Log levels LOG_CRIT
574              
575             This function is identical to log_fatal
576             =cut
577             # implemented using AUTOLOADER
578              
579             =head2 log_err
580              
581             Logs an error message. Log level LOG_ERR.
582             Input: Message to be printed.
583             Output: returns 0 on success, 1 on error and sets error_message and error_code
584             =cut
585             # implemented using AUTOLOADER
586              
587             =head2 log_error
588              
589             Logs an error message. Log level LOG_ERR.
590              
591             This function is identical to log_fatal
592             =cut
593             # implemented using AUTOLOADER
594              
595             =head2 log_warn
596              
597             Logs a warning message. Log level LOG_WARN
598             This function is identical to log_fatal
599             Input: Message to be printed.
600             Output: returns 0 on success, 1 on error and sets error_message and error_code
601             =cut
602             # implemented using AUTOLOADER
603              
604             =head2 log_warning
605              
606             Logs a warning message. Log level LOG_WARNING
607              
608             This function is identical to log_warn
609             =cut
610             # implemented using AUTOLOADER
611              
612             =head2 log_notice
613              
614             Logs a notice message. Log level LOG_NOTICE
615             Input: Message to be printed.
616             Output: returns 0 on success, 1 on error and sets error_message and error_code
617             =cut
618             # implemented using AUTOLOADER
619              
620             =head2 log_info
621              
622             Logs a informational message. Log level LOG_INFO
623             Input: Message to be printed.
624             Output: returns 0 on success, 1 on error and sets error_message and error_code
625             =cut
626             # implemented using AUTOLOADER
627              
628             =head2 log_debug
629              
630             Logs a debug message. Log level LOG_DEBUG
631             Input: Message to be printed.
632             Output: returns 0 on success, 1 on error and sets error_message and error_code
633             =cut
634             # implemented using AUTOLOADER
635              
636             =head2 debug
637              
638             Logs a debug message. Log level LOG_DEBUG
639              
640             This function is identical to log_debug
641             =cut
642             # implemented using AUTOLOADER
643              
644             =head2 get_error_code
645              
646             Get the error code
647             Input : the name of the function whose error code we should report
648             Output: the function's error code
649             or NO_FUNCTION_SPECIFIED if the user did not supply a function
650             or INVALID_FUNCTION_SPECIFIED if the user provided an invalid function
651             =cut
652             sub get_error_code {
653 75     75 1 1639 my $function = shift;
654              
655             # check we got a function name
656 75 100       158 if (!defined($function)) {
657 1         3 return NO_FUNCTION_SPECIFIED_CODE;
658             }
659              
660             # check this is one of our exported function names
661 74 100       155 if (!defined($error_code{$function}) ) {
662 1         4 return INVALID_FUNCTION_SPECIFIED_CODE;
663             }
664              
665 73         97 my $code = $error_code{$function};
666 73         244 return $code;
667             }
668              
669             =head2 get_error_message
670              
671             Get the error message
672             Input : the name of the function whose error message we should report
673             Output: the function's error message
674             or NO_FUNCTION_SPECIFIED if the user did not supply a function
675             or INVALID_FUNCTION_SPECIFIED if the user provided an invalid function
676             =cut
677             sub get_error_message {
678 78     78 1 1512 my $function = shift;
679              
680             # check we got a function name
681 78 100       148 if (!defined($function)) {
682 2         8 return NO_FUNCTION_SPECIFIED_MSG;
683             }
684              
685             # check this is one of our exported function names
686 76 100       162 if (!defined($error_msg{$function}) ) {
687 2         7 return INVALID_FUNCTION_SPECIFIED_MSG;
688             }
689              
690 74         107 my $msg = $error_msg{$function};
691 74         229 return $msg;
692             }
693              
694             =head2 get_error_msg
695              
696             Get the error message
697              
698             This function is identical to get_error_message
699             =cut
700             sub get_error_msg {
701 75     75 1 1781 my $msg = shift;
702 75         338 return get_error_message($msg);
703             }
704              
705             ### ------------------ These functions are not exported -------------
706              
707             # this function handles all log_* functions using AUTOLOAD
708             #Input (from AUTOLOADER): the function name that was called
709             #Input (from caller): Message to be printed.
710             #Output: returns 0 on success, 1 on error
711             # and sets error_message and error_code for function_name
712             sub AUTOLOAD {
713 39     39   28867 our $AUTOLOAD;
714 39         66 my $msg = shift;
715              
716             # get the function name
717 39         58 my $sub = $AUTOLOAD;
718 39         213 (my $function_name = $sub) =~ s/.*:://;
719              
720             # check we got a function name
721 39 50       105 if (!defined($function_name)) {
722             # no function name so no error code/msg to set
723 0         0 return 1;
724             }
725              
726             # check that logging was initialized
727 39 100       79 if ($log_initialized == 0) {
728 2         6 $error_code{$function_name} = LOG_NOT_INITIALIZED_CODE;
729 2         7 $error_msg{$function_name} = LOG_NOT_INITIALIZED_MSG;
730 2         6 return 1;
731             }
732              
733             # check that we have a message
734 37 100       66 if (!defined($msg)) {
735 1         5 $error_code{$function_name} = LOG_MISSING_MSG_CODE;
736 1         4 $error_msg{$function_name} = LOG_MISSING_MSG_MSG;
737 1         4 return 1;
738             }
739              
740             # check the message is printable and has valid length
741 36 100       126 if ($msg =~ /^[[:print:]]*$/) {
742 35 100       92 if (length($msg) > MAX_STRING_LEN ) {
743 1         4 $error_code{$function_name} = LOG_MSG_SIZE_CODE;
744 1         4 $error_msg{$function_name} = LOG_MSG_SIZE_MSG;
745 1         4 return 1;
746             }
747             } else {
748             # prog_name contains non-printable characters
749 1         4 $error_code{$function_name} = LOG_MSG_PRINTABLE_CODE;
750 1         3 $error_msg{$function_name} = LOG_MSG_PRINTABLE_MSG;
751 1         3 return 1;
752             }
753              
754             # calculate the log_level and description from the function
755 34 100 66     161 if ( (!defined($function_level{$function_name})) ||
756             (!defined($function_description{$function_name})) ) {
757 1         4 $error_code{$function_name} = LOG_UNKNOWN_FUNCTION_CODE;
758 1         4 $error_msg{$function_name} = LOG_UNKNOWN_FUNCTION_MSG;
759 1         4 return 1;
760             }
761              
762             # check our log_level
763 33 100       83 if ($function_level{$function_name} > $log_level){
764 6         11 $error_code{$function_name} = NO_ERROR_CODE;
765 6         12 $error_msg{$function_name} = NO_ERROR_MSG;
766 6         17 return 0;
767             }
768              
769             # if using syslog
770 27 50       51 if ($use_syslog == 1) {
771 0         0 syslog($function_level{$function_name}, $msg);
772 0         0 $error_code{$function_name} = NO_ERROR_CODE;
773 0         0 $error_msg{$function_name} = NO_ERROR_MSG;
774 0         0 return 0;
775             }
776              
777             # create a timestamp for this message
778 27         29 my $header;
779 27 100       46 if ($use_gmt) {
780 26         1420 $header = strftime ("%Y-%m-%d %H:%M:%S GMT", gmtime());
781             } else {
782 1         71 $header = strftime ("%Y-%m-%d %H:%M:%S %Z", localtime());
783             }
784             # add the hostname, program name, and pid
785 27         87 $header = $header." $hostname $prog_name\[$pid\]:";
786             # add the function description
787 27         135 $header = $header." $function_description{$function_name}";
788             # combine the header and message
789 27         55 $msg = $header." ".$msg."\n";
790             # write the message to the file (note log_fh may be STDERR)
791 27         556 my $bytes_written = syswrite($log_fh, $msg);
792 27 50 33     268 if (!defined($bytes_written) || $bytes_written == 0
      33        
793             || $bytes_written != length($msg) ) {
794 0         0 $error_code{$function_name} = LOG_WRITE_FAILED_CODE;
795 0         0 $error_msg{$function_name} = LOG_WRITE_FAILED_MSG;
796 0         0 return 1;
797             }
798              
799             # set the error code to success and return
800 27         44 $error_code{$function_name} = NO_ERROR_CODE;
801 27         46 $error_msg{$function_name} = NO_ERROR_MSG;
802 27         69 return 0;
803             }
804              
805             =head2 RETURN VALUES AND ERROR CODES
806              
807             All functions return 0 on success and 1 on error.
808             In the event of an error, an error code and error
809             message can be obtained using
810             $code = get_error_code("function_name");
811             $msg = get_error_msg("function_name");
812              
813             The following error codes are defined:
814              
815             0 - No Error:
816             'No Error'
817              
818             1 - No Function Specified in get_error_code/get_error_msg
819             'Error reporting function called without specifying the function.'
820              
821             2 - Invalid Funtion in get_error_code/get_error_msg
822             'Error reporting function called with invalid function name'
823              
824             3 - Failed To Obtain Hostname in log_init
825             'Unable to get the hostname'
826              
827             4 - Program Name Exceeds Max Length in log_init
828             'Program name exceeds maximum length of MAX_STRING_LEN'
829              
830             5 - Program Name Contains Non-Printable Characters in log_init
831             'Program name contains non-printable characters'
832              
833             6 - Log Level Is Not A Number in log_init
834             'Log level must be a postive integer'
835              
836             7 - Log Level Is Out of Range in log_init
837             'Log level must be between LOG_EMERG and LOG_DEBUG'
838              
839             8 - Log Facility Is Not A Number in log_init
840             'Log facility must be a postive integer'
841              
842             9 - Log File Name Exceeds Max Length in log_init
843             'Log file exceeds maximum length of MAX_STRING_LEN'
844              
845             10 - Log File Name Contains Non-Printable Characters in log_init
846             'Log file contains non-printable characters'
847              
848             11 - Use_syslog Is Not A Number in log_init
849             'use_syslog must be 0 or 1'
850              
851             12 - Use_syslog Is Not 0 or 1 in log_init
852             'use_syslog must be 0 or 1'
853              
854             13 - Use_gmt Is Not A Number in log_init
855             'use_gmt must be 0 or 1'
856              
857             14 - Use_gmt Is Not 0 or 1 in log_init
858             'use_gmt must be 0 or 1'
859              
860             15 - Use_gmt Set When Use_syslog = 1 in log_init
861             'use_gmt not allowed when use_syslog = 1'
862              
863             16 - Specified Both Syslog and Log File in log_init
864             'Unable to both use_syslog and write to file ';
865              
866             17 - Unable To Open Syslog in log_init
867             'Unable To open syslog';
868              
869             18 - Unable To Open Log File in log_init
870             'Unable to open log file';
871              
872             19 - Log Function Called Before Log Initialized
873             'Logging not initialized. Use init_log() prior to calling log_*("msg")';
874              
875             20 -No Such Log Function Exists
876             'No such log function ';
877              
878             21 - No Message to Log
879             'Log function called with no log message';
880              
881             22 - Log Message Exceeds Maximum Length
882             'Log message exceeds maximum length of '.MAX_STRING_LEN;
883              
884             23 - Log Message Contains Non-Printable Characters
885             'Message name contains non-printable characters'
886              
887             24 - Failed to Write Log Message
888             'Unable to write log messsage ';
889              
890             =head1 AUTHOR
891              
892             Dan Massey, C<< >>
893              
894             =head1 BUGS
895              
896             Please report any bugs or feature requests to
897             C<< >>.
898              
899             =head1 SUPPORT
900              
901             You can find documentation for this module with the perldoc command.
902              
903             perldoc BGPmon::Log
904             =cut
905              
906             =head1 LICENSE AND COPYRIGHT
907              
908             Copyright (c) 2012 Colorado State University
909              
910             Permission is hereby granted, free of charge, to any person
911             obtaining a copy of this software and associated documentation
912             files (the "Software"), to deal in the Software without
913             restriction, including without limitation the rights to use,
914             copy, modify, merge, publish, distribute, sublicense, and/or
915             sell copies of the Software, and to permit persons to whom
916             the Software is furnished to do so, subject to the following
917             conditions:
918              
919             The above copyright notice and this permission notice shall be
920             included in all copies or substantial portions of the Software.
921              
922             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
923             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
924             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
925             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
926             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
927             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
928             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
929             OTHER DEALINGS IN THE SOFTWARE.\
930              
931             File: Log.pm
932              
933             Authors: M. Lawrence Weikum, Kaustubh Gadkari, Dan Massey, Cathie Olschanowsky
934             Date: 13 October 2013
935             =cut
936             1;