Skip to content

Commit

Permalink
Merge branch 'master' into feature/improve_appsignal_to_support_tagging
Browse files Browse the repository at this point in the history
  • Loading branch information
Vuta committed Nov 12, 2020
2 parents ee4e7a1 + 2a17bc7 commit 1121f63
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ language: ruby
cache: bundler
rvm:
- 2.6.6
before_install: gem install bundler
before_install: gem install bundler
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ This gem currently supports only:
1. increment_counter
2. add_distribution_value
3. set_gauge
3. Datadog: Empty wrapper around the custom metric distributions
1. count
2. distribution
3. set
4. gauge
5. histogram

No dependencies are declared for this as the

Expand Down Expand Up @@ -50,6 +56,7 @@ Each initialised logger is then registered to `EventTracer`.
```ruby
EventTracer.register :base, base_logger
EventTracer.register :appsignal, appsignal_logger
EventTracer.register :datadog, datadog_logger
```

As this is a registry, you can set it up with your own implemented wrapper as long as it responds to the following `LOG_TYPES` methods: `info, warn, error`
Expand Down Expand Up @@ -119,6 +126,35 @@ EventTracer.info(
)
# This calls .increment_counter on Appsignal once with additional tag
# counter_1, 1, region: 'eu'

**3. Datadog**

Datadog via dogstatsd-ruby (4.8.1) is currently supported for the following metric functions available for the EventTracer's log methods
- increment
- distribution
- set
- gauge
- histogram
All other functions are exposed transparently to the underlying Appsignal class
The interface for using the Appsignal wrapper is:
Key | Secondary key | Secondary key type | Values
--------------|-------------|------------------|-------
datadog | count | Hash | Hash of key-value pairs featuring the metric name and the counter value to send
| | distribution | Hash | Hash of key-value pairs featuring the metric name and the distribution value to send
| | set | Hash | Hash of key-value pairs featuring the metric name and the set value to send
| | gauge | Hash | Hash of key-value pairs featuring the metric name and the gauge value to send
| | histogram | Hash | Hash of key-value pairs featuring the metric name and the histogram value to send
```ruby
# Sample usage
EventTracer.info action: 'Action', message: 'Message', datadog: { count: { counter_1: 1, counter_2: { value: 2, tags: ['foo']} } }
# This calls .count on Datadog twice with the 2 sets of arguments
# counter_1, 1
# counter_2, 2
```
**Summary**
Expand All @@ -127,14 +163,20 @@ In all the generated interface for `EventTracer` logging could look something li
```ruby
EventTracer.info(
loggers: [:base, :appsignal, :custom_logging_service]
loggers: %(base appsignal custom_logging_service datadog),
action: 'NewTransaction',
message: "New transaction created by API",
appsignal: {
add_distribution_value: {
"distribution_metric_1" => 1000,
"distribution_metric_2" => 2000
}
},
datadog: {
distribution: {
"distribution_metric_1" => 1000,
"distribution_metric_2" => { value: 2000, tags: ['eu'] }
}
}
)
```
Expand Down
23 changes: 11 additions & 12 deletions event_tracer.gemspec
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
# coding: utf-8
lib = File.expand_path("../lib", __FILE__)
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "event_tracer/version"
require 'event_tracer/version'

Gem::Specification.new do |spec|
spec.name = "event_tracer"
spec.name = 'event_tracer'
spec.version = EventTracer::VERSION
spec.authors = ["melvrickgoh"]
spec.email = ["[email protected]"]
spec.authors = ['melvrickgoh']
spec.email = ['[email protected]']

spec.summary = %q{Thin wrapper for formatted logging/ metric services to be used as a single service}
spec.description = %q{Thin wrapper for formatted logging/ metric services to be used as a single service. External service(s) supported: Appsignal}
spec.homepage = "https://github.com/melvrickgoh/event_tracer"
spec.license = "MIT"
spec.summary = 'Thin wrapper for formatted logging/ metric services to be used as a single service'
spec.description = 'Thin wrapper for formatted logging/ metric services to be used as a single service. External service(s) supported: Appsignal'
spec.homepage = 'https://github.com/melvrickgoh/event_tracer'
spec.license = 'MIT'

spec.files = Dir['lib/**/*.rb']
spec.bindir = "exe"
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib/event_tracer", "lib"]
spec.require_paths = %w[lib/event_tracer lib]

spec.add_development_dependency "bundler", "~> 2.1.4"
spec.add_development_dependency "rake", "~> 10.0"
Expand Down
75 changes: 75 additions & 0 deletions lib/event_tracer/datadog_logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require_relative '../event_tracer'
require_relative './basic_decorator'
# NOTES
# Datadog interface to send our usual actions
# BasicDecorator adds a transparent interface on top of the datadog interface
#
# Usage: EventTracer.register :datadog, EventTracer::DataDogLogger.new(DataDog)
# data_dog_logger.info datadog: { count: { counter_1: 1, counter_2: 2 }, set: { gauge_1: 1 } }
# data_dog_logger.info datadog: { count: { counter_1: { value: 1, tags: ['tag1, tag2']} } }

module EventTracer
class DatadogLogger < BasicDecorator

class InvalidTagError < StandardError; end

SUPPORTED_METRICS ||= %i[count set distribution gauge histogram].freeze

LOG_TYPES.each do |log_type|
define_method log_type do |**args|
return LogResult.new(false, 'Invalid datadog config') unless args[:datadog]&.is_a?(Hash)

applied_metrics(args[:datadog]).each do |metric|
metric_args = args[:datadog][metric]
return LogResult.new(false, "Datadog metric #{metric} invalid") unless metric_args.is_a?(Hash)

send_metric metric, metric_args
end

LogResult.new(true)
end
end

private

attr_reader :datadog, :decoratee
alias_method :datadog, :decoratee

def applied_metrics(datadog_args)
datadog_args.keys.select { |metric| SUPPORTED_METRICS.include?(metric) }
end

def send_metric(metric, payload)
payload.each do |increment, attribute|
if attribute.is_a?(Hash)
begin
datadog.public_send(
metric,
increment,
attribute.fetch(:value),
build_options(attribute[:tags])
)
rescue KeyError
raise InvalidTagError, "Datadog payload { #{increment}: #{attribute} } invalid"
end
else
datadog.public_send(metric, increment, attribute)
end
end
end

def build_options(tags)
return {} unless tags

formattted_tags =
if tags.is_a?(Array)
tags
else
tags.inject([]) do |acc, (tag, value)|
acc << "#{tag}:#{value}"
end
end
{ tags: formattted_tags }
end
end
end
2 changes: 1 addition & 1 deletion lib/event_tracer/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module EventTracer
VERSION = "0.1.3"
VERSION = '0.2.0'.freeze
end
21 changes: 21 additions & 0 deletions spec/data_helpers/mock_datadog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class MockDatadog < Struct.new(:_)
def increment(*_args)
'increment'
end

def distribution(*_args)
'distribution'
end

def set(*_args)
'set'
end

def gauge(*_args)
'gauge'
end

def histogram(*_args)
'histogram'
end
end
Loading

0 comments on commit 1121f63

Please sign in to comment.