fnord-client 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ross Kaffenberger
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Fnord::Client
2
+
3
+ Send events to an [FnordMetric](https://github.com/paulasmuth/fnordmetric) server via UDP (or TCP).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'fnord-client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install fnord-client
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ # Connect to FnordMetric inbound stream over UDP (default)
23
+ $fnord = Fnord::Client('localhost', 1337)
24
+
25
+ # Connect to FnordMetric inbound stream over TCP
26
+ $fnord = Fnord::Client('localhost', 1337, :protocol => :tcp)
27
+
28
+ # send JSON-encoded event
29
+ $fnord.event("message_received", { :user_id => 123 })
30
+ # "{\"_type\":\"message_received\",\"user_id\":\"123\"}"
31
+
32
+ # configure FnordMetric namespace
33
+ Fnord::Client.namespace = "staging"
34
+ $fnord.event("message_received")
35
+ # "{\"_type\":\"message_received\",\"_namespace\":\"staging\"}"
36
+ ```
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
10
+ # Put spec opts in a file named .rspec in root
11
+ end
12
+
13
+ desc "Generate code coverage"
14
+ RSpec::Core::RakeTask.new(:coverage) do |t|
15
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
16
+ t.rcov = true
17
+ t.rcov_opts = ['--exclude', 'spec']
18
+ end
19
+
20
+ desc "Run the specs"
21
+ task :default => ["spec"]
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/fnord/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ross Kaffenberger"]
6
+ gem.email = ["rosskaff@gmail.com"]
7
+ gem.description = %q{A client for sending events to an FnordMetric server over UDP (or TCP)}
8
+ gem.summary = %q{A client for sending events to an FnordMetric server over UDP (or TCP)}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(spec)/})
14
+ gem.name = "fnord-client"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Fnord::VERSION
17
+
18
+ gem.add_dependency "yajl-ruby"
19
+ gem.add_development_dependency "rake"
20
+ gem.add_development_dependency "rspec"
21
+ end
@@ -0,0 +1,7 @@
1
+ require "fnord/version"
2
+
3
+ module Fnord
4
+ autoload :Client, 'fnord/client'
5
+ autoload :UDPConnection, 'fnord/udp_connection'
6
+ autoload :TCPConnection, 'fnord/tcp_connection'
7
+ end
@@ -0,0 +1,67 @@
1
+ require 'yajl'
2
+
3
+ module Fnord
4
+ class Client
5
+ attr_reader :host, :port, :options
6
+
7
+ class << self
8
+ # Set to any standard logger instance (including stdlib's Logger) to enable
9
+ # stat logging using logger.debug
10
+ attr_accessor :logger, :namespace
11
+ end
12
+
13
+ attr_accessor :connection
14
+
15
+ def initialize(host, port = 1337, options = {})
16
+ @host, @port, @options = host, port, options
17
+ end
18
+
19
+ def event(*args)
20
+ message = extract_options!(args)
21
+ event_name = args.shift
22
+ message[:_type] = event_name if event_name
23
+ message[:_namespace] = self.class.namespace unless message[:_namespace]
24
+ message = stringify_values(message)
25
+ send_to_connection(to_json(message))
26
+ end
27
+
28
+ def connection
29
+ @connection ||= connection_class.new(@host, @port, @options)
30
+ end
31
+
32
+ private
33
+
34
+ def protocol
35
+ @protocol ||= @options.delete(:protocol) || :udp
36
+ end
37
+
38
+ def connection_class
39
+ case protocol
40
+ when :tcp
41
+ TCPConnection
42
+ else
43
+ UDPConnection
44
+ end
45
+ end
46
+
47
+ def send_to_connection(message)
48
+ self.class.logger.debug {"Fnord: #{message}"} if self.class.logger
49
+ connection.send_data(message)
50
+ rescue => boom
51
+ self.class.logger.error {"Fnord: #{boom.class} #{boom}"} if self.class.logger
52
+ end
53
+
54
+ def stringify_values(message)
55
+ {}.tap { |hash| message.each { |k, v| hash[k] = v.to_s } }
56
+ end
57
+
58
+ def extract_options!(args)
59
+ args.last.is_a?(::Hash) ? args.pop : {}
60
+ end
61
+
62
+ def to_json(hash)
63
+ Yajl::Encoder.encode(hash)
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ module Fnord
2
+ class TCPConnection
3
+
4
+ attr_accessor :socket
5
+
6
+ def initialize(host, port = 1337, options = {})
7
+ @host, @port, @options = host, port, options
8
+ end
9
+
10
+ def send_data(data)
11
+ ensure_connected(:retry => true) do
12
+ # Rails.logger.info "[FNORD] Sending data\n#{data}"
13
+ @socket.puts(data)
14
+ @socket.flush
15
+ end
16
+ end
17
+
18
+ def connect
19
+ @socket = TCPSocket.new(@host, @port)
20
+ end
21
+
22
+ def reconnect
23
+ # untested
24
+ disconnect
25
+ connect
26
+ end
27
+
28
+ def disconnect
29
+ # untested
30
+ return unless connected?
31
+
32
+ begin
33
+ @socket.close
34
+ rescue
35
+ ensure
36
+ @socket = nil
37
+ end
38
+ end
39
+
40
+ def connected?
41
+ !!@socket
42
+ end
43
+
44
+ private
45
+
46
+ def ensure_connected(opts = {}, &block)
47
+ begin
48
+ connect unless connected?
49
+ yield
50
+ rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::ECONNREFUSED => e
51
+ if opts[:retry]
52
+ ensure_connected(:retry => false, &block)
53
+ else
54
+ if @options[:raise_errors]
55
+ raise e
56
+ else
57
+ # Rails.logger.warn "[FNORD] Could not connect to fnord at #{@host}:#{@port}"
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ module Fnord
2
+ class UDPConnection
3
+
4
+ attr_accessor :socket
5
+
6
+ def initialize(host, port = 1337, options = {})
7
+ @host, @port, @options = host, port, options
8
+ end
9
+
10
+ def send_data(data)
11
+ # Rails.logger.info "[FNORD] Sending data\n#{data}"
12
+ socket.send(data, 0, @host, @port)
13
+ end
14
+
15
+ def socket
16
+ @socket ||= UDPSocket.new
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,3 @@
1
+ module Fnord
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fnord::Client do
4
+ let(:client) { Fnord::Client.new('localhost', 1339) }
5
+ let(:connection) { stub(Fnord::UDPConnection) }
6
+
7
+ describe "initialize" do
8
+ before { Fnord::Client.namespace = "clientapp_test" }
9
+ it { Fnord::Client.namespace.should == "clientapp_test" }
10
+ it { client.host.should == 'localhost' }
11
+ it { client.port.should == 1339 }
12
+ end
13
+
14
+ describe "event" do
15
+ before { client.connection = connection }
16
+
17
+ it "should send hash as json via connection" do
18
+ data = { "one" => "1" }
19
+ connection.should_receive(:send_data).with(%Q|{"one":"1","_namespace":"clientapp_test\"}|)
20
+ client.event(data)
21
+ end
22
+
23
+ it "should send numeric values as strings" do
24
+ data = { "one" => 1 }
25
+ connection.should_receive(:send_data).with(/#{%Q|"one":"1"|}/)
26
+ client.event(data)
27
+ end
28
+
29
+ it "should merge event type when given as first arg" do
30
+ data = { "one" => "1", "two" => 2 }
31
+ connection.should_receive(:send_data).with(%Q|{"one":"1","two":"2","_type":"logged_in","_namespace":"clientapp_test\"}|)
32
+ client.event("logged_in", data)
33
+ end
34
+ end
35
+
36
+ describe "connection" do
37
+ it "connects uses UDP strategy by default" do
38
+ client.connection.should be_kind_of(Fnord::UDPConnection)
39
+ end
40
+
41
+ it "connects set TCP strategy via option" do
42
+ client = Fnord::Client.new('localhost', 1337, :protocol => :tcp)
43
+ client.connection.should be_kind_of(Fnord::TCPConnection)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fnord::TCPConnection do
4
+
5
+ class FakeTCPSocket
6
+
7
+ def puts(data)
8
+ @data ||= []
9
+ @data << data
10
+ end
11
+
12
+ def flush
13
+ @data = nil
14
+ end
15
+
16
+ def close; end
17
+ end
18
+
19
+ let(:connection) { Fnord::TCPConnection.new('localhost', 1337) }
20
+ let(:socket) { FakeTCPSocket.new }
21
+
22
+ before {
23
+ TCPSocket.stub!(:new).and_return(socket)
24
+ connection.socket = socket
25
+ }
26
+
27
+ describe "disconnect" do
28
+ it "closes the socket" do
29
+ socket.should_receive(:close)
30
+ connection.disconnect
31
+ end
32
+
33
+ it "removes socket reference" do
34
+ connection.disconnect
35
+ connection.socket.should be_nil
36
+ end
37
+ end
38
+
39
+ describe "connected?" do
40
+ it "true if socket exists" do
41
+ connection.socket = socket
42
+ connection.connected?.should be_true
43
+ end
44
+
45
+ it "false if socket doesn't exist" do
46
+ connection.socket = nil
47
+ connection.connected?.should be_false
48
+ end
49
+ end
50
+
51
+ describe "send_data" do
52
+
53
+ it "should puts data and flush over socket" do
54
+ socket.should_receive(:puts).with("data")
55
+ socket.should_receive(:flush)
56
+ connection.send_data("data")
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fnord::UDPConnection do
4
+ class FakeUDPSocket
5
+ def send(data); end
6
+ end
7
+
8
+ let(:connection) {
9
+ Fnord::UDPConnection.new('localhost', 1339)
10
+ }
11
+ let(:socket) { FakeUDPSocket.new }
12
+
13
+ describe "send_data" do
14
+
15
+ it "should send data to initialized host, port" do
16
+ UDPSocket.should_receive(:new).and_return(socket)
17
+ socket.should_receive(:send).with("data", 0, 'localhost', 1339)
18
+ connection.send_data("data")
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,12 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+
4
+ require 'rspec/autorun'
5
+ require 'fnord-client'
6
+
7
+ # Load support files
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
9
+
10
+ RSpec.configure do |config|
11
+ config.mock_with :rspec
12
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fnord-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ross Kaffenberger
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: yajl-ruby
16
+ requirement: &70294812549400 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70294812549400
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70294812548960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70294812548960
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70294812548540 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70294812548540
47
+ description: A client for sending events to an FnordMetric server over UDP (or TCP)
48
+ email:
49
+ - rosskaff@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - LICENSE
57
+ - README.md
58
+ - Rakefile
59
+ - fnord-client.gemspec
60
+ - lib/fnord-client.rb
61
+ - lib/fnord/client.rb
62
+ - lib/fnord/tcp_connection.rb
63
+ - lib/fnord/udp_connection.rb
64
+ - lib/fnord/version.rb
65
+ - spec/fnord/client_spec.rb
66
+ - spec/fnord/tcp_connection_spec.rb
67
+ - spec/fnord/udp_connection_spec.rb
68
+ - spec/spec_helper.rb
69
+ homepage: ''
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ segments:
82
+ - 0
83
+ hash: 3790659374809875027
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 3790659374809875027
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.10
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A client for sending events to an FnordMetric server over UDP (or TCP)
99
+ test_files:
100
+ - spec/fnord/client_spec.rb
101
+ - spec/fnord/tcp_connection_spec.rb
102
+ - spec/fnord/udp_connection_spec.rb
103
+ - spec/spec_helper.rb