From 6d79961b7532b7514e4fc3027c46cea102aae413 Mon Sep 17 00:00:00 2001 From: Marco Costa Date: Wed, 4 Jan 2023 15:41:49 -0800 Subject: [PATCH 1/2] Support PG calls with a block --- .../tracing/contrib/pg/instrumentation.rb | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/lib/datadog/tracing/contrib/pg/instrumentation.rb b/lib/datadog/tracing/contrib/pg/instrumentation.rb index 60e659c633..49c361a20d 100644 --- a/lib/datadog/tracing/contrib/pg/instrumentation.rb +++ b/lib/datadog/tracing/contrib/pg/instrumentation.rb @@ -20,63 +20,66 @@ def self.included(base) # PG::Connection patch methods module InstanceMethods - def exec(sql, *args) - trace(Ext::SPAN_EXEC, sql: sql) do |sql_statement| - super(sql_statement, *args) + def exec(sql, *args, &block) + trace(Ext::SPAN_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, *args, &wrapped_block) end end - def exec_params(sql, params, *args) - trace(Ext::SPAN_EXEC_PARAMS, sql: sql) do |sql_statement| - super(sql_statement, params, *args) + def exec_params(sql, params, *args, &block) + trace(Ext::SPAN_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, params, *args, &wrapped_block) end end - def exec_prepared(statement_name, params, *args) - trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name) do - super(statement_name, params, *args) + def exec_prepared(statement_name, params, *args, &block) + trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block| + super(statement_name, params, *args, &wrapped_block) end end - def async_exec(sql, *args) - trace(Ext::SPAN_ASYNC_EXEC, sql: sql) do |sql_statement| - super(sql_statement, *args) + # async_exec is an alias to exec + def async_exec(sql, *args, &block) + trace(Ext::SPAN_ASYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, *args, &wrapped_block) end end - def async_exec_params(sql, params, *args) - trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql) do |sql_statement| - super(sql_statement, params, *args) + # async_exec_params is an alias to exec_params + def async_exec_params(sql, params, *args, &block) + trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, params, *args, &wrapped_block) end end - def async_exec_prepared(statement_name, params, *args) - trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name) do - super(statement_name, params, *args) + # async_exec_prepared is an alias to exec_prepared + def async_exec_prepared(statement_name, params, *args, &block) + trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block| + super(statement_name, params, *args, &wrapped_block) end end - def sync_exec(sql, *args) - trace(Ext::SPAN_SYNC_EXEC, sql: sql) do |sql_statement| - super(sql_statement, *args) + def sync_exec(sql, *args, &block) + trace(Ext::SPAN_SYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, *args, &wrapped_block) end end - def sync_exec_params(sql, params, *args) - trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql) do |sql_statement| - super(sql_statement, params, *args) + def sync_exec_params(sql, params, *args, &block) + trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block| + super(sql_statement, params, *args, &wrapped_block) end end - def sync_exec_prepared(statement_name, params, *args) - trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name) do - super(statement_name, params, *args) + def sync_exec_prepared(statement_name, params, *args, &block) + trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block| + super(statement_name, params, *args, &wrapped_block) end end private - def trace(name, sql: nil, statement_name: nil) + def trace(name, sql: nil, statement_name: nil, block: nil) service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name] resource = statement_name || sql @@ -101,9 +104,18 @@ def trace(name, sql: nil, statement_name: nil) ) end - result = yield(propagated_sql_statement) - annotate_span_with_result!(span, result) - result + # Read metadata from PG::Result + if block + yield(propagated_sql_statement, proc do |result| + ret = block.call(result) + annotate_span_with_result!(span, result) + ret + end) + else + result = yield(propagated_sql_statement) + annotate_span_with_result!(span, result) + result + end end end @@ -128,6 +140,7 @@ def annotate_span_with_query!(span, service) span.set_tag(Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT, port) end + # @param [PG::Result] result def annotate_span_with_result!(span, result) span.set_tag(Contrib::Ext::DB::TAG_ROW_COUNT, result.ntuples) end From a5a6cdbe53346b2094e66b631086616885948c00 Mon Sep 17 00:00:00 2001 From: Tony Hsu Date: Tue, 24 Jan 2023 11:30:07 +0100 Subject: [PATCH 2/2] Add specs for pg with blocks --- .../tracing/contrib/pg/patcher_spec.rb | 2244 ++++++++++++----- 1 file changed, 1599 insertions(+), 645 deletions(-) diff --git a/spec/datadog/tracing/contrib/pg/patcher_spec.rb b/spec/datadog/tracing/contrib/pg/patcher_spec.rb index f1f49ff29e..6122616318 100644 --- a/spec/datadog/tracing/contrib/pg/patcher_spec.rb +++ b/spec/datadog/tracing/contrib/pg/patcher_spec.rb @@ -52,100 +52,205 @@ describe '#exec' do let(:sql_statement) { 'SELECT 1;' } - subject(:exec) { conn.exec(sql_statement) } + context 'when without a given block' do + subject(:exec) { conn.exec(sql_statement) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when the tracer is disabled' do + before { tracer.enabled = false } - it 'does not write spans' do - exec + it 'does not write spans' do + exec - expect(spans).to be_empty + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' - it 'produces a trace with service override' do - exec + it 'produces a trace with service override' do + exec - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' + + it 'produces a trace' do + exec + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { exec } + let(:peer_hostname) { host } + end - it 'produces a trace' do - exec + it_behaves_like 'measured span for integration', false do + before { exec } + end - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'analytics for integration' do - before { exec } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec', error: PG::Error + + it 'traces failed queries' do + expect { exec }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'a peer service span' do - before { exec } - let(:peer_hostname) { host } + context 'when with a given block' do + subject(:exec) do + conn.exec(sql_statement) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'measured span for integration', false do - before { exec } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + exec + + expect(spans).to be_empty + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_name) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' + + it 'produces a trace with service override' do + exec + + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT INVALID' } + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec' - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec', error: PG::Error + it 'produces a trace' do + exec - it 'traces failed queries' do - expect { exec }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + it_behaves_like 'analytics for integration' do + before { exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { exec } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { exec } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec', error: PG::Error + + it 'traces failed queries' do + expect { exec }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -153,194 +258,410 @@ describe '#exec_params' do let(:sql_statement) { 'SELECT $1::int;' } - subject(:exec_params) { conn.exec_params(sql_statement, [1]) } + context 'when without a given block' do + subject(:exec_params) { conn.exec_params(sql_statement, [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when the tracer is disabled' do + before { tracer.enabled = false } - it 'does not write spans' do - exec_params + it 'does not write spans' do + exec_params - expect(spans).to be_empty + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' - it 'produces a trace with service override' do - exec_params + it 'produces a trace with service override' do + exec_params - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' - it 'produces a trace' do - exec_params + it 'produces a trace' do + exec_params - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PARAMS) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) - end + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - it_behaves_like 'analytics for integration' do - before { exec_params } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + it_behaves_like 'a peer service span' do + before { exec_params } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { exec_params } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'a peer service span' do - before { exec_params } - let(:peer_hostname) { host } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:exec_params) { conn.exec_params(sql_statement, ['INVALID']) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { exec_params }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'measured span for integration', false do - before { exec_params } + context 'when given a block' do + subject(:exec_params) do + conn.exec_params(sql_statement, [1]) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + exec_params + + expect(spans).to be_empty + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT $1;' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - subject(:exec_params) { conn.exec_params(sql_statement, ['INVALID']) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params', error: PG::Error + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' - it 'traces failed queries' do - expect { exec_params }.to raise_error(PG::Error) + it 'produces a trace with service override' do + exec_params - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } - end - end - end + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params' - describe '#exec_prepared' do - before { conn.prepare('prepared select 1', 'SELECT $1::int') } - subject(:exec_prepared) { conn.exec_prepared('prepared select 1', [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + it 'produces a trace' do + exec_params - it 'does not write spans' do - exec_prepared - expect(spans).to be_empty - end - end + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - context 'when the tracer is configured directly' do - let(:service_override) { 'pg-override' } + it_behaves_like 'a peer service span' do + before { exec_params } + let(:peer_hostname) { host } + end - before { Datadog.configure_onto(conn, service_name: service_override) } + it_behaves_like 'measured span for integration', false do + before { exec_params } + end - it 'produces a trace with service override' do - exec_prepared - expect(spans.count).to eq(1) - expect(span.service).to eq(service_override) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - end - context 'when a successful query is made' do - statement_name = 'prepared select 1' - - it 'produces a trace' do - exec_prepared - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PREPARED) - expect(span.resource).to eq(statement_name) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) - end - - it_behaves_like 'analytics for integration' do - before { exec_prepared } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } - end - - it_behaves_like 'a peer service span' do - before { exec_prepared } - let(:peer_hostname) { host } - end - - it_behaves_like 'measured span for integration', false do - before { exec_prepared } - end - - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:exec_params) do + conn.exec_params(sql_statement, ['INVALID']) do |_pg_result| + # Do something with PG::Result + end + end + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { exec_params }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end + end - context 'when a failed query is made' do - it 'traces failed queries' do - expect { conn.exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message( - include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') - ) + describe '#exec_prepared' do + before { conn.prepare('prepared select 1', 'SELECT $1::int') } + + context 'when without a given block' do + subject(:exec_prepared) { conn.exec_prepared('prepared select 1', [1]) } + + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + it 'traces failed queries' do + expect { conn.exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + subject { conn.exec_prepared('invalid prepared select 1', ['INVALID']) } + end end + end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } - subject { conn.exec_prepared('invalid prepared select 1', ['INVALID']) } + context 'when given a block' do + subject(:exec_prepared) do + conn.exec_prepared('prepared select 1', [1]) do |_pg_result| + # Do something with PG::Result + end + end + + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + subject(:exec_prepared) do + conn.exec_prepared('invalid prepared select 1', ['INVALID']) do |_pg_result| + # Do something with PG::Result + end + end + + it 'traces failed queries' do + expect { exec_prepared }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -348,101 +669,211 @@ describe '#async_exec' do let(:sql_statement) { 'SELECT 1;' } - subject(:async_exec) { conn.async_exec(sql_statement) } + context 'when without given block' do + subject(:async_exec) { conn.async_exec(sql_statement) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when the tracer is disabled' do + before { tracer.enabled = false } - it 'does not write spans' do - async_exec + it 'does not write spans' do + async_exec - expect(spans).to be_empty + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' - it 'produces a trace with service override' do - async_exec + it 'produces a trace with service override' do + async_exec - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' + + it 'produces a trace' do + async_exec - it 'produces a trace' do - async_exec + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + it_behaves_like 'analytics for integration' do + before { async_exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { async_exec } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { async_exec } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'analytics for integration' do - before { async_exec } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + subject(:async_exec) { conn.async_exec(sql_statement) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec', error: PG::Error + + it 'traces failed queries' do + expect { async_exec }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'a peer service span' do - before { async_exec } - let(:peer_hostname) { host } + context 'when given a block' do + subject(:async_exec) do + conn.async_exec(sql_statement) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'measured span for integration', false do - before { async_exec } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + async_exec + + expect(spans).to be_empty + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_name) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' + + it 'produces a trace with service override' do + async_exec + + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT INVALID' } + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec' - subject(:async_exec) { conn.async_exec(sql_statement) } + it 'produces a trace' do + async_exec - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec', error: PG::Error + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - it 'traces failed queries' do - expect { async_exec }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + it_behaves_like 'analytics for integration' do + before { async_exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { async_exec } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { async_exec } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + subject(:async_exec) do + conn.async_exec(sql_statement) do |_pg_result| + # Do something with PG::Result + end + end + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec', error: PG::Error + + it 'traces failed queries' do + expect { async_exec }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -454,101 +885,207 @@ let(:sql_statement) { 'SELECT $1::int;' } - subject(:async_exec_params) { conn.async_exec_params(sql_statement, [1]) } + context 'when without given a block' do + subject(:async_exec_params) { conn.async_exec_params(sql_statement, [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when the tracer is disabled' do + before { tracer.enabled = false } - it 'does not write spans' do - async_exec_params + it 'does not write spans' do + async_exec_params - expect(spans).to be_empty + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' - it 'produces a trace with service override' do - async_exec_params + it 'produces a trace with service override' do + async_exec_params - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' + + it 'produces a trace' do + async_exec_params + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { async_exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - it 'produces a trace' do - async_exec_params + it_behaves_like 'a peer service span' do + before { async_exec_params } + let(:peer_hostname) { host } + end - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PARAMS) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + it_behaves_like 'measured span for integration', false do + before { async_exec_params } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'analytics for integration' do - before { async_exec_params } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:async_exec_params) { conn.async_exec_params(sql_statement, ['INVALID']) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { async_exec_params }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'a peer service span' do - before { async_exec_params } - let(:peer_hostname) { host } + context 'when given a block' do + subject(:async_exec_params) do + conn.async_exec_params(sql_statement, [1]) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'measured span for integration', false do - before { async_exec_params } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + async_exec_params + + expect(spans).to be_empty + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_name) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' + + it 'produces a trace with service override' do + async_exec_params + + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT $1;' } + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params' + + it 'produces a trace' do + async_exec_params + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - subject(:async_exec_params) { conn.async_exec_params(sql_statement, ['INVALID']) } + it_behaves_like 'analytics for integration' do + before { async_exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params', error: PG::Error + it_behaves_like 'a peer service span' do + before { async_exec_params } + let(:peer_hostname) { host } + end - it 'traces failed queries' do - expect { async_exec_params }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + it_behaves_like 'measured span for integration', false do + before { async_exec_params } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:async_exec_params) { conn.async_exec_params(sql_statement, ['INVALID']) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.async.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { async_exec_params }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -560,92 +1097,196 @@ end conn.prepare('prepared select 1', 'SELECT $1::int') end - subject(:async_exec_prepared) { conn.async_exec_prepared('prepared select 1', [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } - it 'does not write spans' do - async_exec_prepared - expect(spans).to be_empty + context 'when without given block' do + subject(:async_exec_prepared) { conn.async_exec_prepared('prepared select 1', [1]) } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + async_exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + async_exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + async_exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { async_exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { async_exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { async_exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + it 'traces failed queries' do + expect { conn.async_exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + subject { conn.async_exec_prepared('invalid prepared select 1', ['INVALID']) } + end end end - context 'when the tracer is configured directly' do - let(:service_override) { 'pg-override' } - - before { Datadog.configure_onto(conn, service_name: service_override) } - - it 'produces a trace with service override' do - async_exec_prepared - expect(spans.count).to eq(1) - expect(span.service).to eq(service_override) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) - end - end - - context 'when a successful query is made' do - statement_name = 'prepared select 1' - - it 'produces a trace' do - async_exec_prepared - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PREPARED) - expect(span.resource).to eq(statement_name) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) - end - - it_behaves_like 'analytics for integration' do - before { async_exec_prepared } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } - end - - it_behaves_like 'a peer service span' do - before { async_exec_prepared } - let(:peer_hostname) { host } - end - - it_behaves_like 'measured span for integration', false do - before { async_exec_prepared } - end - - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } - end - end - - context 'when a failed query is made' do - it 'traces failed queries' do - expect { conn.async_exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message( - include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') - ) - end - - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } - subject { conn.async_exec_prepared('invalid prepared select 1', ['INVALID']) } + context 'when given a block' do + subject(:async_exec_prepared) do + conn.async_exec_prepared('prepared select 1', [1]) do |_pg_result| + # Do something with PG::Result + end + end + + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + async_exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + async_exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + async_exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_ASYNC_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { async_exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { async_exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { async_exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + subject(:async_exec_prepared) do + conn.async_exec_prepared('invalid prepared select 1', ['INVALID']) do |_pg_result| + # Do something with PG::Result + end + end + + it 'traces failed queries' do + expect { async_exec_prepared }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -659,99 +1300,203 @@ let(:sql_statement) { 'SELECT 1;' } - subject(:sync_exec) { conn.sync_exec(sql_statement) } + context 'when without a given block' do + subject(:sync_exec) { conn.sync_exec(sql_statement) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when the tracer is disabled' do + before { tracer.enabled = false } - it 'does not write spans' do - sync_exec + it 'does not write spans' do + sync_exec - expect(spans).to be_empty + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' - it 'produces a trace with service override' do - sync_exec + it 'produces a trace with service override' do + sync_exec - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' + + it 'produces a trace' do + sync_exec + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - it 'produces a trace' do - sync_exec + it_behaves_like 'analytics for integration' do + before { sync_exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + it_behaves_like 'a peer service span' do + before { sync_exec } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { sync_exec } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'analytics for integration' do - before { sync_exec } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec', error: PG::Error + + it 'traces failed queries' do + expect { sync_exec }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'a peer service span' do - before { sync_exec } - let(:peer_hostname) { host } + context 'when given a block' do + subject(:sync_exec) do + conn.sync_exec(sql_statement) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'measured span for integration', false do - before { sync_exec } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + sync_exec + + expect(spans).to be_empty + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_name) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' + + it 'produces a trace with service override' do + sync_exec + + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT INVALID' } + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec' + + it 'produces a trace' do + sync_exec + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { sync_exec } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { sync_exec } + let(:peer_hostname) { host } + end - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec', error: PG::Error + it_behaves_like 'measured span for integration', false do + before { sync_exec } + end - it 'traces failed queries' do - expect { sync_exec }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT INVALID' } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec', error: PG::Error + + it 'traces failed queries' do + expect { sync_exec }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('column "invalid" does not exist')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -762,100 +1507,206 @@ end let(:sql_statement) { 'SELECT $1::int;' } - subject(:sync_exec_params) { conn.sync_exec_params(sql_statement, [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } + context 'when without given block' do + subject(:sync_exec_params) { conn.sync_exec_params(sql_statement, [1]) } - it 'does not write spans' do - sync_exec_params - expect(spans).to be_empty + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + sync_exec_params + expect(spans).to be_empty + end end - end - context 'when the tracer is configured directly' do - let(:service_name) { 'pg-override' } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } - before { Datadog.configure_onto(conn, service_name: service_name) } + before { Datadog.configure_onto(conn, service_name: service_name) } - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' - it 'produces a trace with service override' do - sync_exec_params - expect(spans.count).to eq(1) - expect(span.service).to eq(service_name) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + it 'produces a trace with service override' do + sync_exec_params + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a successful query is made' do - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' + + it 'produces a trace' do + sync_exec_params + + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - it 'produces a trace' do - sync_exec_params + it_behaves_like 'analytics for integration' do + before { sync_exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PARAMS) - expect(span.resource).to eq(sql_statement) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + it_behaves_like 'a peer service span' do + before { sync_exec_params } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { sync_exec_params } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'analytics for integration' do - before { sync_exec_params } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:sync_exec_params) { conn.sync_exec_params(sql_statement, ['INVALID']) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { sync_exec_params }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end + end - it_behaves_like 'a peer service span' do - before { sync_exec_params } - let(:peer_hostname) { host } + context 'when given a block' do + subject(:sync_exec_params) do + conn.sync_exec_params(sql_statement, [1]) do |_pg_result| + # Do something with PG::Result + end end - it_behaves_like 'measured span for integration', false do - before { sync_exec_params } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + sync_exec_params + expect(spans).to be_empty + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } + context 'when the tracer is configured directly' do + let(:service_name) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_name) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' + + it 'produces a trace with service override' do + sync_exec_params + expect(spans.count).to eq(1) + expect(span.service).to eq(service_name) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_name) + end end - end - context 'when a failed query is made' do - let(:sql_statement) { 'SELECT $1;' } + context 'when a successful query is made' do + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params' + + it 'produces a trace' do + sync_exec_params - subject(:sync_exec_params) { conn.sync_exec_params(sql_statement, ['INVALID']) } + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PARAMS) + expect(span.resource).to eq(sql_statement) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end - it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params', error: PG::Error + it_behaves_like 'analytics for integration' do + before { sync_exec_params } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end - it 'traces failed queries' do - expect { sync_exec_params }.to raise_error(PG::Error) + it_behaves_like 'a peer service span' do + before { sync_exec_params } + let(:peer_hostname) { host } + end - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + it_behaves_like 'measured span for integration', false do + before { sync_exec_params } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end end - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } + context 'when a failed query is made' do + let(:sql_statement) { 'SELECT $1;' } + + subject(:sync_exec_params) { conn.sync_exec_params(sql_statement, ['INVALID']) } + + it_behaves_like 'with sql comment propagation', span_op_name: 'pg.sync.exec.params', error: PG::Error + + it 'traces failed queries' do + expect { sync_exec_params }.to raise_error(PG::Error) + + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message(include('ERROR') & include('could not determine data type of parameter $1')) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end @@ -865,92 +1716,195 @@ skip('pg < 1.1.0 does not support #sync_exec_prepared') if Gem::Version.new(PG::VERSION) < Gem::Version.new('1.1.0') conn.prepare('prepared select 1', 'SELECT $1::int') end - subject(:sync_exec_prepared) { conn.sync_exec_prepared('prepared select 1', [1]) } - context 'when the tracer is disabled' do - before { tracer.enabled = false } - - it 'does not write spans' do - sync_exec_prepared - expect(spans).to be_empty - end - end - - context 'when the tracer is configured directly' do - let(:service_override) { 'pg-override' } - - before { Datadog.configure_onto(conn, service_name: service_override) } - it 'produces a trace with service override' do - sync_exec_prepared - expect(spans.count).to eq(1) - expect(span.service).to eq(service_override) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + context 'when without a given block' do + subject(:sync_exec_prepared) { conn.sync_exec_prepared('prepared select 1', [1]) } + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + sync_exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + sync_exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + sync_exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { sync_exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { sync_exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { sync_exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + it 'traces failed queries' do + expect { conn.sync_exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + subject { conn.sync_exec_prepared('invalid prepared select 1', ['INVALID']) } + end end end - context 'when a successful query is made' do - statement_name = 'prepared select 1' - - it 'produces a trace' do - sync_exec_prepared - expect(spans.count).to eq(1) - expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PREPARED) - expect(span.resource).to eq(statement_name) - expect(span.service).to eq('pg') - expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) - .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) - expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) - .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) - expect(span.get_tag('db.system')).to eq('postgresql') - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) - expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) - expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) - end - - it_behaves_like 'analytics for integration' do - before { sync_exec_prepared } - let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } - let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } - end - - it_behaves_like 'a peer service span' do - before { sync_exec_prepared } - let(:peer_hostname) { host } - end - - it_behaves_like 'measured span for integration', false do - before { sync_exec_prepared } - end - - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do - let(:configuration_options) { {} } - end - end - - context 'when a failed query is made' do - it 'traces failed queries' do - expect { conn.sync_exec_prepared('invalid prepared select 1', ['INVALID']) }.to raise_error(PG::Error) - expect(spans.count).to eq(1) - expect(span).to have_error - expect(span).to have_error_message( - include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') - ) - end - - it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do - let(:configuration_options) { {} } - subject { conn.sync_exec_prepared('invalid prepared select 1', ['INVALID']) } + context 'when given a block' do + subject(:sync_exec_prepared) do + conn.sync_exec_prepared('prepared select 1', [1]) do |_pg_result| + # Do something with PG::Result + end + end + context 'when the tracer is disabled' do + before { tracer.enabled = false } + + it 'does not write spans' do + sync_exec_prepared + expect(spans).to be_empty + end + end + + context 'when the tracer is configured directly' do + let(:service_override) { 'pg-override' } + + before { Datadog.configure_onto(conn, service_name: service_override) } + + it 'produces a trace with service override' do + sync_exec_prepared + expect(spans.count).to eq(1) + expect(span.service).to eq(service_override) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)).to eq(service_override) + end + end + + context 'when a successful query is made' do + statement_name = 'prepared select 1' + + it 'produces a trace' do + sync_exec_prepared + expect(spans.count).to eq(1) + expect(span.name).to eq(Datadog::Tracing::Contrib::Pg::Ext::SPAN_SYNC_EXEC_PREPARED) + expect(span.resource).to eq(statement_name) + expect(span.service).to eq('pg') + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::SQL::TYPE) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_KIND)) + .to eq(Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT) + expect(span.get_tag(Datadog::Tracing::Contrib::Pg::Ext::TAG_DB_NAME)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_COMPONENT) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::TAG_OPERATION_QUERY) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE)) + .to eq(Datadog::Tracing::Contrib::Pg::Ext::DEFAULT_PEER_SERVICE_NAME) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_INSTANCE)).to eq(dbname) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_USER)).to eq(user) + expect(span.get_tag('db.system')).to eq('postgresql') + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_NAME)).to eq(host) + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::NET::TAG_DESTINATION_PORT)).to eq(port.to_i) + expect(span.get_tag(Datadog::Tracing::Contrib::Ext::DB::TAG_ROW_COUNT)).to eq(1) + end + + it_behaves_like 'analytics for integration' do + before { sync_exec_prepared } + let(:analytics_enabled_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_ENABLED } + let(:analytics_sample_rate_var) { Datadog::Tracing::Contrib::Pg::Ext::ENV_ANALYTICS_SAMPLE_RATE } + end + + it_behaves_like 'a peer service span' do + before { sync_exec_prepared } + let(:peer_hostname) { host } + end + + it_behaves_like 'measured span for integration', false do + before { sync_exec_prepared } + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME' do + let(:configuration_options) { {} } + end + end + + context 'when a failed query is made' do + subject(:sync_exec_prepared) do + conn.sync_exec_prepared('invalid prepared select 1', ['INVALID']) do |_pg_result| + # Do something with PG::Result + end + end + + it 'traces failed queries' do + expect { sync_exec_prepared }.to raise_error(PG::Error) + expect(spans.count).to eq(1) + expect(span).to have_error + expect(span).to have_error_message( + include('ERROR') & include('prepared statement "invalid prepared select 1" does not exist') + ) + end + + it_behaves_like 'environment service name', 'DD_TRACE_PG_SERVICE_NAME', error: PG::Error do + let(:configuration_options) { {} } + end end end end