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 +7 -0
- data/lib/active_measure/adapters/base.rb +53 -0
- data/lib/active_measure/adapters/sink.rb +9 -0
- data/lib/active_measure/adapters/statsd.rb +71 -0
- data/lib/active_measure/adapters/statsd_socket.rb +8 -0
- data/lib/active_measure/adapters/statsd_tagged.rb +8 -0
- data/lib/active_measure/adapters.rb +25 -0
- data/lib/active_measure/assertions.rb +7 -0
- data/lib/active_measure/buffer.rb +15 -0
- data/lib/active_measure/client.rb +84 -0
- data/lib/active_measure/configuration.rb +32 -0
- data/lib/active_measure/logging.rb +20 -0
- data/lib/active_measure/railtie.rb +13 -0
- data/lib/active_measure/sampler.rb +5 -0
- data/lib/active_measure/serializer.rb +46 -0
- data/lib/active_measure/tagging.rb +22 -0
- data/lib/active_measure.rb +3 -0
- data/lib/activemeasure.rb +9 -0
- data/sig/activecypher.rbs +20 -0
- metadata +63 -0
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,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,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,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,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,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: []
|