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