activemeasure 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []