]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/perl/lib/OpenSRF/Utils/Logger.pm
LP#1473479 Syslog configuration adoption
[OpenSRF.git] / src / perl / lib / OpenSRF / Utils / Logger.pm
1 package OpenSRF::Utils::Logger;
2 use strict;
3 use vars qw($AUTOLOAD @EXPORT_OK %EXPORT_TAGS);
4 use Exporter;
5 use Unix::Syslog qw(:macros :subs);
6 use base qw/OpenSRF Exporter/;
7 use FileHandle;
8 use Time::HiRes qw(gettimeofday);
9 use OpenSRF::Utils::Config;
10 use Fcntl;
11
12 =head1
13
14 Logger code
15
16 my $logger = OpenSRF::Utils::Logger;
17 $logger->error( $msg );
18
19 For backwards compability, a log level may also be provided to each log
20 function thereby overriding the level defined by the function.
21
22 i.e. $logger->error( $msg, WARN );  # logs at log level WARN
23
24 =cut
25
26 @EXPORT_OK = qw/ NONE ERROR WARN INFO DEBUG INTERNAL /;
27 push @EXPORT_OK, '$logger';
28
29 %EXPORT_TAGS = ( level => [ qw/ NONE ERROR WARN INFO DEBUG INTERNAL / ], logger => [ '$logger' ] );
30
31 my $config;             # config handle
32 my $loglevel = INFO();  # global log level
33 my $logfile;            # log file
34 my $facility;           # syslog facility
35 my $actfac;             # activity log syslog facility
36 my $actfile;            # activity log file
37 my $service;            # syslog service name.  default provided below.
38 my $service_tag = '';   # default service tag
39 my $syslog_enabled = 0; # is syslog enabled?
40 my $act_syslog_enabled = 0; # is syslog enabled?
41 my $logfile_enabled = 1;    # are we logging to a file?
42 my $act_logfile_enabled = 1;# are we logging to a file?
43 my $max_log_msg_len = 1536; # SYSLOG default maximum is 2048
44
45 our $logger = "OpenSRF::Utils::Logger";
46
47 # log levels
48 sub ACTIVITY { return -1; }
49 sub NONE     { return 0; }
50 sub ERROR    { return 1; }
51 sub WARN     { return 2; }
52 sub INFO     { return 3; }
53 sub DEBUG    { return 4; }
54 sub INTERNAL { return 5; }
55 sub ALL      { return 100; }
56
57 my $isclient;  # true if we control the osrf_xid
58
59 # load up our config options
60 sub set_config {
61     my $force = shift;
62
63     return if defined $config and !$force;
64
65     $config = OpenSRF::Utils::Config->current;
66     if( !defined($config) ) {
67         $loglevel = INFO();
68         warn "*** Logger found no config.  Using STDERR ***\n";
69         return;
70     }
71
72     $loglevel =  $config->bootstrap->loglevel; 
73
74     if ($config->bootstrap->loglength) {
75         $max_log_msg_len = $config->bootstrap->loglength;
76     }
77
78     $service_tag = $config->bootstrap->logtag;
79
80     $logfile = $config->bootstrap->logfile;
81     if($logfile =~ /^syslog/) {
82         $syslog_enabled = 1;
83         $logfile_enabled = 0;
84         $logfile = $config->bootstrap->syslog;
85         $facility = $logfile;
86         $logfile = undef;
87         $facility = _fac_to_const($facility);
88         # OSRF_ADOPT_SYSLOG means we assume syslog is already
89         # opened w/ the correct values.  Don't clobber it.
90         openlog($service, 0, $facility) unless $ENV{OSRF_ADOPT_SYSLOG};
91
92     } else { $logfile = "$logfile"; }
93
94
95     if($syslog_enabled) {
96         # --------------------------------------------------------------
97         # if we're syslogging, see if we have a special syslog facility 
98         # for activity logging.  If not, use the syslog facility for
99         # standard logging
100         # --------------------------------------------------------------
101         $act_syslog_enabled = 1;
102         $act_logfile_enabled = 0;
103         $actfac = $config->bootstrap->actlog || $config->bootstrap->syslog;
104         $actfac = _fac_to_const($actfac);
105         $actfile = undef;
106     } else {
107         # --------------------------------------------------------------
108         # we're not syslogging, use any specified activity log file.
109         # Fall back to the standard log file otherwise
110         # --------------------------------------------------------------
111         $act_syslog_enabled = 0;
112         $act_logfile_enabled = 1;
113         $actfile = $config->bootstrap->actlog || $config->bootstrap->logfile;
114     }
115
116     my $client = OpenSRF::Utils::Config->current->bootstrap->client();
117
118     if ($ENV{OSRF_LOG_CLIENT} or $ENV{MOD_PERL}) {
119         $isclient = 1;
120         return;
121     }
122
123     if (!$client) {
124         $isclient = 0;
125         return;
126     }
127     $isclient = ($client =~ /^true$/iog) ?  1 : 0;
128 }
129
130 sub _fac_to_const {
131     my $name = shift;
132     return LOG_LOCAL0 unless $name;
133     return LOG_LOCAL0 if $name =~ /local0/i;
134     return LOG_LOCAL1 if $name =~ /local1/i;
135     return LOG_LOCAL2 if $name =~ /local2/i;
136     return LOG_LOCAL3 if $name =~ /local3/i;
137     return LOG_LOCAL4 if $name =~ /local4/i;
138     return LOG_LOCAL5 if $name =~ /local5/i;
139     return LOG_LOCAL6 if $name =~ /local6/i;
140     return LOG_LOCAL7 if $name =~ /local7/i;
141     return LOG_LOCAL0;
142 }
143
144 sub is_syslog {
145     set_config();
146     return $syslog_enabled;
147 }
148
149 sub is_act_syslog {
150     set_config();
151     return $act_syslog_enabled;
152 }
153
154 sub is_filelog {
155     set_config();
156     return $logfile_enabled;
157 }
158
159 sub is_act_filelog {
160     set_config();
161     return $act_logfile_enabled;
162 }
163
164 sub set_service {
165     my( $self, $svc ) = @_;
166     return if $ENV{OSRF_ADOPT_SYSLOG};
167     $service = $svc;    
168     $service .= '/' . $service_tag if (defined $service_tag);    
169     if( is_syslog() ) {
170         closelog();
171         openlog($service, 0, $facility);
172     }
173 }
174
175 sub error {
176     my( $self, $msg, $level ) = @_;
177     $level = ERROR() unless defined ($level);
178     _log_message( $msg, $level );
179 }
180
181 sub warn {
182     my( $self, $msg, $level ) = @_;
183     $level = WARN() unless defined ($level);
184     _log_message( $msg, $level );
185 }
186
187 sub info {
188     my( $self, $msg, $level ) = @_;
189     $level = INFO() unless defined ($level);
190     _log_message( $msg, $level );
191 }
192
193 sub debug {
194     my( $self, $msg, $level ) = @_;
195     $level = DEBUG() unless defined ($level);
196     _log_message( $msg, $level );
197 }
198
199 sub internal {
200     my( $self, $msg, $level ) = @_;
201     $level = INTERNAL() unless defined ($level);
202     _log_message( $msg, $level );
203 }
204
205 sub activity {
206     my( $self, $msg ) = @_;
207     _log_message( $msg, ACTIVITY() );
208 }
209
210 # for backward compability
211 sub transport {
212     my( $self, $msg, $level ) = @_;
213     $level = DEBUG() unless defined ($level);
214     _log_message( $msg, $level );
215 }
216
217
218 # ----------------------------------------------------------------------
219 # creates a new xid if necessary
220 # ----------------------------------------------------------------------
221 my $osrf_xid = '';
222 my $osrf_xid_inc = 0;
223 sub mk_osrf_xid {
224    return unless $isclient;
225    $osrf_xid_inc++;
226    return $osrf_xid = "$^T${$}$osrf_xid_inc";
227 }
228
229 sub set_osrf_xid { 
230    return if $isclient; # if we're a client, we control our xid
231    $osrf_xid = $_[1]; 
232 }
233
234 sub get_osrf_xid { return $osrf_xid; }
235 # ----------------------------------------------------------------------
236
237    
238 sub _log_message {
239     my( $msg, $level ) = @_;
240     return if $level > $loglevel;
241
242     # apply a sane default service name/tag
243     $logger->set_service($0) unless $service;
244
245     my $l; my $n; 
246     my $fac = $facility;
247
248     if ($level == ERROR())            {$l = LOG_ERR; $n = "ERR "; }
249     elsif ($level == WARN())        {$l = LOG_WARNING; $n = "WARN"; }
250     elsif ($level == INFO())        {$l = LOG_INFO; $n = "INFO"; }    
251     elsif ($level == DEBUG())        {$l = LOG_DEBUG; $n = "DEBG"; }
252     elsif ($level == INTERNAL())    {$l = LOG_DEBUG; $n = "INTL"; }
253     elsif ($level == ACTIVITY())    {$l = LOG_INFO; $n = "ACT"; $fac = $actfac; }
254
255     my( undef, $file, $line_no ) = caller(1);
256    $file =~ s#/.*/##og;
257
258     # help syslog with the formatting
259     $msg =~ s/\%/\%\%/gso if( is_act_syslog() or is_syslog() );
260
261     $msg = "[$n:"."$$".":$file:$line_no:$osrf_xid] $msg";
262
263     # Trim the message to the configured maximum log message length
264     $msg = substr($msg, 0, $max_log_msg_len); 
265
266     # avoid clobbering the adopted syslog facility
267     my $slog_flags = $ENV{OSRF_ADOPT_SYSLOG} ? $l : $fac | $l;
268
269     if( $level == ACTIVITY() ) {
270         if( is_act_syslog() ) { syslog( $slog_flags, $msg ); }
271         elsif( is_act_filelog() ) { _write_file( $msg, 1 ); }
272
273     } else {
274         if( is_syslog() ) { syslog( $slog_flags, $msg ); }
275         elsif( is_filelog() ) { _write_file($msg); }
276     }
277
278     return $msg;
279 }
280
281 sub _write_file {
282     my ($msg, $isact) = @_;
283     my $file = $isact ? $actfile : $logfile;
284     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);  
285     $year += 1900; $mon += 1;
286
287     if ($file) {
288         sysopen( SINK, $file, O_NONBLOCK|O_WRONLY|O_APPEND|O_CREAT ) 
289             or die "Cannot sysopen $file: $!";
290     } else {
291         open (SINK, ">&2");  # print to STDERR as warned
292     }
293     binmode(SINK, ':utf8');
294     printf SINK "[%04d-%02d-%02d %02d:%02d:%02d] %s %s\n", $year, $mon, $mday, $hour, $min, $sec, $service, $msg;
295     close( SINK );
296 }
297
298 1;
299