Skip to content

Commit

Permalink
Add Passthrough transform and formatter
Browse files Browse the repository at this point in the history
These are useful for custom targets that might not need/want any
transforms for formatting, or to mix-and-match. For example, image a
custom `LogTarget` that can be configured with a `:logger` option. It
could be that the logger itself already knows how to format they
telemetry data, (e.g., into key/value pairs), and so we don't want/need
the Target to do any formatting.

This allows this plugin's config to look like this:

```ruby
Puma::Plugin::Telemetry.configure do |config|
  config.add_target(CustomLogTarget, logger: Logfmt.logger, transform: :cloud_watch, formatter: :noop)
end
```
  • Loading branch information
stevenharman committed Jul 3, 2024
1 parent 2a4a191 commit b95b291
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 15 deletions.
2 changes: 1 addition & 1 deletion lib/puma/plugin/telemetry/formatters/json_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Puma
class Plugin
module Telemetry
module Formatters
# JSON formatter for IO, expects `call` method accepting telemetry hash
# JSON formatter, expects `call` method accepting telemetry hash
#
class JSONFormatter
def self.call(telemetry)
Expand Down
16 changes: 16 additions & 0 deletions lib/puma/plugin/telemetry/formatters/passthrough_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Puma
class Plugin
module Telemetry
module Formatters
# A passthrough formatter - it returns the telemetry Hash it was given
class PassthroughFormatter
def self.call(telemetry)
telemetry
end
end
end
end
end
end
38 changes: 38 additions & 0 deletions lib/puma/plugin/telemetry/targets/base_formatting_target.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require_relative '../formatters/json_formatter'
require_relative '../formatters/passthrough_formatter'
require_relative '../transforms/cloud_watch_transform'
require_relative '../transforms/passthrough_transform'

module Puma
class Plugin
module Telemetry
module Targets
# A base class for other Targets concerned with formatting telemetry
class BaseFormattingTarget
def initialize(formatter: :json, transform: :cloud_watch)
@transform = case transform
when :cloud_watch then Transforms::CloudWatchTranform
when :passthrough then Transforms::PassthroughTransform
else transform
end
@formatter = case formatter
when :json then Formatters::JSONFormatter
when :passthrough then Formatters::PassthroughFormatter
else formatter
end
end

def call(_telemetry)
raise "#{__method__} must be implemented by #{self.class.name}"
end

private

attr_reader :formatter, :transform
end
end
end
end
end
17 changes: 4 additions & 13 deletions lib/puma/plugin/telemetry/targets/io_target.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
# frozen_string_literal: true

require_relative '../formatters/json_formatter'
require_relative '../transforms/cloud_watch_transform'
require_relative 'base_formatting_target'

module Puma
class Plugin
module Telemetry
module Targets
# Simple IO Target, publishing metrics to STDOUT or logs
#
class IOTarget
class IOTarget < BaseFormattingTarget
def initialize(io: $stdout, formatter: :json, transform: :cloud_watch)
super(formatter: formatter, transform: transform)
@io = io
@transform = case transform
when :cloud_watch then Transforms::CloudWatchTranform
else transform
end
@formatter = case formatter
when :json then Formatters::JSONFormatter
else formatter
end
end

def call(telemetry)
Expand All @@ -28,7 +19,7 @@ def call(telemetry)

private

attr_reader :formatter, :io, :transform
attr_reader :io
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions lib/puma/plugin/telemetry/transforms/passthrough_transform.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Puma
class Plugin
module Telemetry
module Transforms
# A passthrough transform - it returns the telemetry Hash it was given
class PassthroughTransform
def self.call(telemetry)
telemetry
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion spec/fixtures/sockets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

Puma::Plugin::Telemetry.configure do |config|
# Simple `key=value` formatter
config.add_target(:io, formatter: ->(t) { t.map { |r| r.join('=') }.join(' ') }, transform: ->(t) { t })
config.add_target(:io, formatter: ->(t) { t.map { |r| r.join('=') }.join(' ') }, transform: :passthrough)
config.frequency = 1
config.enabled = true

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Puma
class Plugin
module Telemetry
module Formatters
RSpec.describe PassthroughFormatter do
subject(:formatter) { described_class }

it 'returns the telemetry, unalterted' do
telmetry_data = { 'foo' => 'bar' }
formatted_data = formatter.call(telmetry_data)

expect(formatted_data).to eq(telmetry_data)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Puma
class Plugin
module Telemetry
module Transforms
RSpec.describe PassthroughTransform do
subject(:transform) { described_class }

it 'returns the telemetry, unalterted' do
telmetry_data = { 'foo' => 'bar' }
transformed_data = transform.call(telmetry_data)

expect(transformed_data).to eq(telmetry_data)
end
end
end
end
end
end

0 comments on commit b95b291

Please sign in to comment.