Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Transaction and Span classes. #1653

Merged
merged 3 commits into from
Dec 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ When `config.send_default_pii` is set as `true`, `:http_logger` will include que
- Fix `Net::HTTP` breadcrump url when using `Net::HTTP.new` [#1637](https://github.com/getsentry/sentry-ruby/pull/1637)
- Fix trace span creation when using `Net::HTTP.start` [#1637](https://github.com/getsentry/sentry-ruby/pull/1637)

### Documentation

- Rewrite documents with yard [#1635](https://github.com/getsentry/sentry-ruby/pull/1635)
- Document Transaction and Span classes [#1653](https://github.com/getsentry/sentry-ruby/pull/1653)

### Refactoring

- Minor improvements on Net::HTTP patch [#1651](https://github.com/getsentry/sentry-ruby/pull/1651)
Expand Down
91 changes: 83 additions & 8 deletions sentry-ruby/lib/sentry/span.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,49 @@ class Span
504 => "deadline_exceeded"
}


attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
attr_accessor :span_recorder, :transaction
# An uuid that can be used to identify a trace.
# @return [String]
attr_reader :trace_id
# An uuid that can be used to identify the span.
# @return [String]
attr_reader :span_id
# Span parent's span_id.
# @return [String]
attr_reader :parent_span_id
# Sampling result of the span.
# @return [Boolean, nil]
attr_reader :sampled
# Starting timestamp of the span.
# @return [Float]
attr_reader :start_timestamp
# Finishing timestamp of the span.
# @return [Float]
attr_reader :timestamp
# Span description
# @return [String]
attr_reader :description
# Span operation
# @return [String]
attr_reader :op
# Span status
# @return [String]
attr_reader :status
# Span tags
# @return [Hash]
attr_reader :tags
# Span data
# @return [Hash]
attr_reader :data

# The SpanRecorder the current span belongs to.
# SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
# @return [SpanRecorder]
attr_accessor :span_recorder

# The Transaction object the Span belongs to.
# Every span needs to be attached to a Transaction and their child spans will also inherit the same transaction.
# @return [Transaction]
attr_accessor :transaction

def initialize(
description: nil,
Expand All @@ -45,6 +85,8 @@ def initialize(
@tags = {}
end

# Finishes the span by adding a timestamp.
# @return [self]
def finish
# already finished
return if @timestamp
Expand All @@ -53,13 +95,16 @@ def finish
self
end

# Generates a trace string that can be used to connect other transactions.
# @return [String]
def to_sentry_trace
sampled_flag = ""
sampled_flag = @sampled ? 1 : 0 unless @sampled.nil?

"#{@trace_id}-#{@span_id}-#{sampled_flag}"
end

# @return [Hash]
def to_hash
{
trace_id: @trace_id,
Expand All @@ -75,6 +120,8 @@ def to_hash
}
end

# Returns the span's context that can be used to embed in an Event.
# @return [Hash]
def get_trace_context
{
trace_id: @trace_id,
Expand All @@ -86,9 +133,11 @@ def get_trace_context
}
end

def start_child(**options)
options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
new_span = Span.new(**options)
# Starts a child span with given attributes.
# @param attributes [Hash] the attributes for the child span.
def start_child(**attributes)
attributes = attributes.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
new_span = Span.new(**attributes)
new_span.transaction = transaction
new_span.span_recorder = span_recorder

Expand All @@ -99,8 +148,17 @@ def start_child(**options)
new_span
end

def with_child_span(**options, &block)
child_span = start_child(**options)
# Starts a child span, yield it to the given block, and then finish the span after the block is executed.
# @example
# span.with_child_span do |child_span|
# # things happen here will be recorded in a child span
# end
#
# @param attributes [Hash] the attributes for the child span.
# @param block [Proc] the action to be recorded in the child span.
# @yieldparam child_span [Span]
def with_child_span(**attributes, &block)
child_span = start_child(**attributes)

yield(child_span)

Expand All @@ -111,22 +169,33 @@ def deep_dup
dup
end

# Sets the span's operation.
# @param op [String] operation of the span.
def set_op(op)
@op = op
end

# Sets the span's description.
# @param description [String] description of the span.
def set_description(description)
@description = description
end


# Sets the span's status.
# @param satus [String] status of the span.
def set_status(status)
@status = status
end

# Sets the span's finish timestamp.
# @param timestamp [Float] finished time in float format (most precise).
def set_timestamp(timestamp)
@timestamp = timestamp
end

# Sets the span's status with given http status code.
# @param status_code [String] example: "500".
def set_http_status(status_code)
status_code = status_code.to_i
set_data("status_code", status_code)
Expand All @@ -140,10 +209,16 @@ def set_http_status(status_code)
set_status(status)
end

# Inserts a key-value pair to the span's data payload.
# @param key [String, Symbol]
# @param value [Object]
def set_data(key, value)
@data[key] = value
end

# Sets a tag to the span.
# @param key [String, Symbol]
# @param value [String]
def set_tag(key, value)
@tags[key] = value
end
Expand Down
25 changes: 24 additions & 1 deletion sentry-ruby/lib/sentry/transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ class Transaction < Span

include LoggingHelper

attr_reader :name, :parent_sampled
# The name of the transaction.
# @return [String]
attr_reader :name

# The sampling decision of the parent transaction, which will be considered when making the current transaction's sampling decision.
# @return [String]
attr_reader :parent_sampled

# @deprecated Use Sentry.get_current_hub instead.
attr_reader :hub
Expand All @@ -40,6 +46,15 @@ def initialize(name: nil, parent_sampled: nil, hub:, **options)
init_span_recorder
end

# Initalizes a Transaction instance with a Sentry trace string from another transaction (usually from an external request).
#
# The original transaction will become the parent of the new Transaction instance. And they will share the same `trace_id`.
#
# The child transaction will also store the parent's sampling decision in its `parent_sampled` attribute.
# @param sentry_trace [String] the trace string from the previous transaction.
# @param hub [Hub] the hub that'll be responsible for sending this transaction when it's finished.
# @param options [Hash] the options you want to use to initialize a Transaction instance.
# @return [Transaction, nil]
def self.from_sentry_trace(sentry_trace, hub: Sentry.get_current_hub, **options)
return unless hub.configuration.tracing_enabled?
return unless sentry_trace
Expand All @@ -58,12 +73,14 @@ def self.from_sentry_trace(sentry_trace, hub: Sentry.get_current_hub, **options)
new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, hub: hub, **options)
end

# @return [Hash]
def to_hash
hash = super
hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
hash
end

# @return [Transaction]
def deep_dup
copy = super
copy.init_span_recorder(@span_recorder.max_length)
Expand All @@ -77,6 +94,9 @@ def deep_dup
copy
end

# Sets initial sampling decision of the transaction.
# @param sampling_context [Hash] a context Hash that'll be passed to `traces_sampler` (if provided).
# @return [void]
def set_initial_sample_decision(sampling_context:)
unless @tracing_enabled
@sampled = false
Expand Down Expand Up @@ -123,6 +143,9 @@ def set_initial_sample_decision(sampling_context:)
end
end

# Finishes the transaction's recording and send it to Sentry.
# @param hub [Hub] the hub that'll send this transaction. (Deprecated)
# @return [TransactionEvent]
def finish(hub: nil)
if hub
log_warn(
Expand Down