eltesla 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/eltesla/client.rb +69 -0
- data/lib/eltesla/experiment.rb +49 -0
- data/lib/eltesla/observation.rb +35 -0
- data/lib/eltesla/result.rb +38 -0
- data/lib/eltesla/version.rb +3 -0
- data/lib/eltesla.rb +10 -0
- metadata +62 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 6d5a5688dc14f783b38a944c3e29088ee53343beab09b3a7dd0a4d59a54eadcc
         | 
| 4 | 
            +
              data.tar.gz: 39b89807a086e30b1b0d680975a29a3f657591e82e192b9709fc4c91388d3487
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: b263b136234020ac7b6e88b7493131b2f815120409b36b1c6bd51d1d873adae29a4456e05a6e1613150fe4fbbb72d6c9f65e49be6a49e54963673749fe6a3036
         | 
| 7 | 
            +
              data.tar.gz: 1b935e5420b4720c16be076184c13a32ba98f597043bc32b9dd4fbecaf74dcd99a9670ba7765354908e86864db976380c038beec17bb346e3ff4bed2f455b91a
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'net/http'
         | 
| 4 | 
            +
            require 'uri'
         | 
| 5 | 
            +
            require 'json'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Eltesla
         | 
| 8 | 
            +
              # Client for the Eltesla backend
         | 
| 9 | 
            +
              class Client
         | 
| 10 | 
            +
                if ENV.fetch('ELTESLA_DEBUG', false)
         | 
| 11 | 
            +
                  PROTOCOL = 'http'
         | 
| 12 | 
            +
                  DOMAIN = 'localhost:3000'
         | 
| 13 | 
            +
                  QUEUE_SIZE_THRESHOLD = 1
         | 
| 14 | 
            +
                  QUEUE_SIZE_LIMIT = 2
         | 
| 15 | 
            +
                else
         | 
| 16 | 
            +
                  PROTOCOL = 'https'
         | 
| 17 | 
            +
                  DOMAIN = 'eltesla.dev'
         | 
| 18 | 
            +
                  QUEUE_SIZE_THRESHOLD = 10
         | 
| 19 | 
            +
                  QUEUE_SIZE_LIMIT = 20
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                ENDPOINT = URI.parse("#{PROTOCOL}://#{DOMAIN}/metrics")
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                class << self
         | 
| 24 | 
            +
                  attr_writer :queue
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def queue
         | 
| 27 | 
            +
                    @queue ||= []
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def send(result)
         | 
| 31 | 
            +
                    raise "Could not process #{result}" unless result.is_a?(Eltesla::Result)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    queue << result
         | 
| 34 | 
            +
                    flush! if queue.size >= QUEUE_SIZE_THRESHOLD
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def flush!
         | 
| 38 | 
            +
                    return if queue.empty?
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    http_post!
         | 
| 41 | 
            +
                    queue.clear
         | 
| 42 | 
            +
                  rescue StandardError => e
         | 
| 43 | 
            +
                    warn "[Eltesla] Could not send payload: #{e.message}"
         | 
| 44 | 
            +
                    if queue.size > QUEUE_SIZE_LIMIT
         | 
| 45 | 
            +
                      warn("[Eltesla] Dropping #{queue.size - QUEUE_SIZE_LIMIT} results from the queue")
         | 
| 46 | 
            +
                      self.queue = queue[-QUEUE_SIZE_LIMIT..]
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  private
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def http_post!
         | 
| 53 | 
            +
                    http = Net::HTTP.new(ENDPOINT.host, ENDPOINT.port)
         | 
| 54 | 
            +
                    request = Net::HTTP::Post.new(
         | 
| 55 | 
            +
                      ENDPOINT.request_uri,
         | 
| 56 | 
            +
                      { 'Content-Type': 'application/json' }
         | 
| 57 | 
            +
                    )
         | 
| 58 | 
            +
                    request.body = { results: queue }.to_json
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    http.request(request).value
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            # rubocop:disable Style/GlobalVars
         | 
| 67 | 
            +
            $eltesla_exit_callback ||= at_exit { Eltesla::Client.flush! }
         | 
| 68 | 
            +
            # rubocop:enable Style/GlobalVars
         | 
| 69 | 
            +
             | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'scientist/experiment'
         | 
| 4 | 
            +
            require 'eltesla/result'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Eltesla
         | 
| 7 | 
            +
              # Github scientist experiment implementation for Eltesla
         | 
| 8 | 
            +
              class Experiment
         | 
| 9 | 
            +
                include Scientist::Experiment
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                attr_reader :name, :file, :line
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(name)
         | 
| 14 | 
            +
                  location_parts = clean_trace(caller).first.split(/:/)
         | 
| 15 | 
            +
                  @file = location_parts.first
         | 
| 16 | 
            +
                  @line = location_parts[1].to_i
         | 
| 17 | 
            +
                  @name = name || location_parts.last[4..-2]
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def enabled?
         | 
| 21 | 
            +
                  # FIXME : Add activation policies
         | 
| 22 | 
            +
                  true
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def raised(operation, error)
         | 
| 26 | 
            +
                  # see "In a Scientist callback" below
         | 
| 27 | 
            +
                  p "Operation '#{operation}' failed with error '#{error.inspect}'"
         | 
| 28 | 
            +
                  super # will re-raise
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def publish(result)
         | 
| 32 | 
            +
                  Eltesla::Client.send(result.to_eltesla)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def clean_trace(backtrace)
         | 
| 36 | 
            +
                  return backtrace unless defined?(Rails.backtrace_cleaner)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  Rails.backtrace_cleaner.clean(backtrace)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def self.run(name = nil)
         | 
| 42 | 
            +
                  raise 'Missing block' unless block_given?
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  experiment = Eltesla::Experiment.new(name)
         | 
