diff --git a/lib/cloud_controller/diego/stager.rb b/lib/cloud_controller/diego/stager.rb index 9d632b133f7..42c031aa2d9 100644 --- a/lib/cloud_controller/diego/stager.rb +++ b/lib/cloud_controller/diego/stager.rb @@ -33,6 +33,11 @@ def send_stage_package_request(staging_details) rescue CloudController::Errors::ApiError => e raise e rescue StandardError => e + logger.error('stage.package.error', + package_guid: staging_details.package.guid, + staging_guid: staging_details.staging_guid, + error: e, + backtrace: e.backtrace) raise CloudController::Errors::ApiError.new_from_details('StagerError', e) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 49b19b7361d..81611b76951 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -110,6 +110,7 @@ rspec_config.include TimeHelpers rspec_config.include LinkHelpers rspec_config.include BackgroundJobHelpers + rspec_config.include LogHelpers rspec_config.include ServiceBrokerHelpers rspec_config.include UserHelpers diff --git a/spec/support/log_helpers.rb b/spec/support/log_helpers.rb new file mode 100644 index 00000000000..b91965d3335 --- /dev/null +++ b/spec/support/log_helpers.rb @@ -0,0 +1,30 @@ +module LogHelpers + class TailedLogs + def initialize(io_log) + @io_log = io_log + end + + def read + @io_log.string.split("\n").map { |l| Oj.load(l) } + end + end + + def tail_logs(&block) + steno_config_backup = ::Steno.config + + begin + io_log = ::StringIO.new + io_sink = ::Steno::Sink::IO.new(io_log, codec: ::Steno::Codec::JsonRFC3339.new) + ::Steno.init(::Steno::Config.new( + sinks: steno_config_backup.sinks + [io_sink], + codec: steno_config_backup.codec, + context: steno_config_backup.context, + default_log_level: 'all' + )) + + block.yield(TailedLogs.new(io_log)) + ensure + ::Steno.init(steno_config_backup) + end + end +end diff --git a/spec/unit/lib/cloud_controller/diego/stager_spec.rb b/spec/unit/lib/cloud_controller/diego/stager_spec.rb index 824b090fc0b..1154d88b712 100644 --- a/spec/unit/lib/cloud_controller/diego/stager_spec.rb +++ b/spec/unit/lib/cloud_controller/diego/stager_spec.rb @@ -64,20 +64,62 @@ module Diego end context 'when the stage fails' do - let(:error) do - { error: { id: 'StagingError', message: 'Stager error: staging failed' } } + describe 'with an APIError' do + let(:error) do + { error: { id: 'StagingError', message: 'Stager error: staging failed' } } + end + + before do + allow(messenger).to receive(:send_stage_request).and_raise(CloudController::Errors::ApiError.new_from_details('StagerError', 'staging failed')) + end + + it 'calls the completion handler with the error' do + expect do + stager.stage(staging_details) + end.to raise_error(CloudController::Errors::ApiError) + package.reload + expect(buildpack_completion_handler).to have_received(:staging_complete).with(error, false) + end end - before do - allow(messenger).to receive(:send_stage_request).and_raise(CloudController::Errors::ApiError.new_from_details('StagerError', 'staging failed')) - end - - it 'calls the completion handler with the error' do - expect do - stager.stage(staging_details) - end.to raise_error(CloudController::Errors::ApiError) - package.reload - expect(buildpack_completion_handler).to have_received(:staging_complete).with(error, false) + describe 'with any other error' do + let(:error) do + { error: { id: 'StagingError', message: 'Stager error: something is very wrong' } } + end + + before do + allow(messenger).to receive(:send_stage_request).and_raise(StandardError.new('something is very wrong')) + end + + it 'calls the completion handler with the error' do + expect do + stager.stage(staging_details) + end.to raise_error(CloudController::Errors::ApiError) + package.reload + expect(buildpack_completion_handler).to have_received(:staging_complete).with(error, false) + end + + it 'logs the original error, with a stack trace' do + tail_logs do |logs| + expect do + stager.stage(staging_details) + end.to raise_error(CloudController::Errors::ApiError) + + expect( + logs.read.find { |l| l['message'] == 'stage.package.error' } + ).to match( + hash_including( + 'message' => 'stage.package.error', + 'data' => { + 'package_guid' => package.guid, + 'staging_guid' => build.guid, + 'error' => 'something is very wrong', + 'backtrace' => array_including(/and_raise/) + } + ) + ) + end + end end end end