GithubHelp home page GithubHelp logo

open-telemetry / opentelemetry-ruby Goto Github PK

View Code? Open in Web Editor NEW
458.0 26.0 227.0 10.93 MB

OpenTelemetry Ruby API & SDK, and related gems

Home Page: https://opentelemetry.io/

License: Apache License 2.0

Ruby 97.91% Dockerfile 0.17% Thrift 1.83% Jinja 0.08%
telemetry distributed-tracing metrics opentelemetry opentelemetry-ruby opentelemetry-api hacktoberfest

opentelemetry-ruby's Introduction

OpenTelemetry Ruby

Slack channel CI Apache License

The Ruby OpenTelemetry client.

Contributing

We'd love your help! Use tags good first issue and help wanted to get started with the project.

Please review the contribution instructions for important information on setting up your environment, running the tests, and opening pull requests.

The Ruby special interest group (SIG) meets regularly. See the OpenTelemetry community page repo for information on this and other language SIGs.

Approvers (@open-telemetry/ruby-approvers):

Find more about the approver role in community repository.

Maintainers (@open-telemetry/ruby-maintainers):

Find more about the maintainer role in community repository.

Contrib Repository

The opentelemetry-ruby-contrib repository contains instrumentation libraries for many popular Ruby gems, including Rails, Rack, Sinatra, and others, so you can start using OpenTelemetry with minimal changes to your application. See the contrib README for more details.

Versioning

OpenTelemetry Ruby follows the versioning and stability document in the OpenTelemetry specification. Notably, we adhere to the outlined version numbering exception, which states that experimental signals may have a 0.x version number.

Useful links

License

Apache 2.0 - See LICENSE for more information.

opentelemetry-ruby's People

Contributors

ahayworth avatar aislinnnnn avatar angeliski avatar arielvalentin avatar cartermp avatar chalin avatar chrisholmes avatar dazuma avatar dmathieu avatar duonoid avatar elskwid avatar ericmustin avatar fbogsany avatar fhwang avatar genebean avatar github-actions[bot] avatar grantbdev avatar hosamaly avatar ibawt avatar indrekj avatar johnnyshields avatar kaylareopelle avatar miry avatar mwear avatar plantfansam avatar richardmcmillen avatar robertlaurin avatar somalianivan avatar tsloughter avatar xuan-cao-swi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opentelemetry-ruby's Issues

Enable CI integration

PRs should be checked with a CI tool (e.g. travis, circleci, etc) to avoid pushing breaking changes to master. The api has bundle exec rake command to run tests and rubocop.

API: decide what to do for invalid arguments

I'm not sure what we should do for invalid arguments in the minimal implementation, and am somewhat torn on the issue.

I just wanted to point out that there is a proposal currently in PR form here: open-telemetry/opentelemetry-specification#153.

There seem to be various opinions as you read through the comments. This comment proposed a somewhat pragmatic approach of falling back to a default when an argument is invalid. Quote (from the comment)

Specific case: I do think using a null name for Span could fallback to using a default name, instead of throwing. Documenting it is nice, but providing defaults for these kind of things is a good alternative ;)

It might be too early to make a final call on how to deal exceptions in the minimal implementation, but we should keep an eye on that PR and the specification repo for guidance.

Originally posted by @mwear in https://github.com/open-telemetry/opentelemetry-ruby/diffs

API: cleanup SpanContext and Span (parent ID vs span ID)

There's a lot of confusion in the implementations for other languages around SpanContext and Span. We've inherited that confusion. At present, the Span has no representation of "parent span", and we use the SpanContext (if provided) unchanged as this span's context, when it is actually meant to be the parent context. I believe the expected transformation is:

def start_span(name, with_parent: nil, with_parent_context: nil, ...)
  span_context = with_parent&.context || with_parent_context || current_span.context
  parent_id = span_context.span_id # Should be 0 unless span_context.valid?
  span_context = if span_context.valid?
    SpanContext.new(trace_id: span_context.trace_id, trace_options: span_context.trace_options)
  else
    SpanContext.new
  end
  Span.new(span_context: span_context, parent_span_id: parent_id)
end

Add CI, either Circle or Travis

