Skip to content

Commit

Permalink
feat: Add preconfigured support for Smart Agent
Browse files Browse the repository at this point in the history
  • Loading branch information
jtmalinowski committed Aug 24, 2022
1 parent 70ba63a commit 29418cf
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 17 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ end
```

And add the middleware in `Rack::Builder`:

``` ruby
Rack::Builder.app do
use OpenTelemetry::Instrumentation::Rack::Middlewares::TracerMiddleware
Expand All @@ -227,6 +227,14 @@ To disable the response headers being added the environment variable
`SPLUNK_TRACE_RESPONSE_HEADER_ENABLED` can be set to `false`, or pass
`trace_response_header_enabled: false` to `Splunk::Otel.configure`.

## Configure for use with Smart Agent

This distribution includes the `jaeger-thrift-splunk` exporter, which is preconfigured to send data to local instance of the [SignalFx Smart Agent](https://github.com/signalfx/signalfx-agent).

To use the `jaeger-thrift-splunk` exporter, set the`OTEL_TRACES_EXPORTER` environment variable to `jaeger-thrift-splunk`, or append the exporter to the existing values. For example, `OTEL_TRACES_EXPORTER=otlp,jaeger-thrift-splunk`.

If the `SPLUNK_REALM` or the `OTEL_EXPORTER_JAEGER_ENDPOINT` environmental variables are set, the default endpoint is overwritten.

## Troubleshooting

For troubleshooting information, see the [Troubleshooting](docs/troubleshooting.md) documentation.
Expand Down
1 change: 1 addition & 0 deletions examples/smart-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Gemfile.lock
6 changes: 6 additions & 0 deletions examples/smart-agent/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

source "https://rubygems.org"

gem "opentelemetry-exporter-jaeger"
gem "splunk-otel", path: "../../"
8 changes: 8 additions & 0 deletions examples/smart-agent/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: "3"
services:
otel:
image: quay.io/signalfx/signalfx-agent:5
ports:
- 9080:9080
volumes:
- ./smart-agent-config.yaml:/etc/signalfx/agent.yaml
22 changes: 22 additions & 0 deletions examples/smart-agent/runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require "rubygems"
require "bundler/setup"
Bundler.require(:default)

Splunk::Otel.configure do |configurator|
$configurator = configurator # rubocop:disable Style/GlobalVars

class << configurator
def test_shutdown
@span_processors.each(&:shutdown)
end
end
end

tracer = OpenTelemetry.tracer_provider.tracer("test", "1.0")
tracer.in_span("test-span") do
puts "test-span execution"
end

$configurator.test_shutdown # rubocop:disable Style/GlobalVars
5 changes: 5 additions & 0 deletions examples/smart-agent/smart-agent-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
signalFxAccessToken: ""
ingestUrl: "https://ingest.lab0.signalfx.com"
signalFxRealm: "lab0"
monitors:
- type: trace-forwarder
36 changes: 22 additions & 14 deletions lib/splunk/otel.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# frozen_string_literal: true

require_relative "otel/version"
require "opentelemetry/sdk"

# FIXME: without this, otlp doesn't work out-of-the-box
require "opentelemetry-exporter-otlp"

require_relative "otel/version"
require_relative "otel/proprietary_exporters"

module Splunk
# main module for application startup configuration
module Otel
module Otel # rubocop:disable Metrics/ModuleLength
# custom exception types in this gem must inherit from Splunk::Otel::Error
# this allows the user to rescue a generic exception type to catch all exceptions
class Error < StandardError; end
Expand Down Expand Up @@ -57,20 +57,21 @@ def configure(service_name: ENV.fetch("OTEL_SERVICE_NAME", "unnamed-ruby-service
trace_response_header_enabled: ENV.fetch("SPLUNK_TRACE_RESPONSE_HEADER_ENABLED", "true"))
@trace_response_header_enabled = to_boolean(trace_response_header_enabled)

set_default_propagators
set_access_token_header
set_default_exporter
set_default_span_limits
set_defaults

# run SDK's setup function
OpenTelemetry::SDK.configure do |c|
c.service_name = service_name
c.resource = OpenTelemetry::SDK::Resources::Resource.create(
OpenTelemetry::SDK.configure do |configurator|
class << configurator
include Splunk::Otel::ExporterExtensions
end

configurator.service_name = service_name
configurator.resource = OpenTelemetry::SDK::Resources::Resource.create(
"splunk.distro.version" => Splunk::Otel::VERSION
)

c.use_all if auto_instrument
yield c if block_given?
configurator.use_all if auto_instrument
yield configurator if block_given?
end

# set span limits to GDI defaults if not set by the user
Expand All @@ -79,6 +80,13 @@ def configure(service_name: ENV.fetch("OTEL_SERVICE_NAME", "unnamed-ruby-service
verify_service_name
end

def set_defaults
set_default_propagators
set_access_token_header
set_default_exporter
set_default_span_limits
end

# verify `service.name` is set and print a warning if it is still the default
def verify_service_name
provider_resource = OpenTelemetry.tracer_provider.instance_variable_get(:@resource)
Expand Down Expand Up @@ -183,7 +191,7 @@ def service_name_warning
module_function :configure, :gdi_span_limits, :set_default_propagators, :set_default_exporter,
:verify_service_name, :service_name_warning, :default_env_vars,
:set_default_span_limits, :set_access_token_header, :set_endpoint,
:to_boolean, :trace_response_header_enabled
:to_boolean, :trace_response_header_enabled, :set_defaults
end
end

Expand Down
54 changes: 54 additions & 0 deletions lib/splunk/otel/proprietary_exporters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

module Splunk
module Otel
OUR_EXPORTERS_KEYS = ["jaeger-thrift-splunk"].freeze
private_constant :OUR_EXPORTERS_KEYS

# internal module for allowing our exporters to be set via ENV
module ExporterExtensions
def effective_splunk_jaeger_endpoint
return "https://ingest.#{ENV["SPLUNK_REALM"]}.signalfx.com/v1/trace" if ENV["SPLUNK_REALM"]
return ENV["OTEL_EXPORTER_JAEGER_ENDPOINT"] if ENV["OTEL_EXPORTER_JAEGER_ENDPOINT"]

"http://127.0.0.1:9080/v1/trace"
end

def wrapped_exporters_from_env
original_env_value = ENV.fetch("OTEL_TRACES_EXPORTER", "otlp")
exporters_keys = original_env_value.split(",").map(&:strip)
non_proprietary_exporters_keys = exporters_keys - OUR_EXPORTERS_KEYS

ENV["OTEL_TRACES_EXPORTER"] = non_proprietary_exporters_keys.join(",")
original_exporters = super
ENV["OTEL_TRACES_EXPORTER"] = original_env_value

original_exporters + proprietary_exporters(exporters_keys)
end

def proprietary_exporters(exporters_keys)
(exporters_keys & OUR_EXPORTERS_KEYS).map do |exporter_key|
case exporter_key
when "jaeger-thrift-splunk"
args = {
endpoint: effective_splunk_jaeger_endpoint
}
fetch_exporter_with_args("jaeger-thrift-splunk", "OpenTelemetry::Exporter::Jaeger::CollectorExporter",
**args)
end
end.compact
end

def fetch_exporter_with_args(name, class_name, **args)
# TODO: warn if jaeger exporter gem is not present
exporter = Kernel.const_get(class_name).new(**args)
OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new exporter
rescue NameError
OpenTelemetry.logger.warn "The #{name} exporter cannot be configured" \
"- please add opentelemetry-exporter-#{name} to your Gemfile" \
", spans will not be exported.."
nil
end
end
end
end
25 changes: 25 additions & 0 deletions test/splunk/otel/proprietary_exporters_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

require "test_helper"
require "opentelemetry/sdk"
require "opentelemetry-exporter-jaeger"

module Splunk
class OtelProprietaryExportersTest < Test::Unit::TestCase
def setup
with_env("OTEL_TRACES_EXPORTER" => "jaeger-thrift-splunk") do
Splunk::Otel.configure
end
end

def teardown
OpenTelemetry.tracer_provider.shutdown
end

test "check that jaeger exporter is present" do
processors = OpenTelemetry.tracer_provider.instance_variable_get("@span_processors")
exporter = processors[0].instance_variable_get("@exporter")
assert_instance_of OpenTelemetry::Exporter::Jaeger::CollectorExporter, exporter
end
end
end
3 changes: 1 addition & 2 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
require "simplecov-cobertura"
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter

$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
require "splunk/otel"
require_relative "../lib/splunk/otel"

require "test-unit"

Expand Down

0 comments on commit 29418cf

Please sign in to comment.