Merge pull request #9679 from opf/grape-logging
Allow request logging for grape with lograge and optional JSON loggingpull/9682/head
commit
05b3d23b18
@ -0,0 +1,14 @@ |
||||
OpenProject::Application.configure do |
||||
config.after_initialize do |
||||
ActiveSupport::Notifications.subscribe('openproject_grape_logger') do |_, _, _, _, payload| |
||||
time = payload[:time] |
||||
attributes = { |
||||
duration: time[:total], |
||||
db: time[:db], |
||||
view: time[:view] |
||||
}.merge(payload.except(:time)) |
||||
|
||||
Rails.logger.info OpenProject::Logging.formatter.call(attributes) |
||||
end |
||||
end |
||||
end |
@ -1,9 +1,12 @@ |
||||
Rails.application.configure do |
||||
config.lograge.enabled = Rails.env.production? || ENV['OPENPROJECT_LOGRAGE_ENABLED'] |
||||
next unless OpenProject::Logging.lograge_enabled? |
||||
|
||||
config.lograge.enabled = true |
||||
config.lograge.formatter = OpenProject::Logging.formatter |
||||
config.lograge.base_controller_class = %w[ActionController::Base] |
||||
|
||||
# Add custom data to event payload |
||||
config.lograge.custom_payload do |controller| |
||||
::OpenProject::Logging::LogDelegator.controller_payload_hash controller |
||||
::OpenProject::Logging.extend_payload!({}, { controller: controller }) |
||||
end |
||||
end |
||||
|
@ -0,0 +1,59 @@ |
||||
require_relative 'logging/log_delegator' |
||||
|
||||
module OpenProject |
||||
module Logging |
||||
class << self |
||||
## |
||||
# Do we use lograge in the end to perform the payload output |
||||
def lograge_enabled? |
||||
OpenProject::Configuration.lograge_formatter.present? |
||||
end |
||||
|
||||
## |
||||
# The lograge class to output the payload object |
||||
def formatter |
||||
@formatter ||= begin |
||||
formatter_setting = OpenProject::Configuration.lograge_formatter || 'key_value' |
||||
"Lograge::Formatters::#{formatter_setting.classify}" |
||||
.constantize |
||||
.new |
||||
end |
||||
end |
||||
|
||||
## |
||||
# Extend a payload to be logged with additional information |
||||
# @param context {Hash} The context of the log, might contain controller or sentry related keys |
||||
def extend_payload!(payload, context) |
||||
payload_extenders.reduce(payload.dup) do |hash, handler| |
||||
res = handler.call(context) |
||||
hash.merge!(res) if res.is_a?(Hash) |
||||
hash |
||||
rescue StandardError => e |
||||
Rails.logger.error "Failed to extend payload in #{handler.inspect}: #{e.message}" |
||||
hash |
||||
end |
||||
end |
||||
|
||||
## |
||||
# Get a set of extenders that may add to the logging context payload |
||||
def payload_extenders |
||||
@payload_extenders ||= [ |
||||
method(:default_payload) |
||||
] |
||||
end |
||||
|
||||
## |
||||
# Register a new payload extender |
||||
# for all logging purposes |
||||
def add_payload_extender(&block) |
||||
payload_extenders << block |
||||
end |
||||
|
||||
private |
||||
|
||||
def default_payload(_context) |
||||
{ user: User.current.try(:id) } |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,95 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2021 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'spec_helper' |
||||
|
||||
describe OpenProject::Logging, 'Log extenders' do |
||||
subject { described_class.extend_payload!(payload, input_context) } |
||||
|
||||
let(:payload) do |
||||
{ method: 'GET', action: 'something', controller: 'SomeController' } |
||||
end |
||||
|
||||
let(:input_context) do |
||||
{} |
||||
end |
||||
|
||||
context 'with an extender returning keys' do |
||||
let(:return_value) do |
||||
{ some_hash: 123 } |
||||
end |
||||
|
||||
let(:extender) do |
||||
->(_context) do |
||||
return_value |
||||
end |
||||
end |
||||
|
||||
before do |
||||
described_class.add_payload_extender(&extender) |
||||
end |
||||
|
||||
after do |
||||
described_class.instance_variable_set('@payload_extenders', nil) |
||||
end |
||||
|
||||
it 'calls that extender as well as the default one' do |
||||
allow(extender).to receive(:call).and_call_original |
||||
|
||||
expect(subject.keys).to contain_exactly :method, :action, :controller, :some_hash, :user |
||||
expect(subject[:some_hash]).to eq 123 |
||||
end |
||||
end |
||||
|
||||
context 'with an extender raising an error' do |
||||
let(:return_value) do |
||||
{ some_hash: 123 } |
||||
end |
||||
|
||||
let(:extender) do |
||||
->(_context) do |
||||
raise "This is not good." |
||||
end |
||||
end |
||||
|
||||
before do |
||||
described_class.add_payload_extender(&extender) |
||||
end |
||||
|
||||
after do |
||||
described_class.instance_variable_set('@payload_extenders', nil) |
||||
end |
||||
|
||||
it 'does not break the returned payload' do |
||||
allow(extender).to receive(:call).and_call_original |
||||
|
||||
expect(subject.keys).to contain_exactly :method, :action, :controller, :user |
||||
expect(subject[:some_hash]).to eq nil |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue