Skip to content

Commit

Permalink
Merge pull request #327 from alphagov/enable-adding-more-custom-logst…
Browse files Browse the repository at this point in the history
…asher-fields

Enable adding custom LogStasher fields from apps
  • Loading branch information
mike29736 committed Nov 27, 2023
2 parents 6c67586 + 2305f46 commit 6dcd26f
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 9.7.0

* Enable adding custom LogStasher fields from apps ([#327](https://github.com/alphagov/govuk_app_config/pull/327))

# 9.6.0

* Allow YouTube thumbnails from https://i.ytimg.com in the global Content Security Policy ([#328](https://github.com/alphagov/govuk_app_config/pull/328))
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,20 @@ allow JSON format logs and `Govuk-Request-Id` to be visible.
For development logs, in order to see the production style logs, developers should
set `GOVUK_RAILS_JSON_LOGGING`in `govuk-docker` -> `docker-compose` files.

### Logger configuration

To include additional custom fields in your Rails logs, you can declare them
within a `GovukJsonLogging.configure` block in a `config/initializers/` file.

Example of adding a key/value to log entries based on a request header:

```ruby
GovukJsonLogging.configure do
add_custom_fields do |fields|
fields[:govuk_custom_field] = request.headers["GOVUK-Custom-Header"]
end
end
```

## Content Security Policy generation

Expand Down
20 changes: 19 additions & 1 deletion lib/govuk_app_config/govuk_json_logging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,23 @@
require "action_controller"

module GovukJsonLogging
def self.configure
class Configuration
def initialize
@custom_fields_block = proc {}
end

attr_reader :custom_fields_block

def add_custom_fields(&block)
@custom_fields_block = block if block_given?
end
end

def self.configure(&block)
configuration = Configuration.new

configuration.instance_eval(&block) if block_given?

# We disable buffering, so that logs aren't lost on crash or delayed
# indefinitely while troubleshooting.
$stdout.sync = true
Expand Down Expand Up @@ -31,6 +47,8 @@ def self.configure
fields[:govuk_request_id] = request.headers["GOVUK-Request-Id"]
fields[:varnish_id] = request.headers["X-Varnish"]
fields[:govuk_app_config] = GovukAppConfig::VERSION

instance_exec(fields, &configuration.custom_fields_block) if block_given?
end

Rails.application.config.logstasher.enabled = true
Expand Down
2 changes: 1 addition & 1 deletion lib/govuk_app_config/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module GovukAppConfig
VERSION = "9.6.0".freeze
VERSION = "9.7.0".freeze
end
65 changes: 65 additions & 0 deletions spec/lib/govuk_json_logging_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
require "govuk_app_config/govuk_json_logging"
require "rack/test"

class TestController < ActionController::Base
include LogStasher::ActionController::Instrumentation
def index; end
end

RSpec.describe GovukJsonLogging do
let(:govuk_headers_class) do
Class.new do
Expand Down Expand Up @@ -78,6 +83,66 @@ def self.headers
expect(fake_stdout.read).to match(/test default log entry/)
end

context "given a block" do
it "evals the block" do
done = false
expect {
GovukJsonLogging.configure do
done = true
end
}.to change { done }.to(true)
end

context "and the block configures custom fields" do
describe "any subsequently-created ActionController" do
let(:headers) { { "REMOTE_ADDR" => "10.10.10.10" } }
let(:mock_request) { ActionDispatch::TestRequest.new(Rack::MockRequest.env_for("http://example.com:8080/", headers)) }
let(:mock_response) { ActionDispatch::TestResponse.new }

before do
GovukJsonLogging.configure do
add_custom_fields do |fields|
fields[:govuk_custom_field] = request.headers["GOVUK-Custom-Header"]
end
end

@controller = TestController.new
allow(@controller).to receive(:request).and_return(mock_request)
allow(@controller).to receive(:response).and_return(mock_response)
end

it "has a logstasher_add_custom_fields_to_payload method" do
expect(@controller.methods).to include(:logstasher_add_custom_fields_to_payload)
end

describe "calling the logstasher_add_custom_fields_to_payload" do
let(:payload) { {} }

it "executes the block" do
expect(@controller).to receive(:logstasher_add_custom_fields_to_payload)
@controller.send(:append_info_to_payload, payload)
end

it "adds the custom fields to the payload" do
@controller.send(:append_info_to_payload, payload)
expect(payload.keys).to include(:govuk_custom_field)
end

context "when the custom field has a value" do
before do
mock_request.headers["GOVUK-Custom-header"] = "My header value"
end

it "sets the custom field value in the payload" do
@controller.send(:append_info_to_payload, payload)
expect(payload[:govuk_custom_field]).to eq("My header value")
end
end
end
end
end
end

describe "when making requests to the application" do
include Rack::Test::Methods

Expand Down

0 comments on commit 6dcd26f

Please sign in to comment.