| 45 | 
            +
                  yield(experiment)
         | 
| 46 | 
            +
                  experiment.run
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'json'
         | 
| 4 | 
            +
            require 'scientist'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Eltesla
         | 
| 7 | 
            +
              # rubocop:disable Naming/ConstantName
         | 
| 8 | 
            +
              OBSERVATION_ATTRIBUTES = %i[
         | 
| 9 | 
            +
                name
         | 
| 10 | 
            +
                value
         | 
| 11 | 
            +
                duration
         | 
| 12 | 
            +
                exception_class
         | 
| 13 | 
            +
                exception_message
         | 
| 14 | 
            +
                exception_backtrace
         | 
| 15 | 
            +
              ].freeze
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              Observation =
         | 
| 18 | 
            +
                if defined?(Data.define)
         | 
| 19 | 
            +
                  Data.define(*OBSERVATION_ATTRIBUTES)
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  Struct.new(*OBSERVATION_ATTRIBUTES, keyword_init: true)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              Scientist::Observation.define_method(:to_eltesla) do
         | 
| 25 | 
            +
                Eltesla::Observation.new(
         | 
| 26 | 
            +
                  exception_class: exception&.class&.name,
         | 
| 27 | 
            +
                  exception_message: exception&.message,
         | 
| 28 | 
            +
                  exception_backtrace: exception&.backtrace,
         | 
| 29 | 
            +
                  name:,
         | 
| 30 | 
            +
                  value:,
         | 
| 31 | 
            +
                  duration:
         | 
| 32 | 
            +
                )
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              # rubocop:enable Naming/ConstantName
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'json'
         | 
| 4 | 
            +
            require 'scientist'
         | 
| 5 | 
            +
            require_relative 'observation'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Eltesla
         | 
| 8 | 
            +
              # rubocop:disable Naming/ConstantName
         | 
| 9 | 
            +
              RESULT_ATTRIBUTES = %i[
         | 
| 10 | 
            +
                observations_attributes
         | 
| 11 | 
            +
                context
         | 
| 12 | 
            +
                matched
         | 
| 13 | 
            +
                executed_at
         | 
| 14 | 
            +
                experiment_name
         | 
| 15 | 
            +
                experiment_file
         | 
| 16 | 
            +
                experiment_line
         | 
| 17 | 
            +
              ].freeze
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              Result =
         | 
| 20 | 
            +
                if defined?(Data.define)
         | 
| 21 | 
            +
                  Data.define(*RESULT_ATTRIBUTES)
         | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  Struct.new(*RESULT_ATTRIBUTES, keyword_init: true)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              Scientist::Result.define_method(:to_eltesla) do
         | 
| 27 | 
            +
                Eltesla::Result.new(
         | 
| 28 | 
            +
                  experiment_name: experiment.name,
         | 
| 29 | 
            +
                  experiment_file: experiment.file,
         | 
| 30 | 
            +
                  experiment_line: experiment.line,
         | 
| 31 | 
            +
                  context: context.empty? ? nil : context,
         | 
| 32 | 
            +
                  matched: matched?,
         | 
| 33 | 
            +
                  executed_at: Time.now,
         | 
| 34 | 
            +
                  observations_attributes: observations.map(&:to_eltesla)
         | 
| 35 | 
            +
                )
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
              # rubocop:enable Naming/ConstantName
         | 
| 38 | 
            +
            end
         | 
    
        data/lib/eltesla.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: eltesla
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Alexandre Ignjatovic
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2024-03-04 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: scientist
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.6'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.6'
         | 
| 27 | 
            +
            description: Client for the Eltesla service, for easier refactoring
         | 
| 28 | 
            +
            email: alexandre.ignjatovic@gmail.com
         | 
| 29 | 
            +
            executables: []
         | 
| 30 | 
            +
            extensions: []
         | 
| 31 | 
            +
            extra_rdoc_files: []
         | 
| 32 | 
            +
            files:
         | 
| 33 | 
            +
            - lib/eltesla.rb
         | 
| 34 | 
            +
            - lib/eltesla/client.rb
         | 
| 35 | 
            +
            - lib/eltesla/experiment.rb
         | 
| 36 | 
            +
            - lib/eltesla/observation.rb
         | 
| 37 | 
            +
            - lib/eltesla/result.rb
         | 
| 38 | 
            +
            - lib/eltesla/version.rb
         | 
| 39 | 
            +
            homepage: https://eltes.la
         | 
| 40 | 
            +
            licenses:
         | 
| 41 | 
            +
            - MIT
         | 
| 42 | 
            +
            metadata: {}
         | 
| 43 | 
            +
            post_install_message:
         | 
| 44 | 
            +
            rdoc_options: []
         | 
| 45 | 
            +
            require_paths:
         | 
| 46 | 
            +
            - lib
         | 
| 47 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 48 | 
            +
              requirements:
         | 
| 49 | 
            +
              - - ">="
         | 
| 50 | 
            +
                - !ruby/object:Gem::Version
         | 
| 51 | 
            +
                  version: '2.3'
         | 
| 52 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 53 | 
            +
              requirements:
         | 
| 54 | 
            +
              - - ">="
         | 
| 55 | 
            +
                - !ruby/object:Gem::Version
         | 
| 56 | 
            +
                  version: '0'
         | 
| 57 | 
            +
            requirements: []
         | 
| 58 | 
            +
            rubygems_version: 3.5.6
         | 
| 59 | 
            +
            signing_key:
         | 
| 60 | 
            +
            specification_version: 4
         | 
| 61 | 
            +
            summary: 'Eltesla: GitHub Scientist as a Service.'
         | 
| 62 | 
            +
            test_files: []
         |