File: tracing_utils.rb

package info (click to toggle)
ruby-gitlab-labkit 0.36.1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 444 kB
  • sloc: ruby: 1,705; makefile: 6
file content (82 lines) | stat: -rw-r--r-- 2,767 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# frozen_string_literal: true

require "active_support/core_ext/string/starts_ends_with"
require "opentracing"

module Labkit
  module Tracing
    # Internal methods for tracing. This is not part of the LabKit public API.
    # For internal usage only
    class TracingUtils
      # Convience method for running a block with a span
      def self.with_tracing(operation_name:, tags:, child_of: nil)
        scope = tracer.start_active_span(operation_name, child_of: child_of, tags: tags)
        span = scope.span

        log_common_fields_on_span(span, operation_name)

        begin
          yield span
        rescue StandardError => e
          log_exception_on_span(span, e)
          raise e
        ensure
          scope.close
        end
      end

      # Obtain a tracer instance
      def self.tracer
        OpenTracing.global_tracer
      end

      # Generate a span retrospectively
      def self.postnotify_span(operation_name, start_time, end_time, tags: nil, child_of: nil, exception: nil)
        span = OpenTracing.start_span(operation_name, start_time: start_time, tags: tags, child_of: child_of)

        log_common_fields_on_span(span, operation_name)
        log_exception_on_span(span, exception) if exception

        span.finish(end_time: end_time)
      end

      # Add common fields to a span
      def self.log_common_fields_on_span(span, operation_name)
        correlation_id = Labkit::Correlation::CorrelationId.current_id
        span.set_tag("correlation_id", correlation_id) if correlation_id
        span.log_kv(stack: caller.join('\n')) if include_stacktrace?(operation_name)
      end

      # Add exception logging to a span
      def self.log_exception_on_span(span, exception)
        return if exception.blank?

        span.set_tag("error", true)
        span.log_kv(**kv_tags_for_exception(exception))
      end

      # Generate key-value tags for an exception
      def self.kv_tags_for_exception(exception)
        case exception
        when Exception
          {
            :"event" => "error",
            :"error.kind" => exception.class.to_s,
            :"message" => Labkit::Logging::Sanitizer.sanitize_field(exception.message),
            :"stack" => exception.backtrace&.join('\n'),
          }
        else
          { :"event" => "error", :"error.kind" => exception.class.to_s, :"error.object" => Labkit::Logging::Sanitizer.sanitize_field(exception.to_s) }
        end
      end

      def self.include_stacktrace?(operation_name)
        @include_stacktrace ||= Hash.new do |result, name|
          result[name] = Tracing.stacktrace_operations.any? { |stacktrace_operation| name.starts_with?(stacktrace_operation) }
        end

        @include_stacktrace[operation_name]
      end
    end
  end
end