]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1437646 - add support for Log::Log4perl
authorDylan William Hardison <dylan@hardison.net>
Thu, 1 Mar 2018 02:55:10 +0000 (21:55 -0500)
committerGitHub <noreply@github.com>
Thu, 1 Mar 2018 02:55:10 +0000 (21:55 -0500)
12 files changed:
.circleci/config.yml
Bugzilla.pm
Bugzilla/Install/Filesystem.pm
Bugzilla/Logging.pm [new file with mode: 0644]
Dockerfile
Log/Log4perl/Layout/Mozilla.pm [new file with mode: 0644]
Makefile.PL
README.rst
conf/log4perl-json.conf [new file with mode: 0644]
conf/log4perl-syslog.conf [new file with mode: 0644]
conf/log4perl-test.conf [new file with mode: 0644]
docker-compose.yml

index 9c99df18b71567aa96cbaf362447486de8f57bea..7a2c62e82e55fad61dd4b35a404af67b4a1113fc 100644 (file)
@@ -26,6 +26,7 @@ defaults:
     PORT: 8000
     LOGGING_PORT: 5880
     LOCALCONFIG_ENV: 1
+    LOG4PERL_CONFIG_FILE: log4perl-test.conf
     BMO_db_user: bugs
     BMO_db_host: 127.0.0.1
     BMO_db_pass: bugs
@@ -108,7 +109,10 @@ jobs:
         environment: *bmo_env
     steps:
       - checkout
-      - *default_qa_setup
+      - run: |
+          mv /opt/bmo/local /app/local
+          mkdir artifacts
+      - run: perl Makefile.PL
       - run:
           name: run sanity tests
           command: |
index c21b1ad98f45f4f3919bc615f6fb4a4c8e739b77..a154b174b7461a94b2187670b4956a76e65da195 100644 (file)
@@ -11,6 +11,8 @@ use 5.10.1;
 use strict;
 use warnings;
 
