Verified Commit 9ec9ac27 authored by Hercules Merscher's avatar Hercules Merscher 🌴
Browse files

feat: Expose concrete tracer implementation

parent ee176c11
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -77,6 +77,23 @@ module Labkit
        .gsub("{{ service }}", service_name)
    end

    # Returns the underlying tracer implementation from the tracing library in use.
    # This provides direct access to the native tracer API when LabKit's abstraction
    # is insufficient for advanced use cases.
    #
    # @example Using OpenTelemetry-specific APIs
    #   tracer = Labkit::Tracing.tracer
    #   tracer.start_span("custom-span") do |span|
    #     span.add_event("custom-event", attributes: { "key" => "value" })
    #   end
    #
    # @return [Object] The tracer implementation:
    #   - OpenTelemetry::SDK::Trace::Tracer when using OTLP connection
    #   - No-op tracer when tracing is not configured
    def self.tracer
      TracingUtils.tracer.tracer
    end

    # This will run a block with a span
    # @param operation_name [String] The operation name for the span
    # @param tags [Hash] Tags to assign to the span
+26 −0
Original line number Diff line number Diff line
@@ -287,6 +287,32 @@ if Labkit::Tracing.sampled?
end
```

### Direct Access to Underlying Tracer

When LabKit's abstraction doesn't provide the functionality you need, you can access the underlying tracer implementation directly using `Labkit::Tracing.tracer`:

```ruby
# Access the native tracer API
tracer = Labkit::Tracing.tracer

# Use OpenTelemetry-specific features when using OTLP connection
if Labkit::Tracing.otlp_connection?
  # tracer is an OpenTelemetry::SDK::Trace::Tracer instance
  tracer.start_span("custom-operation") do |span|
    span.add_event("processing_started", attributes: { "batch_size" => 100 })

    # Use OpenTelemetry-specific APIs
    span.record_exception(StandardError.new("test"))
    span.status = OpenTelemetry::Trace::Status.error("Failed")
  end
end

This is useful when you need:
- Library-specific APIs not exposed by LabKit (e.g., OpenTelemetry events)
- Advanced span manipulation or custom exporters
- Direct integration with third-party libraries that expect native tracer instances


## Instrumentation

### Rack Middleware
+43 −0
Original line number Diff line number Diff line
@@ -144,6 +144,49 @@ describe Labkit::Tracing do
    end
  end

  describe ".tracer" do
    context "when using OpenTelemetry" do
      before do
        stub_const("ENV", ENV.to_hash.merge("GITLAB_TRACING" => "otlp://localhost:4318"))
        Labkit::Tracing::TracingUtils.instance_variable_set(:@tracer, nil)
      end

      it "returns the OpenTelemetry tracer" do
        tracer = described_class.tracer

        expect(tracer).to be_a(OpenTelemetry::Trace::Tracer)
      end
    end

    context "when using OpenTracing" do
      before do
        stub_const("ENV", ENV.to_hash.merge("GITLAB_TRACING" => "opentracing://jaeger"))
        Labkit::Tracing::TracingUtils.instance_variable_set(:@tracer, nil)
      end

      it "returns the OpenTracing global tracer" do
        tracer = described_class.tracer

        expect(tracer).to respond_to(:start_span)
        expect(tracer).to respond_to(:inject)
        expect(tracer).to respond_to(:extract)
      end
    end

    context "when tracing is not configured" do
      before do
        stub_const("ENV", ENV.to_hash.merge("GITLAB_TRACING" => nil))
        Labkit::Tracing::TracingUtils.instance_variable_set(:@tracer, nil)
      end

      it "returns a no-op tracer" do
        tracer = described_class.tracer

        expect(tracer).not_to be_nil
      end
    end
  end

  describe ".stacktrace_operations" do
    before do
      Labkit::Tracing.instance_variable_set(:@stacktrace_operations, nil)