activemeasure 0.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 06afb38a723f4ae8cf7d834f1c5535564471c8878337aaf6d6f19dd8407dc22f
4
+ data.tar.gz: 864934d81291f917080982466a68a4b0e273730dabc0e3a4705003b2ae0eef29
5
+ SHA512:
6
+ metadata.gz: ca4103b83f570c4f151a8d74e1d3382595cba6dc798424d794b246c76d5b5167df33d34ac77ae8ab4099873aa53322e83cf81ae5d7028242fc5a87d2b94e82b2
7
+ data.tar.gz: ecb1f39d86839dde6a1f13a8203dcd41c8d2db230e6ed9819a6bba88c108ecb4065128ad20f3f20aeba2c0bdd506224e694181108d10dee38fd3c7b50e33c53d
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveMeasure
4
+ module Adapters
5
+ class Base
6
+ def increment(metric, value = 1, **_options)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def decrement(metric, value = 1, **_options)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def count(metric, value, **_options)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def gauge(metric, value, **_options)
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def timing(metric, value, **_options)
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def time(metric, &block)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def histogram(metric, value, **_options)
31
+ raise NotImplementedError
32
+ end
33
+
34
+ def set(metric, value, **_options)
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def distribution(metric, value, **_options)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ private
43
+
44
+ def dispatch_metric(metric)
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def connection
49
+ raise NotImplementedError
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is a dummy adapter that does nothing. it
4
+ module ActiveMeasure
5
+ module Adapters
6
+ class Sink < Base
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ module ActiveMeasure
6
+ module Adapters
7
+ class Statsd < Base
8
+ # c - counter
9
+ # g - gauge
10
+ # h - histogram
11
+ # ms - measure
12
+ # s - set
13
+ # d - distribution
14
+ VALID_METRICS_TYPES = %i[c g h ms s d].freeze
15
+ def dispatch_metric(metric)
16
+ connection.send(metric.to_s, 0)
17
+ end
18
+
19
+ def initialize(options = {})
20
+ @host = options.fetch(:host, 'localhost')
21
+ @port = options.fetch(:port, 8125)
22
+ @client = options.fetch(:client)
23
+ end
24
+
25
+ def increment(metric, value = nil, tags: {}, **_options)
26
+ send_measure(:c, metric, value, tags)
27
+ end
28
+
29
+ def decrement(metric, value = nil, tags: {}, **_options)
30
+ send_measure(:c, metric, -value, tags)
31
+ end
32
+
33
+ def count(metric, value = nil, tags: {}, **_options)
34
+ send_measure(:c, metric, value, tags)
35
+ end
36
+
37
+ def gauge(metric, value = nil, tags: {}, **_options)
38
+ send_measure(:g, metric, value, tags)
39
+ end
40
+
41
+ def timing(metric, value = nil, tags: {}, **_options)
42
+ send_measure(:ms, metric, value, tags)
43
+ end
44
+
45
+ def time(metric, value = nil, tags: {}, **_options)
46
+ send_measure(:ms, metric, value, tags)
47
+ end
48
+
49
+ def histogram(metric, value = nil, tags: {}, **_options)
50
+ send_measure(:h, metric, value, tags)
51
+ end
52
+
53
+ def set(metric, value = nil, tags: {}, **_options)
54
+ send_measure(:s, metric, value, tags)
55
+ end
56
+
57
+ def distribution(metric, value = nil, tags: {}, **_options)
58
+ send_measure(:d, metric, value, tags)
59
+ end
60
+
61
+ private
62
+
63
+ def connection
64
+ return @connection if @connection
65
+
66
+ @connection ||= UDPSocket.new
67
+ @connection.bind(@host, @port)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveMeasure
4
+ module Adapters
5
+ class StatsdSocket < Statsd
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveMeasure
4
+ module Adapters
5
+ class StatsdTagged < Statsd
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveMeasure
4
+ module Adapters
5
+ autoload :Base, 'active_measure/adapters/base'
6
+ autoload :Sink, 'active_measure/adapters/sink'
7
+ autoload :Statsd, 'active_measure/adapters/statsd'
8
+ autoload :StatsdSocket, 'active_measure/adapters/statsd_socket'
9
+ autoload :StatsdTagged, 'active_measure/adapters/statsd_tagged'
10
+ autoload :StatsdTaggedSocket, 'active_measure/adapters/statsd_tagged_socket'
11
+ ADAPTERS = {
12
+ 'statsd' => 'ActiveMeasure::Adapters::Statsd',
13
+ 'statsd_tagged' => 'ActiveMeasure::Adapters::StatsdTagged',
14
+ 'statsd_socket' => 'ActiveMeasure::Adapters::StatsdSocket',
15
+ 'statsd_tagged_socket' => 'ActiveMeasure::Adapters::StatsdTaggedSocket'
16
+ }.freeze
17
+
18
+ def self.for(adapter)
19
+ class_name = ADAPTERS[adapter]
20
+ raise("Unknown adapter: #{adapter}") unless class_name
21
+
22
+ Object.const_get(class_name)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ module ActiveMeasure
2
+ module Assertions
3
+ def assert_metric(metric, value, tags: nil)
4
+ raise "Not implemented"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveMeasure
2
+ class Buffer < Array
3
+ def initialize
4
+ super
5
+ end
6
+
7
+ def <<(metric)
8
+ super
9
+ end
10
+
11
+ def flush
12
+ self.clear
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,84 @@
1
+ require 'singleton'
2
+ require 'uri'
3
+ require 'forwardable'
4
+
5
+ module ActiveMeasure
6
+ class Client
7
+ extend Forwardable
8
+ DEFAULT_CONNECTION_STRING = 'udp://localhost:8125'
9
+
10
+ attr_reader :logger, :tags
11
+ attr_reader :transport, :namespace
12
+
13
+ def initialize(connection_string = nil, logger: nil, tags: {}, namespace: nil)
14
+ @connection_string = parse_connection_string(connection_string)
15
+ @connection_string[:client] = self
16
+ @transport = ActiveMeasure::Adapters.for(@connection_string[:adapter]).new(@connection_string)
17
+ @logger = logger || ActiveMeasure.logger
18
+ @tags = filter_tags(tags)
19
+ end
20
+
21
+ # forward all methods to transport
22
+ METRIC_METHODS = %i(
23
+ increment
24
+ decrement
25
+ count
26
+ gauge
27
+ timing
28
+ time
29
+ histogram
30
+ set
31
+ distribution
32
+ ).freeze
33
+
34
+ def_delegators :@transport, *METRIC_METHODS
35
+
36
+
37
+
38
+ def parse_connection_string(connection)
39
+ connection ||= ENV['ActiveMeasure_URL']
40
+ default_connection = {
41
+ scheme: 'statsd',
42
+ host: 'localhost',
43
+ port: 8125,
44
+ adapter: 'statsd'
45
+ }
46
+
47
+ return default_connection if connection.nil?
48
+
49
+ if connection.is_a?(Hash)
50
+ connection[:port] ||= default_connection[:port]
51
+ connection
52
+ else
53
+ uri = URI.parse(connection)
54
+ {
55
+ scheme: uri.scheme,
56
+ host: uri.host,
57
+ port: uri.port || default_connection[:port],
58
+ adapter: determine_adapter(uri.scheme)
59
+ }
60
+ end
61
+ end
62
+
63
+ def filter_tags(tags)
64
+ (ActiveMeasure.tags || {}).merge(tags || {}).reject { |_, value| value.nil? || value.empty? }
65
+ end
66
+
67
+ private
68
+
69
+ def determine_adapter(scheme)
70
+ case scheme
71
+ when 'statsd', 'udp', 'http'
72
+ 'statsd'
73
+ when 'statsdt'
74
+ 'statsd_tagged'
75
+ when 'unix'
76
+ 'statsd_socket'
77
+ when 'unixt'
78
+ 'statsd_tagged_socket'
79
+ else
80
+ raise "Unknown scheme: #{scheme}"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,32 @@
1
+ require 'singleton'
2
+
3
+ module ActiveMeasure
4
+ class Configuration
5
+ include Singleton
6
+ attr_reader :logger, :tags
7
+
8
+ def initialize
9
+ @mutex = Mutex.new
10
+ end
11
+
12
+ def logger=(value)
13
+ @mutex.synchronize { @logger = value }
14
+ end
15
+
16
+ def tags=(value)
17
+ @mutex.synchronize { @tags = value }
18
+ end
19
+ end
20
+
21
+ def self.configure
22
+ yield Configuration.instance
23
+ end
24
+
25
+ def self.logger
26
+ Configuration.instance.logger
27
+ end
28
+
29
+ def self.tags
30
+ Configuration.instance.tags
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ require 'logger'
2
+
3
+ module ActiveMeasure
4
+ module Logging
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def logger
11
+ @logger ||= Logger.new($stdout)
12
+ end
13
+
14
+ def logger=(new_logger)
15
+ @logger = new_logger
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,13 @@
1
+ require 'railtie'
2
+
3
+ module ActiveMeasure
4
+ class Railtie < ::Rails::Railtie
5
+ config.active_measure = ActiveSupport::OrderedOptions.new
6
+
7
+ initializer 'active_measure.configur_logger' do |app|
8
+ ActiveMeasure.configure do |config|
9
+ config.logger = Rails.logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveMeasure
2
+ module Sampler
3
+
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ module ActiveMeasure
2
+ module Serializer
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ # Serialize a metric into a string
10
+ # @param metric [String] The metric to serialize
11
+ # @example 'company.create'
12
+ # @param value [Numeric] The value to serialize
13
+ # @example 1
14
+ # @param type [String] The type of metric (defaults to 'c')
15
+ # @example 'ms'
16
+ # @param tags [Hash] The tags to serialize
17
+ # @example { company: 'acme', environment: 'production' }
18
+ # @return [String] Serialized metric string
19
+ # @example 'company.create;company=acme,environment=production:1|ms'
20
+ def serialize(metric, value, type: 'c', tags: {})
21
+ tag_string = tags.map { |key, val| "#{key}=#{val}" }.join(',')
22
+ "#{metric};#{tag_string}:#{value}|#{type}"
23
+ end
24
+
25
+ # Deserialize a metric from a serialized string
26
+ # @param serialized_metric [String] The metric string to deserialize
27
+ # @example 'company.create;company=acme,environment=production:1|ms'
28
+ # @return [Hash] Deserialized metric as a hash with keys: :metric, :value, :type, and :tags
29
+ # @example { metric: 'company.create', value: 1.0, type: 'ms', tags: { 'company' => 'acme', 'environment' => 'production' } }
30
+ def deserialize(serialized_metric)
31
+ metric, tag_string, value_and_type = serialized_metric.split(';')
32
+ value, type = value_and_type.split('|')
33
+
34
+ tags = {}
35
+ tag_string.split(',').each do |tag|
36
+ key, value = tag.split('=')
37
+ tags[key] = value
38
+ end
39
+
40
+ { metric: metric, value: value.to_f, type: type, tags: tags }
41
+ rescue => e
42
+ raise "Failed to deserialize metric: #{e.message}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ module ActiveMeasure
2
+ InvalidMetric = Class.new(ArgumentError)
3
+ module Tagging
4
+ def self.included(base)
5
+ base.include InstanceMethods
6
+ end
7
+ ## Add tags support to the client, the tags have to be passed in at initialization or at the time of the metric
8
+ # tags are a hash of key value pairs
9
+ module InstanceMethods
10
+ def check_tags(tags)
11
+ raise InvalidMetric, 'Tags must be a hash' unless tags.is_a?(Hash)
12
+ ## All keys need to be string and start with a letter, they can contain letters, numbers, underscores.
13
+ # They cannot contain spaces, dashes, or other special characters.
14
+ # They cannot be longer than 32 characters
15
+ # They cannot be empty
16
+ raise InvalidMetric, 'Tags keys must be basic string' unless tags.keys.all? { |k| k.is_a?(String) && k.match?(/^[a-zA-Z][a-zA-Z0-9_]{0,31}$/) }
17
+ raise InvalidMetric, 'Tags must be a hash of key value pairs' unless tags.values.all? { |v| v.is_a?(String) }
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'activemeasure'
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'active_measure/client'
4
+ require_relative 'active_measure/configuration'
5
+ require_relative 'active_measure/adapters'
6
+
7
+ module ActiveMeasure
8
+ end
9
+
@@ -0,0 +1,20 @@
1
+ module ActiveMeasure
2
+ VERSION: String
3
+
4
+ class Client
5
+ type connection_string_type = String | Hash[String, untyped] | nil
6
+ type tags_type = Hash[String, String]
7
+
8
+ DEFAULT_CONNECTION_STRING: String
9
+
10
+ attr_reader connection_string: URI::Generic
11
+ attr_reader logger: Logger
12
+ attr_reader tags: tags_type
13
+
14
+ def initialize: (?connection_string: connection_string_type, ?logger: Logger, ?tags: tags_type) -> void
15
+
16
+ def parse_connection_string: (connection_string_type) -> URI::Generic
17
+
18
+ def filter_tags: (tags_type?) -> tags_type
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activemeasure
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Abdelkader Boudih
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-06-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ActiveMeasure is vendor agnostic metrics library for Ruby and Rails.
14
+ email:
15
+ - seuros@pre-history.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/active_measure.rb
21
+ - lib/active_measure/adapters.rb
22
+ - lib/active_measure/adapters/base.rb
23
+ - lib/active_measure/adapters/sink.rb
24
+ - lib/active_measure/adapters/statsd.rb
25
+ - lib/active_measure/adapters/statsd_socket.rb
26
+ - lib/active_measure/adapters/statsd_tagged.rb
27
+ - lib/active_measure/assertions.rb
28
+ - lib/active_measure/buffer.rb
29
+ - lib/active_measure/client.rb
30
+ - lib/active_measure/configuration.rb
31
+ - lib/active_measure/logging.rb
32
+ - lib/active_measure/railtie.rb
33
+ - lib/active_measure/sampler.rb
34
+ - lib/active_measure/serializer.rb
35
+ - lib/active_measure/tagging.rb
36
+ - lib/activemeasure.rb
37
+ - sig/activecypher.rbs
38
+ homepage: https://github.com/seuros/activemetric
39
+ licenses:
40
+ - MIT
41
+ metadata:
42
+ homepage_uri: https://github.com/seuros/activemetric
43
+ source_code_uri: https://github.com/seuros/activemetric
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.0.6
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.2.33
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: ActiveMeasure is vendor agnostic metrics library for Ruby and Rails.
63
+ test_files: []