lib/timber/log_devices/http.rb in timberio-1.0.0.beta1 vs lib/timber/log_devices/http.rb in timberio-1.0.0
- old
+ new
@@ -1,28 +1,87 @@
-require File.join(File.dirname(__FILE__), "http", "log_pile")
-require File.join(File.dirname(__FILE__), "http", "log_truck")
+require "monitor"
+require "msgpack"
module Timber
module LogDevices
- class HTTP < LogDevice
- SPLIT_LINES = false
+ # A log device that buffers and sends logs to the Timber API over HTTP in intervals. The buffer
+ # uses MessagePack::Buffer, which is fast, efficient with memory, and reduces
+ # the payload size sent to Timber.
+ class HTTP
+ class DeliveryError < StandardError; end
- attr_reader :application_key
+ API_URI = URI.parse("https://api.timber.io/http_frames")
+ CONTENT_TYPE = "application/json".freeze
+ CONNECTION_HEADER = "keep-alive".freeze
+ USER_AGENT = "Timber Ruby Gem/#{Timber::VERSION}".freeze
- def initialize(application_key = nil)
- @application_key = application_key || Config.application_key
- if @application_key.nil?
- raise ArgumentError.new("A Timber application_key is required")
+ HTTPS = Net::HTTP.new(API_URI.host, API_URI.port).tap do |https|
+ https.use_ssl = true
+ https.read_timeout = 30
+ https.ssl_timeout = 10
+ if https.respond_to?(:keep_alive_timeout=)
+ https.keep_alive_timeout = 60
end
- LogTruck.start!
+ https.open_timeout = 10
end
- def close(*args)
+ DEFAULT_DELIVERY_FREQUENCY = 2.freeze
+
+ # Instantiates a new HTTP log device.
+ #
+ # @param api_key [String] The API key provided to you after you add your application to
+ # [Timber](https://timber.io).
+ # @param [Hash] options the options to create a HTTP log device with.
+ # @option attributes [Symbol] :frequency_seconds (2) How often the client should
+ # attempt to deliver logs to the Timber API. The HTTP client buffers logs between calls.
+ def initialize(api_key, options = {})
+ @api_key = api_key
+ @buffer = []
+ @monitor = Monitor.new
+ @delivery_thread = Thread.new do
+ at_exit { deliver }
+ loop do
+ sleep options[:frequency_seconds] || DEFAULT_DELIVERY_FREQUENCY
+ deliver
+ end
+ end
end
+ def write(msg)
+ @monitor.synchronize {
+ @buffer << msg
+ }
+ end
+
+ def close
+ @delivery_thread.kill
+ end
+
private
- def write_log_line(log_line)
- LogPile.get(application_key).drop(log_line)
+ def deliver
+ body = @buffer.read
+
+ request = Net::HTTP::Post.new(API_URI.request_uri).tap do |req|
+ req['Authorization'] = authorization_payload
+ req['Connection'] = CONNECTION_HEADER
+ req['Content-Type'] = CONTENT_TYPE
+ req['User-Agent'] = USER_AGENT
+ req.body = body
+ end
+
+ HTTPS.request(request).tap do |res|
+ code = res.code.to_i
+ if code < 200 || code >= 300
+ raise DeliveryError.new("Bad response from Timber API - #{res.code}: #{res.body}")
+ end
+ Config.instance.logger.debug("Success! #{code}: #{res.body}")
+ end
+
+ @buffer.clear
+ end
+
+ def authorization_payload
+ @authorization_payload ||= "Basic #{Base64.strict_encode64(@api_key).chomp}"
end
end
end
end
\ No newline at end of file