From c534781397606e01c2c97faff1852d9e0be7bdf0 Mon Sep 17 00:00:00 2001 From: Loic Nageleisen Date: Thu, 14 Apr 2022 18:20:15 +0200 Subject: [PATCH] Move user attribution API to Datadog::Kit::Identity --- lib/datadog/kit.rb | 9 +++++ lib/datadog/kit/identity.rb | 36 ++++++++++++++++++++ lib/datadog/tracing/trace_operation.rb | 28 --------------- lib/ddtrace.rb | 1 + spec/datadog/kit/identity_spec.rb | 34 ++++++++++++++++++ spec/datadog/tracing/trace_operation_spec.rb | 22 ------------ 6 files changed, 80 insertions(+), 50 deletions(-) create mode 100644 lib/datadog/kit.rb create mode 100644 lib/datadog/kit/identity.rb create mode 100644 spec/datadog/kit/identity_spec.rb diff --git a/lib/datadog/kit.rb b/lib/datadog/kit.rb new file mode 100644 index 00000000000..201c144f667 --- /dev/null +++ b/lib/datadog/kit.rb @@ -0,0 +1,9 @@ +# typed: false + +module Datadog + # Namespace for Datadog Kit + module Kit + end +end + +require 'datadog/kit/identity' diff --git a/lib/datadog/kit/identity.rb b/lib/datadog/kit/identity.rb new file mode 100644 index 00000000000..ceeab5a2e7f --- /dev/null +++ b/lib/datadog/kit/identity.rb @@ -0,0 +1,36 @@ +# typed: false + +module Datadog + module Kit + # Tracking identity via traces + module Identity + # Attach user information to the trace + # + # Values must be strings. Keys are free form, although the following keys have specific meanings: + # - id: Mandatory. Username or client id extracted from the access token or + # Authorization header in the inbound request from outside the system. + # - email: Email of the authenticated user associated to the trace. + # - name: User-friendly name. To be displayed in the UI if set. + # - session_id: Session ID of the authenticated user. + # - role: Actual/assumed role the client is making the request under + # extracted from token or application security context. + # - scope: Scopes or granted authorities the client currently possesses + # extracted from token or application security context. The value would + # come from the scope associated with an OAuth 2.0 Access Token or an + # attribute value in a SAML 2.0 Assertion. + def self.set_user(trace, data = {}) + raise ArgumentError, 'missing required key: :id' unless data[:id] + + # enforce types + data.each do |k, v| + raise TypeError, "#{k.inspect} must be a String" unless v.is_a?(String) + end + + # set tags once data is made consistent + data.each do |k, v| # rubocop:disable Style/CombinableLoops + trace.set_tag("usr.#{k}", v) + end + end + end + end +end diff --git a/lib/datadog/tracing/trace_operation.rb b/lib/datadog/tracing/trace_operation.rb index 665c521ff3c..8bdcd39ffd8 100644 --- a/lib/datadog/tracing/trace_operation.rb +++ b/lib/datadog/tracing/trace_operation.rb @@ -128,34 +128,6 @@ def reject! self.sampling_priority = Sampling::Ext::Priority::USER_REJECT end - # Attach user information to the trace - # - # Values must be strings. Keys are free form, although the following keys have specific meanings: - # - id: Mandatory. Username or client id extracted from the access token or - # Authorization header in the inbound request from outside the system. - # - email: Email of the authenticated user associated to the trace. - # - name: User-friendly name. To be displayed in the UI if set. - # - session_id: Session ID of the authenticated user. - # - role: Actual/assumed role the client is making the request under - # extracted from token or application security context. - # - scope: Scopes or granted authorities the client currently possesses - # extracted from token or application security context. The value would - # come from the scope associated with an OAuth 2.0 Access Token or an - # attribute value in a SAML 2.0 Assertion. - def set_user(data = {}) - raise ArgumentError, 'missing required key: :id' unless data[:id] - - # enforce types - data.each do |k, v| - raise TypeError, "#{k.inspect} must be a String" unless v.is_a?(String) - end - - # set tags once data is made consistent - data.each do |k, v| # rubocop:disable Style/CombinableLoops - set_tag("usr.#{k}", v) - end - end - def measure( op_name, events: nil, diff --git a/lib/ddtrace.rb b/lib/ddtrace.rb index 4e1679aaeb1..42966595abf 100644 --- a/lib/ddtrace.rb +++ b/lib/ddtrace.rb @@ -10,3 +10,4 @@ # Load other products (must follow tracing) require 'datadog/profiling' require 'datadog/ci' +require 'datadog/kit' diff --git a/spec/datadog/kit/identity_spec.rb b/spec/datadog/kit/identity_spec.rb new file mode 100644 index 00000000000..2668f546702 --- /dev/null +++ b/spec/datadog/kit/identity_spec.rb @@ -0,0 +1,34 @@ +# typed: ignore + +require 'spec_helper' + +require 'time' + +require 'datadog/tracing/trace_operation' +require 'datadog/kit/identity' + +RSpec.describe Datadog::Kit::Identity do + subject(:trace_op) { Datadog::Tracing::TraceOperation.new } + + describe '#set_user' do + it 'sets user on trace' do + trace_op.measure('root') do + described_class.set_user(trace_op, id: '42') + end + trace = trace_op.flush! + expect(trace.send(:meta)).to include('usr.id' => '42') + end + + it 'enforces :id presence' do + trace_op.measure('root') do + expect { described_class.set_user(trace_op, foo: 'bar') }.to raise_error(ArgumentError) + end + end + + it 'enforces String values' do + trace_op.measure('root') do + expect { described_class.set_user(trace_op, id: 42) }.to raise_error(TypeError) + end + end + end +end diff --git a/spec/datadog/tracing/trace_operation_spec.rb b/spec/datadog/tracing/trace_operation_spec.rb index 07daf2a33ea..dda4ee98d64 100644 --- a/spec/datadog/tracing/trace_operation_spec.rb +++ b/spec/datadog/tracing/trace_operation_spec.rb @@ -902,28 +902,6 @@ end end - describe '#set_user' do - it 'sets user on trace' do - trace_op.measure('root') do - trace_op.set_user(id: '42') - end - trace = trace_op.flush! - expect(trace.tags).to include('usr.id' => '42') - end - - it 'enforces :id presence' do - trace_op.measure('root') do - expect { trace_op.set_user(foo: 'bar') }.to raise_error(ArgumentError) - end - end - - it 'enforces String values' do - trace_op.measure('root') do - expect { trace_op.set_user(id: 42) }.to raise_error(TypeError) - end - end - end - describe '#build_span' do subject(:build_span) { trace_op.build_span(span_name, **span_options) } let(:span_name) { 'web.request' }