+use Bugzilla::Logging;
+
 # We want any compile errors to get to the browser, if possible.
 BEGIN {
     # This makes sure we're in a CGI.
@@ -97,6 +99,10 @@ sub init_page {
         binmode STDOUT, ':utf8';
     }
 
+    if (i_am_cgi()) {
+        Log::Log4perl::MDC->put(remote_ip => remote_ip());
+    }
+
     if (${^TAINT}) {
         # Some environment variables are not taint safe
         delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
@@ -380,6 +386,10 @@ sub login {
 
     my $authenticated_user = $authorizer->login($type);
 
+    if (i_am_cgi()) {
+        Log::Log4perl::MDC->put(user_id => $authenticated_user->id);
+    }
+
     # At this point, we now know if a real person is logged in.
 
     # Check if a password reset is required
@@ -770,9 +780,8 @@ sub local_timezone {
 # Send messages to syslog for the auditing systems (eg. mozdef) to pick up.
 sub audit {
     my ($class, $message) = @_;
-    openlog('apache', 'cons,pid', 'local4');
-    syslog('notice', '[audit] ' . encode_utf8($message));
-    closelog();
+    state $logger = Log::Log4perl->get_logger("audit");
+    $logger->notice(encode_utf8($message));
 }
 
 # This creates the request cache for non-mod_perl installations.
@@ -887,6 +896,8 @@ sub _cleanup {
     foreach my $signal (qw(TERM PIPE)) {
         $SIG{$signal} = 'DEFAULT' if $SIG{$signal} && $SIG{$signal} eq 'IGNORE';
     }
+
+    Log::Log4perl::MDC->remove();
 }
 
 sub END {
index d205a67509e2bb31f3b839d7006384e3be3a4b5a..97ab69b9be3a1c1788bd32e9c3beb8844ef567dc 100644 (file)
@@ -105,6 +105,7 @@ EOT
 use constant HTTPD_ENV => qw(
     LOCALCONFIG_ENV
     BUGZILLA_UNSAFE_AUTH_DELEGATION
+    LOG4PERL_CONFIG_FILE
     USE_NYTPROF
     NYTPROF_DIR
 );
diff --git a/Bugzilla/Logging.pm b/Bugzilla/Logging.pm
new file mode 100644 (file)
index 0000000..c10f4c1
--- /dev/null
@@ -0,0 +1,25 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Logging;
+use 5.10.1;
+use strict;
+use warnings;
+
+use Log::Log4perl;
+use Log::Log4perl::MDC;
+use File::Spec::Functions qw(rel2abs);
+use Bugzilla::Constants qw(bz_locations);
+
+BEGIN {
+    my $file = $ENV{LOG4PERL_CONFIG_FILE} // "log4perl-syslog.conf";
+    Log::Log4perl::Logger::create_custom_level('NOTICE', 'WARN', 5, 2);
+    Log::Log4perl->init(rel2abs($file, bz_locations->{confdir}));
+    Log::Log4perl->get_logger(__PACKAGE__)->debug("logging enabled in $0");
+}
+
+1;
index 8b82ac6ff9cfb0eb7287ee815ef33641398e9c9f..ac101bb941ceacd69c6318df5bbb1dfa0b2c1fca 100644 (file)
@@ -9,6 +9,7 @@ ENV CI=${CI}
 ENV CIRCLE_BUILD_URL=${CIRCLE_BUILD_URL}
 ENV CIRCLE_SHA1=${CIRCLE_SHA1}
 
+ENV LOG4PERL_CONFIG_FILE=log4perl-json.conf
 ENV HTTPD_StartServers=8
 ENV HTTPD_MinSpareServers=5
 ENV HTTPD_MaxSpareServers=20
diff --git a/Log/Log4perl/Layout/Mozilla.pm b/Log/Log4perl/Layout/Mozilla.pm
new file mode 100644 (file)
index 0000000..67a070c
--- /dev/null
@@ -0,0 +1,124 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Log::Log4perl::Layout::Mozilla;
+use 5.10.1;
+use Moo;
+use Sys::Hostname;
+use JSON::MaybeXS ();
+use English qw(-no_match_vars $PID);
+
+use constant LOGGING_FORMAT_VERSION => 2.0;
+
+extends 'Log::Log4perl::Layout';
+
+has 'name' => (
+    is      => 'ro',
+    default => 'Bugzilla',
+);
+
+has 'max_json_length' => (
+    is      => 'ro',
+    isa     => sub { die "must be at least 1024\n" if $_[0] < 1024 },
+    default => 4096,
+);
+
+sub BUILDARGS {
+    my ($class, $params) = @_;
+
+    delete $params->{value};
+    foreach my $key (keys %$params) {
+        if (ref $params->{$key} eq 'HASH') {
+            $params->{$key} = $params->{$key}{value};
+        }
+    }
+    return $params;
+}
+
+sub render {
+    my ( $self, $msg, $category, $priority, $caller_level ) = @_;
+
+    state $HOSTNAME = hostname();
+    state $JSON     = JSON::MaybeXS->new(
+        indent          => 0,    # to prevent newlines (and save space)
+        ascii           => 1,    # to avoid encoding issues downstream
+        allow_unknown   => 1,    # encode null on bad value (instead of exception)
+        convert_blessed => 1,    # call TO_JSON on blessed ref, if it exists
+        allow_blessed   => 1,    # encode null on blessed ref that can't be converted
+    );
+
+    my $mdc = Log::Log4perl::MDC->get_context;
+    my %out = (
+        EnvVersion => LOGGING_FORMAT_VERSION,
+        Hostname   => $HOSTNAME,
+        Logger     => $self->name,
+        Pid        => $PID,
+        Severity   => $Log::Log4perl::Level::SYSLOG{$priority},
+        Timestamp  => time() * 1e9,
+        Type       => $category,
+        Fields     => { msg => $msg, %$mdc },
+    );
+
+    my $json_text = $JSON->encode(\%out) . "\n";
+    if (length($json_text) > $self->max_json_length) {
+        my $scary_msg = sprintf( "DANGER! LOG MESSAGE TOO BIG %d > %d", length($json_text), $self->max_json_length );
+        $out{Fields}   = { remote_ip => $mdc->{remote_ip}, msg => $scary_msg };
+        $out{Severity} = 1; # alert
+        $json_text     = $JSON->encode(\%out) . "\n";
+    }
+
+    return $json_text;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Log::Log4perl::Layout::Mozilla - Implement the mozilla-services json log format
+
+=head1 SYNOPSIS
+
+Example configuration:
+
+    log4perl.appender.Example.layout = Log::Log4perl::Layout::Mozilla
+    log4perl.appender.Example.layout.max_json_length = 16384
+    log4perl.appender.Example.layout.name = Bugzilla
+
+=head1 DESCRIPTION
+
+This class implements a C<Log::Log4perl> layout format
+that implements the recommend json format using in Mozilla services.
+L<https://wiki.mozilla.org/Firefox/Services/Logging#MozLog_JSON_schema>.
+
+The JSON hash is ASCII encoded, with no newlines or other whitespace, and is
+suitable for output, via Log::Log4perl appenders, to files and syslog etc.
+
+Contextual data in the L<Log::Log4perl::MDC> hash will be put into the Fields
+hash.
+
+=head1 LAYOUT CONFIGURATION
+
+=head2 name
+
+Data source, server that is doing the logging, e.g. "Sync-1_5".
+
+Use the server's name, and avoid implementation details. "FxaAuthWebserver", not "NginxLogs".
+
+=head2 max_json_length
+
+Set the maximum JSON length in bytes. The default is 4096,
+and it cannot be smaller than 1024.
+
+    log4perl.appender.Example.layout.max_json_length = 16384
+
+This is useful where some downstream system has a limit on the maximum size of
+a message.
+
+If the message is larger than this limit, the message will be replaced
+with a scary message at a severity level of ALERT.
\ No newline at end of file
index bfeaafa4360868d8d60d308b050084803c441bfa..9c1f05e6f2d736b44d1fd776350fe26aa3442356 100755 (executable)
@@ -71,6 +71,9 @@ my %requires = (
     'HTML::Escape'             => '1.10',
     'URI::Escape::XS'          => '0.14',
     'Sereal'                   => '4.004',
+    'Log::Dispatch'            => '2.67',
+    'Log::Log4perl'            => '1.49',
+    'JSON::MaybeXS'            => '1.003008',
 );
 my %build_requires = (
     'ExtUtils::MakeMaker' => '7.22',
index ef585bacffbadae8927da6a3c674ace0661e9527..a2b23d069a2b8da5177e11900fa16764a1dc1e48 100644 (file)
@@ -342,7 +342,13 @@ USE_NYTPROF
 NYTPROF_DIR
   Alternative location to store profiles from the above option.
 
+LOG4PERL_CONFIG_FILE
+  Filename of `Log::Log4perl`_ config file.
+  It defaults to log4perl-syslog.conf.
+  If the file is given as a relative path, it will belative to the /app/conf/ directory.
+
 .. _`Devel::NYTProf`: https://metacpan.org/pod/Devel::NYTProf
+.. _`Log::Log4perl`: https://metacpan.org/pod/Log::Log4perl
 
 Persistent Data Volume
 ----------------------
diff --git a/conf/log4perl-json.conf b/conf/log4perl-json.conf
new file mode 100644 (file)
index 0000000..4156203
--- /dev/null
@@ -0,0 +1,16 @@
+log4perl.rootLogger = INFO, Socket
+log4perl.appender.Socket = Log::Log4perl::Appender::Socket
+log4perl.appender.Socket.PeerAddr=127.0.0.1
+log4perl.appender.Socket.PeerPort=5880
+log4perl.appender.Socket.defer_connection=1
+
+# This class is currently bundled with bugzilla
+log4perl.appender.Socket.layout = Log::Log4perl::Layout::Mozilla
+
+# lines longer than this will not be logged in detail.
+# instead a scary message with a much higher severity will be logged.
+log4perl.appender.Socket.layout.max_json_length = 16384
+# The default is Bugzilla. This is the "Logger" field
+# in https://wiki.mozilla.org/Firefox/Services/Logging#MozLog_JSON_schema
+#and it might be useful to pass in different values for different jobs.
+log4perl.appender.Socket.layout.name = Bugzilla
diff --git a/conf/log4perl-syslog.conf b/conf/log4perl-syslog.conf
new file mode 100644 (file)
index 0000000..32f3d4c
--- /dev/null
@@ -0,0 +1,9 @@
+log4perl.rootLogger = INFO, syslog
+log4perl.appender.syslog = Log::Dispatch::Syslog
+log4perl.appender.syslog.min_level = notice
+log4perl.appender.syslog.ident = apache
+log4perl.appender.syslog.facility = local4
+log4perl.appender.syslog.logopt = cons,pid
+log4perl.appender.syslog.layout = Log::Log4perl::Layout::PatternLayout
+log4perl.appender.syslog.layout.ConversionPattern = [%c] %m{chomp}%n
+
diff --git a/conf/log4perl-test.conf b/conf/log4perl-test.conf
new file mode 100644 (file)
index 0000000..7f2309c
--- /dev/null
@@ -0,0 +1,7 @@
+log4perl.rootLogger = DEBUG, DebugSocket
+log4perl.appender.DebugSocket = Log::Log4perl::Appender::Socket
+log4perl.appender.DebugSocket.PeerAddr=127.0.0.1
+log4perl.appender.DebugSocket.PeerPort=5880
+log4perl.appender.DebugSocket.defer_connection=1
+log4perl.appender.DebugSocket.layout = Log::Log4perl::Layout::PatternLayout
+log4perl.appender.DebugSocket.layout.ConversionPattern = [%d] [%c] <%p> %m{chomp} at %F line %L (%M)%n
index 1c5011b55578239c4a470591fd0cb9b40947da35..e04e9c7128adb6ecd00ed23e09442c88097c1c6c 100755 (executable)
@@ -17,6 +17,7 @@ services:
       - /run
     environment: &bmo_env
       - LOCALCONFIG_ENV=1
+      - LOG4PERL_CONFIG_FILE=log4perl-test.conf
       - BUGZILLA_UNSAFE_AUTH_DELEGATION=1
       - PORT=80
       - BMO_db_host=bmo-db.vm