├── .gitignore
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── bin
└── mini_statsd
├── lib
├── mini_statsd.rb
├── port_sanitizer.rb
└── statsd_listener.rb
├── mini_statsd.gemspec
└── spec
└── port_sanitizer_spec.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | Gemfile.lock
2 | *.gem
3 | *.DS_Store
4 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem 'rspec'
4 |
5 | gemspec
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Igor Marques
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mini-StatsD
2 | A simple StatsD listener
3 |
4 | [](https://codeclimate.com/github/IgorMarques/Mini-StatsD)
5 |
6 |
7 |
8 | Mini-StatsD is just a simple UDP server that listens to (and prints) StatsD-like messages sent to some port on your system.
9 |
10 | ## Running
11 |
12 | ```shell
13 | $ gem install mini_statsd
14 | $ bundle install
15 | $ mini_statsd
16 | ```
17 |
18 | Simple as that :)
19 |
20 | If you want to set a specific port and binding host, just run:
21 |
22 | ```shell
23 | $ mini_statsd
24 | ```
25 |
26 | Like:
27 |
28 | ```shell
29 | $ mini_statsd 9125 0.0.0.0
30 | ```
31 |
32 | A simple example of a code that sends the statsd message from the gif can be found [here](https://gist.github.com/IgorMarques/079b08c3bbb13e8d896151a192262e8b)
33 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | begin
2 | require 'rspec/core/rake_task'
3 |
4 | RSpec::Core::RakeTask.new(:spec)
5 |
6 | task default: :spec
7 | rescue LoadError
8 | puts "Rspec unavaliable, please make sure it's installed."
9 | end
10 |
--------------------------------------------------------------------------------
/bin/mini_statsd:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require_relative '../lib/mini_statsd'
4 |
5 | MiniStatsd.run(ARGV)
6 |
--------------------------------------------------------------------------------
/lib/mini_statsd.rb:
--------------------------------------------------------------------------------
1 | require_relative 'statsd_listener'
2 |
3 | class MiniStatsd
4 | def self.run(args = [])
5 | StatsdListener.run(port: args[0], host: args[1])
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/port_sanitizer.rb:
--------------------------------------------------------------------------------
1 | require 'term/ansicolor'
2 |
3 | class PortSanitizer
4 | DEFAULT_PORT = 8125
5 |
6 | def self.sanitize(port = DEFAULT_PORT)
7 | color = Term::ANSIColor
8 |
9 | port = port.to_i
10 |
11 | unless port.between?(1024, 49151)
12 | puts "#{color.yellow("Invalid or no port informed. Assigning default port (#{DEFAULT_PORT})")}.\n\n"
13 |
14 | return DEFAULT_PORT
15 | end
16 |
17 | port
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/statsd_listener.rb:
--------------------------------------------------------------------------------
1 | require 'socket'
2 | require 'term/ansicolor'
3 | require_relative 'port_sanitizer'
4 |
5 | class StatsdListener
6 | include Term::ANSIColor
7 |
8 | def self.run(port: nil, host: nil)
9 | puts "Starting MiniStatsd...\n\n"
10 |
11 | new(host: host, port: port).run
12 | end
13 |
14 | def initialize(host: nil, port: nil)
15 | $stdout.sync = true
16 |
17 | @socket = UDPSocket.new
18 | @port = PortSanitizer.sanitize(port)
19 | @host = host.nil? ? '127.0.0.1' : host
20 |
21 | @socket.bind(@host, @port)
22 | end
23 |
24 | def run
25 | puts "Listening on #{@host}:#{@port}"
26 |
27 | while @message = @socket.recvfrom(@port)
28 | extract_metric
29 |
30 | print_metric
31 | end
32 | end
33 |
34 | private
35 |
36 | def extract_metric
37 | return if @message.empty?
38 |
39 | @metric, @value = @message.first.split(':')
40 | end
41 |
42 | def print_metric
43 | puts "#{bold('Metric Received')}: #{blue(@metric)} | value: #{green(@value)}"
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/mini_statsd.gemspec:
--------------------------------------------------------------------------------
1 | Gem::Specification.new do |s|
2 | s.name = 'mini_statsd'
3 |
4 | s.summary = "Mini StatsD"
5 | s.description = "A super simple StatsD receiver"
6 | s.version = '0.3.1'
7 | s.homepage = 'https://github.com/IgorMarques/Mini-StatsD'
8 | s.license = 'MIT'
9 |
10 | s.authors = ["Igor Marques"]
11 | s.email = 'igormarquessilva@gmail.com'
12 |
13 | s.executables << 'mini_statsd'
14 | s.files = [
15 | "lib/mini_statsd.rb",
16 | "lib/port_sanitizer.rb",
17 | "lib/statsd_listener.rb"
18 | ]
19 |
20 | s.add_dependency "term-ansicolor", "1.3.2"
21 | end
22 |
--------------------------------------------------------------------------------
/spec/port_sanitizer_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../lib/port_sanitizer'
2 |
3 | RSpec.describe PortSanitizer do
4 | describe "self.sanitize" do
5 | let(:default_port){ 8125 }
6 |
7 | subject { described_class.sanitize(port) }
8 |
9 | context 'a port between 1024 and 49151 is informed' do
10 | let(:port) { 8234 }
11 |
12 | it 'returns the informed port' do
13 | is_expected.to eq(port)
14 | end
15 | end
16 |
17 | context 'a port bellow 1024 is informed' do
18 | let(:port) { 1 }
19 |
20 | it 'returns the default port' do
21 | is_expected.to eq(default_port)
22 | end
23 | end
24 |
25 | context 'a port above 49151 is informed' do
26 | let(:port) { 49152 }
27 |
28 | it 'returns the default port' do
29 | is_expected.to eq(default_port)
30 | end
31 | end
32 |
33 | context 'no port is informed' do
34 | let(:port) { nil }
35 |
36 | it 'returns the default port' do
37 | is_expected.to eq(default_port)
38 | end
39 | end
40 |
41 | context 'a letter or text is informed as a port' do
42 | let(:port) { 'test' }
43 |
44 | it 'returns the default port' do
45 | is_expected.to eq(default_port)
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------