logglier 0.0.5 → 0.1.0

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/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source :gemcutter
2
2
 
3
- gemspec 'logglier'
3
+ gemspec
4
+
5
+ gem "jruby-openssl", :platforms => :jruby
data/README.md CHANGED
@@ -3,7 +3,8 @@ Overview
3
3
 
4
4
  Send logged messages to Loggly using either the HTTP API or Syslog/UDP.
5
5
 
6
- Can be used in place of Ruby's Logger (<http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/>)
6
+ Can be used in place of Ruby's Logger
7
+ (<http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/>)
7
8
 
8
9
  In fact, it (currently) returns an instance of Logger.
9
10
 
@@ -32,21 +33,35 @@ Input URLs
32
33
  ### HTTP Inputs
33
34
  Logglier.new('https://logs.loggly.com/inputs/<id>')
34
35
 
35
- The id is provided by loggly, look at the input's details page
36
- To make sure the http client doesn't block too long read_timeout and
36
+ The id is provided by loggly, look at the input's details page To make
37
+ sure the http client doesn't block too long read_timeout and
37
38
  open_timeout are set to 2 seconds by default. This can be overridden
38
39
  like so:
39
40
 
40
- Logglier.new(:input_url => 'https://logs.loggle.com/inputs/<id>',
41
+ Logglier.new('https://logs.loggly.com/inputs/<id>',
41
42
  :read_timeout => <#>,
42
43
  :open_timeout => <#> )
43
44
 
45
+ #### Threaded Delivery
46
+
47
+ Creating a new Logglier instance, pointed at a http input, with the
48
+ `:threaded => true` option will tell Logglier to deliver log messages
49
+ for that logger in a seperate thread. Each new Logglier instance gets
50
+ it's own delivery thread and those threads are joined at exit to ensure
51
+ log message delivery.
52
+
53
+ Example:
54
+
55
+ Logglier.new('https://logs.loggly.com/inputs/<id>',
56
+ :threaded => true)
57
+
44
58
  ### Syslog TCP/UDP Inputs
45
59
 
46
60
  Logglier.new('[udp|tcp]://<hostname>:<port>/<facility>')
47
61
 
48
62
  The facility is optional and defaults to 16 (local0) if none is
49
- specified. Facilities are just integers from 0 to 23, see <http://www.faqs.org/rfcs/rfc3164.html>
63
+ specified. Facilities are just integers from 0 to 23, see
64
+ <http://www.faqs.org/rfcs/rfc3164.html>
50
65
 
51
66
 
52
67
  Logging
@@ -86,4 +101,4 @@ TODO
86
101
 
87
102
  * Alternative https implementations (Typheous, Excon, etc). May be
88
103
  faster?
89
- * Do logging in a seperate thread. Is this useful? Too complex?
104
+ * EM Integration?
@@ -0,0 +1,42 @@
1
+ module Logglier
2
+
3
+ module Client
4
+
5
+ module HTTP
6
+
7
+ class Sync
8
+ include Logglier::Client::InstanceMethods
9
+
10
+ attr_reader :input_uri, :http
11
+
12
+ def initialize(opts={})
13
+ setup_input_uri(opts)
14
+
15
+ @http = Net::HTTP.new(@input_uri.host, @input_uri.port)
16
+ if @input_uri.scheme == 'https'
17
+ @http.use_ssl = true
18
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
+ end
20
+
21
+ @http.read_timeout = opts[:read_timeout] || 2
22
+ @http.open_timeout = opts[:open_timeout] || 2
23
+ end
24
+
25
+ # Required by Logger::LogDevice
26
+ def write(message)
27
+ begin
28
+ @http.request_post(@input_uri.path, message)
29
+ rescue TimeoutError => e
30
+ $stderr.puts "WARNING: TimeoutError posting message: #{message}"
31
+ end
32
+ end
33
+
34
+ # Required by Logger::LogDevice
35
+ def close
36
+ nil
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,98 @@
1
+ require 'thread'
2
+
3
+ module Logglier
4
+
5
+ module Client
6
+
7
+ module HTTP
8
+
9
+ # Used by the Threaded client to hold a queue, deliver messsages from it
10
+ # and to ensure it's flushed on program exit.
11
+ #
12
+ # Not meant to be used directly.
13
+ class DeliveryThread < Thread
14
+
15
+ # @param [URI] input_uri The uri to deliver messags to
16
+ # @param [Integer] read_timeout Read timeout for the http session. defaults to 120
17
+ # @param [Integer] open_timeout Open timeout for the http session. defaults to 120
18
+ #
19
+ # @note registers an at_exit handler that signals exit intent and joins the thread.
20
+ def initialize(input_uri, read_timeout=120, open_timeout=120)
21
+
22
+ @input_uri = input_uri
23
+
24
+ @http = Net::HTTP.new(@input_uri.host, @input_uri.port)
25
+ if @input_uri.scheme == 'https'
26
+ @http.use_ssl = true
27
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
28
+ end
29
+
30
+ @http.read_timeout = read_timeout
31
+ @http.open_timeout = open_timeout
32
+
33
+ @queue = Queue.new
34
+ @exiting = false
35
+
36
+ super do
37
+ until @exiting && @queue.empty?
38
+ deliver(@queue.pop)
39
+ end
40
+ end
41
+
42
+ at_exit {
43
+ exit!
44
+ join
45
+ }
46
+ end
47
+
48
+ # Signals the queue that we're exiting
49
+ def exit!
50
+ @exiting = true
51
+ @queue.push(:__delivery_thread_exit_signal__)
52
+ end
53
+
54
+ # Delivers individual messages via http
55
+ def deliver(message)
56
+ unless message == :__delivery_thread_exit_signal__
57
+ begin
58
+ @http.request_post(@input_uri.path, message)
59
+ rescue TimeoutError => e
60
+ $stderr.puts "WARNING: TimeoutError posting message: #{message}"
61
+ end
62
+ end
63
+ end
64
+
65
+ # Pushes a message onto the internal queue
66
+ def push(message)
67
+ @queue.push(message)
68
+ end
69
+ end
70
+
71
+ # Interface to the DeliveryThread
72
+ class Threaded
73
+ include Logglier::Client::InstanceMethods
74
+
75
+ attr_reader :input_uri, :delivery_thread
76
+
77
+ def initialize(opts={})
78
+ setup_input_uri(opts)
79
+ @delivery_thread = DeliveryThread.new(@input_uri, opts[:read_timeout] || 120, opts[:open_timeout] || 120)
80
+ end
81
+
82
+ # Required by Logger::LogDevice
83
+ # @param [String] message the message to deliver
84
+ #
85
+ # @note doesn't do actual deliver. Pushes the messages off to the delivery thread
86
+ def write(message)
87
+ @delivery_thread.push(message)
88
+ end
89
+
90
+ # Required by Logger::LogDevice
91
+ def close
92
+ nil
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
@@ -2,48 +2,20 @@ require 'net/https'
2
2
  require 'uri'
3
3
 
4
4
  module Logglier
5
-
6
5
  module Client
6
+ module HTTP
7
7
 
8
- class HTTP
9
- include Logglier::Client::InstanceMethods
10
-
11
- attr_reader :input_uri, :http
12
-
13
- def initialize(opts={})
14
- setup_input_uri(opts)
15
-
16
- @http = Net::HTTP.new(@input_uri.host, @input_uri.port)
17
- if @input_uri.scheme == 'https'
18
- @http.use_ssl = true
19
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
20
- end
21
-
22
- @http.read_timeout = opts[:read_timeout] || 2
23
- @http.open_timeout = opts[:open_timeout] || 2
24
- end
25
-
26
- # Required by Logger::LogDevice
27
- def write(message)
28
- begin
29
- @http.request_post(@input_uri.path, message)
30
- rescue TimeoutError => e
31
- $stderr.puts "WARNING: TimeoutError posting message: #{message}"
32
- end
33
- end
34
-
35
- def formatter
36
- proc do |severity, datetime, progname, msg|
37
- message = "#{datetime} "
38
- message << massage_message(msg, severity)
8
+ def self.new(opts={})
9
+ if opts[:threaded]
10
+ Logglier::Client::HTTP::Threaded.new(opts)
11
+ else
12
+ Logglier::Client::HTTP::Sync.new(opts)
39
13
  end
40
14
  end
41
15
 
42
- # Required by Logger::LogDevice
43
- def close
44
- nil
45
- end
46
-
47
16
  end
48
17
  end
49
18
  end
19
+
20
+ require File.join(File.dirname(__FILE__), 'http', 'sync')
21
+ require File.join(File.dirname(__FILE__), 'http', 'threaded')
@@ -1,12 +1,21 @@
1
1
  module Logglier
2
2
  module Client
3
3
 
4
- def self.new(opts={})
5
- if opts.nil? or opts.empty?
6
- raise InputURLRequired.new
4
+ # Creates a new loggly client, based on a url scheme and options provided
5
+ # @param [Hash,String] opts the options hash or url string
6
+ # @option opts [String] :input_url The Loggly input_url
7
+ #
8
+ # If a url string is passed, it becomes {:input_url => <string>}
9
+ #
10
+ #
11
+ # @raise [Logglier::UnsupportedScheme] if the :input_url isn't recognized
12
+ # @return [Logglier::Client::HTTP, Logglier::Client::Syslog] returns an instance of the Logglier Client class
13
+ def self.new(input_url, opts={})
14
+ unless input_url
15
+ raise URLRequired.new
7
16
  end
8
17
 
9
- opts = { :input_url => opts } if opts.is_a?(String)
18
+ opts.merge!({ :input_url => input_url })
10
19
 
11
20
  begin
12
21
  input_uri = URI.parse(opts[:input_url])
@@ -46,6 +55,13 @@ module Logglier
46
55
  end.join(", ")
47
56
  end
48
57
 
58
+ def formatter
59
+ proc do |severity, datetime, progname, msg|
60
+ message = "#{datetime} "
61
+ message << massage_message(msg, severity)
62
+ end
63
+ end
64
+
49
65
  def massage_message(incoming_message, severity)
50
66
  outgoing_message = ""
51
67
  outgoing_message << "severity=#{severity}, "
@@ -66,7 +82,7 @@ module Logglier
66
82
  begin
67
83
  @input_uri = URI.parse(@input_uri)
68
84
  rescue URI::InvalidURIError => e
69
- raise InputURLRequired.new("Invalid Input URL: #{@input_uri}")
85
+ raise URLRequired.new("Invalid Input URL: #{@input_uri}")
70
86
  end
71
87
  end
72
88
 
@@ -1,3 +1,3 @@
1
1
  module Logglier
2
- VERSION = '0.0.5'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/logglier.rb CHANGED
@@ -8,8 +8,8 @@ module Logglier
8
8
  class UnsupportedScheme < ArgumentError; end
9
9
  class UnknownFacility < ArgumentError; end
10
10
 
11
- def self.new(opts={})
12
- client = Logglier::Client.new(opts)
11
+ def self.new(url, opts={})
12
+ client = Logglier::Client.new(url, opts)
13
13
  logger = Logger.new(client)
14
14
 
15
15
  if client.respond_to?(:formatter)
data/logglier.gemspec CHANGED
@@ -4,15 +4,15 @@ require File.expand_path(File.join(dir, 'lib', 'logglier', 'version'))
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "logglier"
6
6
  s.version = Logglier::VERSION
7
- s.date = '2011-02-25'
7
+ s.date = Time.now
8
8
  s.summary = "Loggly 'plugin' for Logger"
9
9
  s.description =<<EOD
10
10
  Logger => Loggly
11
11
  EOD
12
12
 
13
13
  s.authors = ["Edward Muller (aka freeformz)"]
14
- s.email =
15
- s.homepage = "http://loggly.com"
14
+ s.email = "edwardam@interlix.com"
15
+ s.homepage = "http://icanhazdowntime.org"
16
16
 
17
17
  s.files = %w{ README.md Gemfile LICENSE logglier.gemspec Rakefile } + Dir["#{dir}/lib/**/*.rb"]
18
18
  s.require_paths = ["lib"]
data/spec/client_spec.rb CHANGED
@@ -7,7 +7,7 @@ describe Logglier::Client do
7
7
  context "w/o any params" do
8
8
 
9
9
  it "should raise an error" do
10
- expect { Logglier::Client.new() }.to raise_error Logglier::InputURLRequired
10
+ expect { Logglier::Client.new() }.to raise_error ArgumentError
11
11
  end
12
12
 
13
13
  end
@@ -18,7 +18,7 @@ describe Logglier::Client do
18
18
 
19
19
  it "should return an instance of the proper client" do
20
20
  log = Logglier::Client.new('http://localhost')
21
- log.should be_an_instance_of Logglier::Client::HTTP
21
+ log.should be_an_instance_of Logglier::Client::HTTP::Sync
22
22
  end
23
23
 
24
24
  end
@@ -1,12 +1,24 @@
1
1
  describe Logglier do
2
2
 
3
3
  context "HTTPS" do
4
- subject { new_logglier('https://localhost') }
5
4
 
6
- it { should be_an_instance_of Logger }
7
- its('logdev.dev') { should be_an_instance_of Logglier::Client::HTTP }
5
+ context "w/o any options" do
6
+ subject { new_logglier('https://localhost') }
8
7
 
9
- it_should_behave_like "a logglier enhanced Logger instance"
8
+ it { should be_an_instance_of Logger }
9
+ its('logdev.dev') { should be_an_instance_of Logglier::Client::HTTP::Sync }
10
+
11
+ it_should_behave_like "a logglier enhanced Logger instance"
12
+ end
13
+
14
+ context "w/threaded option" do
15
+ subject { new_logglier('https://localhost', :threaded => true) }
16
+
17
+ it { should be_an_instance_of Logger }
18
+ its('logdev.dev') { should be_an_instance_of Logglier::Client::HTTP::Threaded }
19
+
20
+ it_should_behave_like "a logglier enhanced Logger instance"
21
+ end
10
22
 
11
23
  end
12
24
 
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
2
 
3
- require 'lib/logglier'
3
+ require 'logglier'
4
4
 
5
5
  module LoggerHacks
6
6
  def logdev
@@ -21,8 +21,8 @@ RSpec.configure do |config|
21
21
  def send(*args); end
22
22
  end
23
23
 
24
- def new_logglier(url)
25
- log = Logglier.new(url)
24
+ def new_logglier(url,opts={})
25
+ log = Logglier.new(url,opts)
26
26
  log.extend(LoggerHacks)
27
27
  end
28
28
 
@@ -39,10 +39,14 @@ shared_examples_for "a logglier enhanced Logger instance" do
39
39
 
40
40
  context "with a hash" do
41
41
  it "should send a message via the logdev" do
42
- subject.logdev.dev.should_receive(:write).with(/severity=WARN, foo=bar, man=pants/)
42
+ subject.logdev.dev.should_receive(:write).with(/severity=WARN/)
43
+ subject.logdev.dev.should_receive(:write).with(/foo=bar/)
44
+ subject.logdev.dev.should_receive(:write).with(/man=pants/)
43
45
  # The following is equiv to:
44
46
  # subject.warn :foo => :bar, :man => :pants
45
47
  subject.add(Logger::WARN) { {:foo => :bar, :man => :pants} }
48
+ subject.add(Logger::WARN) { {:foo => :bar, :man => :pants} }
49
+ subject.add(Logger::WARN) { {:foo => :bar, :man => :pants} }
46
50
  end
47
51
  end
48
52
  end
@@ -0,0 +1,19 @@
1
+ describe Logglier::Client::HTTP::DeliveryThread do
2
+
3
+ subject { described_class.new(URI.parse('http://localhost')) }
4
+
5
+ before do
6
+ subject.stub(:deliver)
7
+ end
8
+
9
+ it "should" do
10
+ subject.should_receive(:deliver).with("test")
11
+ subject.push('test')
12
+
13
+ #Signal the thread it's going to exit
14
+ subject.exit!
15
+
16
+ #Wait for it to exit
17
+ subject.join
18
+ end
19
+ end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logglier
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 0
9
- - 5
10
- version: 0.0.5
4
+ prerelease:
5
+ version: 0.1.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Edward Muller (aka freeformz)
@@ -15,7 +10,7 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-02-25 00:00:00 -08:00
13
+ date: 2011-05-07 00:00:00 -07:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
@@ -26,9 +21,6 @@ dependencies:
26
21
  requirements:
27
22
  - - ">="
28
23
  - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
24
  version: "0"
33
25
  type: :development
34
26
  version_requirements: *id001
@@ -40,18 +32,13 @@ dependencies:
40
32
  requirements:
41
33
  - - ~>
42
34
  - !ruby/object:Gem::Version
43
- hash: 27
44
- segments:
45
- - 2
46
- - 5
47
- - 0
48
35
  version: 2.5.0
49
36
  type: :development
50
37
  version_requirements: *id002
51
38
  description: |
52
39
  Logger => Loggly
53
40
 
54
- email: http://loggly.com
41
+ email: edwardam@interlix.com
55
42
  executables: []
56
43
 
57
44
  extensions: []
@@ -64,16 +51,19 @@ files:
64
51
  - LICENSE
65
52
  - logglier.gemspec
66
53
  - Rakefile
67
- - ./lib/logglier.rb
68
- - ./lib/logglier/client.rb
69
- - ./lib/logglier/version.rb
54
+ - ./lib/logglier/client/http/sync.rb
55
+ - ./lib/logglier/client/http/threaded.rb
70
56
  - ./lib/logglier/client/http.rb
71
57
  - ./lib/logglier/client/syslog.rb
58
+ - ./lib/logglier/client.rb
59
+ - ./lib/logglier/version.rb
60
+ - ./lib/logglier.rb
72
61
  - ./spec/client_spec.rb
73
62
  - ./spec/logglier_spec.rb
74
63
  - ./spec/spec_helper.rb
64
+ - ./spec/threaded_spec.rb
75
65
  has_rdoc: true
76
- homepage: http://loggly.com
66
+ homepage: http://icanhazdowntime.org
77
67
  licenses: []
78
68
 
79
69
  post_install_message:
@@ -86,23 +76,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
76
  requirements:
87
77
  - - ">="
88
78
  - !ruby/object:Gem::Version
89
- hash: 3
90
- segments:
91
- - 0
92
79
  version: "0"
93
80
  required_rubygems_version: !ruby/object:Gem::Requirement
94
81
  none: false
95
82
  requirements:
96
83
  - - ">="
97
84
  - !ruby/object:Gem::Version
98
- hash: 3
99
- segments:
100
- - 0
101
85
  version: "0"
102
86
  requirements: []
103
87
 
104
88
  rubyforge_project: logglier
105
- rubygems_version: 1.3.7
89
+ rubygems_version: 1.6.2
106
90
  signing_key:
107
91
  specification_version: 3
108
92
  summary: Loggly 'plugin' for Logger
@@ -110,3 +94,4 @@ test_files:
110
94
  - ./spec/client_spec.rb
111
95
  - ./spec/logglier_spec.rb
112
96
  - ./spec/spec_helper.rb
97
+ - ./spec/threaded_spec.rb