We have a .travis.yml that should enable TravisCI for this project, but actually turning it on requires admin access to Travis (or to the open-telemetry org on Github - I'm not clear which). None of the primary contributors to this project have that access.

@SergeyKanzhelev or @bogdandrutu can you please enable this?

Alternatively, if the preference is to use CircleCI, can you please enable it there and I'll add the necessary config.

API: Retrieve Resource labels

There has been some discussion on #24 about the best way to expose labels from the Resource API. This is covered in the retrieve labels section of the Resource spec.

We are currently exposing an enumerator and not the underlying frozen hash of labels. Exposing the underlying hash would require that all SDKs would have to return labels with a data structure matching that interface. See the discussion here.

Several options have been proposed:

  • labels should return an enumerable, the exact implementation would be up to the SDK
  • a each_label method
  • exposing the underlying hash

If there are any other options we should add them here and discuss what we'd like to do going forward.

Cleanup api/test directory

api/test/opentracing/trace should be api/test/opentelemetry/trace
api/test/resources should be api/test/opentelemetry/resources
api/test/opentracing_test.rb should be api/test/opentelemetry_test.rb

SDK: integration tests

We need integration tests in the SDK gem to exercise the integration between the API and the SDK. A good structure for this is probably a method that, for example, traces a bunch of operations in different ways (root spans, child-of-remote spans, child-of-local spans, with and without links, etc.), and then a bunch of tests that configure the global tracer in different ways, call the tracing method, and asserts the results using an InMemorySpanExporter.

SDK: Thread safety

LightStep's Ruby gem is thread-safe. For example, spans can be modified concurrently in different threads (adding tags, logs, etc.).

The OpenCensus Ruby gem is not thread-safe. Spans cannot be safely shared between threads.

Should we support this use-case (concurrent modification of a span)?

API: consider adding an empty Resource

The Resource spec states:

It is recommended, but not required, to provide a way to quickly create an empty resource.

Should we add a Resource::EMPTY constant? As with #25 it isn't clear if this has value, if Resource is only attached to a Tracer, and SpanData is removed.

SDK: test exporters and processors

Span#set_attribute with strings & symbols

Span#set_attribute currently accepts both symbols and strings for both keys and values.

We had a similar discussion here: opentracing/opentracing-ruby#35 and went with only strings. Currently we can still decide what's the best approach.

The problem with allowing both strings and symbols as attribute keys has two main problems:

  • memory allocation in case we need to convert one to other
  • what happens if somebody does span[:foo] = "bar"; span["foo"] = "baz". who wins?

API: SpanData should only expose enumerators for collections

I really like this idea. I think the no-op implementation should try to expose the smallest possible interface. That will help users ensure their usage is correct (e.g. they aren't inadvertently depending on the returned objects implementing obscure methods of Array or Hash), and relieve implementors of the burden of implementing a larger surface.

Originally posted by @dazuma in https://github.com/open-telemetry/opentelemetry-ruby/diffs

SDK: fork safety

LightStep's Ruby gem is fork-safe. If a process forks, spans already buffered in memory by the parent process are not exported by the child process.

Do we want to support fork()? Doing so brings some complexity. It isn't clear that common use-cases for tracing require it.

Implement OpenCensus compatibility shim

Note that the OpenCensus implementation for Ruby was incomplete - in particular, it lacked metrics and exporter support. Do we need to implement an OC shim? Does it need to support metrics?

SDK: auto-instrumentation via ActiveSupport::Notification

ActiveSupport::Notification is a common mechanism for instrumenting a Rails application. Its API is a bit of a mess, though. For example, the payload can be modified by subscribers, and between calls to start and finish, so care has to be taken to only copy attributes from the payload in finish. Also, calls to start may not be paired with calls to finish if (another) subscriber raises an error.

Given the complexity of the API, should we support or use it for auto-instrumentation, or rely on lower-level monkey-patching?

API: Resource Create recommended to be a factory method

The Resource spec recommends Create be a factory method:

A factory method is recommended to enable support for cached objects.

It is currently implemented as a constructor, which is permitted by the spec. We should consider whether caching is useful in this context. Specifically, open-telemetry/oteps#8 suggests removing SpanData from the API, which leaves attachment to a Tracer as the only use of Resource.

SDK: post-request vs immediate export

The OpenCensus gem buffers spans during a request (for Rack apps) and exports them when the request has completed. This means finished child spans of long requests will not be available for analysis until the request finishes.

Should we wait for request completion to export all child spans, or should spans be exported as they finish?

API: Propagate tracestate

There was a PR to temporarily remove tracestate. It was opened due to confusion around what context belongs in tracestate, but ultimately never merged. The Context Propagation OTEP provides the necessary layers for the different types of context that users can interact with. It doesn't mention tracestate, and that is because tracestate is for context used by the tracer (SDK) implementation.

As discussed in a recent W3 Distributed Tracing Meeting OpenTelemetry should:

  • Propagate tracestate
  • Does not need to expose it via API
  • May expose it via SDK SPI if there is a use case

Instrumentation Packaging and Installation

Third Party Instrumentation Proposal for OpenTelemetry Ruby

Overview

There is an RFC for auto-instrumentation and this document describes a possible approach that we could use for managing instrumentation for the OpenTelemetry Ruby Project.

Packaging

  • Instrumentation should be packaged as gems
  • Packages should list dependencies in their gemspec for
    • OpenTelemetry API Version
    • Framework version
  • This will allow us to use Bundler to do the heavy lifting regarding versioning and compatibility of dependencies

Installation

  • The tracer should be able to auto detect any instrumentation that is listed as a dependency in an application's Gemfile
  • The time at which to install instrumentation in a Ruby application can be challenging to get right
    • To make this straightforward for the reference implementation, the SDK should have an API method that a user can call to install instrumentation at the right time for their application
    • Various SDK implementations can engage in whatever clever means they need to try to install instrumentation at the right time by calling this API method at the right time on behalf of the user

Implementation

The implementation I am proposing is very similar to and inspired by Rails::Railtie.

OpenTelemetry Ruby will ship with a common base class, OpenTelemetry::Instrumentation that

  • registers instrumentation with tracer (via the Class#inherited callback)
  • provides hooks for the instrumentation to be installed
  • provides the ability to enable or disable instrumentation
    • by having an optional, explicit hook that can be defined for complex use cases
    • establishing a naming convention for environment variables users can specify to override whether or not instrumentation is enabled

Example Instrumentation Package

A package should list its dependencies in its gemspec

Gem::Specification.new do |spec|
  spec.add_dependency 'activerecord', '>= 5.0'
  spec.add_dependency 'opentelemetry-api', '~> 1.0'
end

A package will ship with a class that subclasses OpenTelemetry::Instrumentation which will auto-register instrumentation, and provide hooks for installing and enabling it. The base class will automatically check for an environment variable derived off of the instrumentation_name field for overriding an enabled decision. The convention I'm proposing for an environment variable name is OPENTELEMETRY_{insrumentation_name}_ENABLED, which in this example would be OPENTELEMETRY_OTEL_ACTIVE_RECORD_ENABLED.

class ActiveRecordInstrumentation < OpenTelemetry::Instrumentation
  instrumentation_name :otel_active_record

  enabled do
    # optional and overridable by environment variable, but complex logic around 
    # whether this is enabled can go here
    true
  end

  install do |tracer|
    require 'active_record_instrumentation/subscriber'
    subscriber = Subscriber.new tracer
    ActiveSupport::Notifications.subscribe 'sql.active_record' do |*args|
      subscriber.call(*args)
    end
  end
end

Instrumentation installation API

The SDK should provide an API method to install instrumentation that can be called at the right time during application startup. This method should evaluate and install all instrumentation that subclasses OpenTelemetry::Instrumentation if it is enabled.

tracer = TracerImplementation.new
OpenTelemetry::Instrumentation.install tracer

OpenTelemetry::Instrumentation Implementation

Below is a rough-draft of what the OpenTelemetry::Instrumentation class would look like

module OpenTelemetry
  class Instrumentation
    class << self
      private :new
      
      #subclasses are registered via this hook
      def inherited subclass
        subclasses << subclass
      end

      def subclasses
        @subclasses ||= []
      end

      def install_instrumentation tracer
        subclasses.each do |subclass|
          instrumentation = subclass.instance
          if instrumentation.enabled? && !instrumentation.installed?
            instrumentation.install tracer
          end
        end
      end

      #this method is dual purpose, its used by the DSL to setup an install block,
      #but when passed a tracer, will install all registered instrumentation
      def install tracer = nil, &blk
        if tracer && blk
          raise ArgumentError, "Pass a tracer or block, but not both"
        end
        if blk
          instance.install_block = blk
        elsif tracer
          install_instrumentation tracer
        end
      end

      def enabled &blk
        instance.enabled_block = blk
      end

      def instrumentation_name name = nil
        if name.nil?
          @instrumentation_name
        else
          @instrumentation_name = name.to_sym
        end
      end

      def instance
        @instance ||= new
      end
    end

    attr_accessor :install_block
    attr_accessor :enabled_block

    attr_reader :installed
    alias_method :installed?, :installed

    def initialize
      @installed = false
    end

    def install tracer = ::OpenTelemetry.global_tracer
      instance_exec tracer, &install_block
      @installed = true
    end

    def enabled?
      if enabled_block
        enabled_by_env? && instance_eval(&enabled_block)
      else
        enabled_by_env?
      end
    end

    private

    def enabled_by_env?
      key = "OPENTELEMETRY_#{self.class.instrumentation_name.to_s.upcase}_ENABLED"
      if ENV.include? key
        ENV[key] == 'true'
      else
        true
      end
    end
  end
end

Discussion

I've been thinking about how we can package instrumentation for OpenTelemetry Ruby and wanted to put these thoughts in writing as a starting point for a discussion about it. I'm open to any and all suggestions with the end goal of us having the best possible instrumentation distribution story, even if it doesn't end up being this one.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.