Skip to content

Instantly share code, notes, and snippets.

@stevenharman
Last active November 23, 2021 21:05
Show Gist options
  • Save stevenharman/c375529f1c3ddbdc7886a66a2ea275e5 to your computer and use it in GitHub Desktop.
Save stevenharman/c375529f1c3ddbdc7886a66a2ea275e5 to your computer and use it in GitHub Desktop.

Revisions

  1. stevenharman revised this gist Nov 23, 2021. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions telemetry_wrapper.rb
    Original file line number Diff line number Diff line change
    @@ -34,12 +34,11 @@ def configure(env: ENV)
    self.honeycomb_dataset = env.fetch(ENV_HONEYCOMB_DATASET, nil)
    self.environment = "development"
    self.deployment_environment = environment
    sdk_config.service_version = env.fetch(ENV_SERVICE_VERSION, "v0-dev")

    yield(self) if block_given?

    sdk_config.service_name ||= "#{component} - #{deployment_environment}"
    sdk_config.service_version ||= env.fetch(ENV_SERVICE_VERSION, "v0-dev")

    sdk_config.service_name = "#{component} - #{deployment_environment}"
    sdk_config.resource = OpenTelemetry::SDK::Resources::Resource.create(
    "service.component" => component,
    OpenTelemetry::SemanticConventions::Resource::DEPLOYMENT_ENVIRONMENT => deployment_environment
  2. stevenharman revised this gist Nov 23, 2021. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions telemetry_wrapper.rb
    Original file line number Diff line number Diff line change
    @@ -34,17 +34,17 @@ def configure(env: ENV)
    self.honeycomb_dataset = env.fetch(ENV_HONEYCOMB_DATASET, nil)
    self.environment = "development"
    self.deployment_environment = environment

    yield(self) if block_given?

    sdk_config.service_name = "#{component} - #{deployment_environment}"
    sdk_config.service_version = env.fetch(ENV_SERVICE_VERSION, "v0-dev")
    sdk_config.service_name ||= "#{component} - #{deployment_environment}"
    sdk_config.service_version ||= env.fetch(ENV_SERVICE_VERSION, "v0-dev")

    sdk_config.resource = OpenTelemetry::SDK::Resources::Resource.create(
    "service.component" => component,
    OpenTelemetry::SemanticConventions::Resource::DEPLOYMENT_ENVIRONMENT => deployment_environment
    )

    yield(self) if block_given?

    enable_honeycomb if honeycomb_api_key.present? && honeycomb_dataset.present?
    enable_development_mode if development?
    enable_test_mode if test?
  3. stevenharman created this gist Nov 23, 2021.
    11 changes: 11 additions & 0 deletions telemetry_initializer.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    Telemetry.configure do |c|
    c.component = ENV.fetch("COMPONENT_NAME")
    c.environment = ENV.fetch("APP_ENV")
    c.deployment_environment = ENV.fetch("DEPLOYMENT_ENVIRONMENT")

    c.honeycomb_api_key = ENV.fetch("HONEYCOMB_API_KEY", nil)
    c.honeycomb_dataset = ENV.fetch("HONEYCOMB_DATASET", nil)

    # This is delegating through to `OpenTelemetry::SDK::Configurator#use_all`
    c.use_all("OpenTelemetry::Instrumentation::Sidekiq" => {span_naming: :job_class})
    end
    110 changes: 110 additions & 0 deletions telemetry_wrapper.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    # frozen_string_literal: true

    module Telemetry
    ENV_SERVICE_VERSION = "HEROKU_RELEASE_VERSION" # Depends on Feature: https://devcenter.heroku.com/articles/dyno-metadata
    ENV_HONEYCOMB_API_KEY = "HONEYCOMB_API_KEY"
    ENV_HONEYCOMB_DATASET = "HONEYCOMB_DATASET"
    VERSION = "0.9.0-beta"

    def self.tracer(name = "telemetry-ruby", version = Telemetry::VERSION)
    OpenTelemetry.tracer_provider.tracer(name, version)
    end

    def self.configure
    c = Configuration.new
    yield(c) if block_given?
    c.configure
    end

    class Configuration
    extend Forwardable
    # Delegate the public API of SDK's Configurator to allow an escape hatch for more advanced configuration needs.
    delegate [:logger, :logger=, :error_handler, :resource=, :service_name=, :service_version=, :use, :use_all, :add_span_processor] => :sdk_config

    attr_accessor :component, :version
    attr_accessor :honeycomb_api_key, :honeycomb_dataset
    attr_reader :deployment_environment, :environment

    def initialize(sdk_config: OpenTelemetry::SDK::Configurator.new)
    @sdk_config = sdk_config
    end

    def configure(env: ENV)
    self.honeycomb_api_key = env.fetch(ENV_HONEYCOMB_API_KEY, nil)
    self.honeycomb_dataset = env.fetch(ENV_HONEYCOMB_DATASET, nil)
    self.environment = "development"
    self.deployment_environment = environment

    sdk_config.service_name = "#{component} - #{deployment_environment}"
    sdk_config.service_version = env.fetch(ENV_SERVICE_VERSION, "v0-dev")

    sdk_config.resource = OpenTelemetry::SDK::Resources::Resource.create(
    "service.component" => component,
    OpenTelemetry::SemanticConventions::Resource::DEPLOYMENT_ENVIRONMENT => deployment_environment
    )

    yield(self) if block_given?

    enable_honeycomb if honeycomb_api_key.present? && honeycomb_dataset.present?
    enable_development_mode if development?
    enable_test_mode if test?

    sdk_config.configure
    rescue
    # This error handling is roughly equivalent to what the OpenTelementry::SDK itself does.
    # see: https://github.com/open-telemetry/opentelemetry-ruby/blob/9428b4e7df915f6bf062445fa6de7fb921cc7a44/sdk/lib/opentelemetry/sdk.rb#L67-L72
    begin
    raise OpenTelemetry::SDK::ConfigurationError
    rescue OpenTelemetry::SDK::ConfigurationError => e
    OpenTelemetry.handle_error(exception: e, message: "unexpected configuration error due to #{e.cause}")
    end
    end

    def deployment_environment=(value)
    @deployment_environment = String(value)
    end

    def environment=(value)
    @environment = String(value)
    end

    private

    attr_reader :sdk_config

    def enable_development_mode
    console_exporter = OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new
    add_span_processor(OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(console_exporter))
    end

    def enable_honeycomb
    oltp_exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(
    endpoint: "https://api.honeycomb.io:443/v1/traces",
    headers: {
    "x-honeycomb-team" => honeycomb_api_key,
    "x-honeycomb-dataset" => honeycomb_dataset
    },
    compression: "gzip"
    )
    batch_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(oltp_exporter)
    sdk_config.add_span_processor(batch_processor)
    end

    def enable_test_mode
    in_memory_exporter = OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new(recording: false)
    sdk_config.add_span_processor(OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(in_memory_exporter))

    # Quiet the Info/Warn log lines generated by #use_all
    # There must be a better way to do this so we don't have to silence warnings.
    sdk_config.logger.level = Logger::ERROR
    end

    def development?
    environment == "development"
    end

    def test?
    environment == "test"
    end
    end
    end