Ruby
Send logs from Ruby and Rails apps using net/http or a custom Logger device.
Quick start
No gems required — Ruby's standard net/http handles it:
ruby
require 'net/http'
require 'json'
require 'uri'
LOGFLOW_API_KEY = ENV['LOGFLOW_API_KEY']
LOGFLOW_URI = URI('https://api.getlogflow.com/v1/logs')
def log(level, message, service: 'app', **attributes)
http = Net::HTTP.new(LOGFLOW_URI.host, LOGFLOW_URI.port)
http.use_ssl = true
http.open_timeout = 3
http.read_timeout = 3
request = Net::HTTP::Post.new(LOGFLOW_URI)
request['Authorization'] = "Bearer #{LOGFLOW_API_KEY}"
request['Content-Type'] = 'application/json'
request.body = { level:, message:, service:, attributes: }.to_json
http.request(request)
rescue StandardError
nil # never let logging crash your app
end
log('info', 'Server started', service: 'api', port: 3000)
log('error', 'Payment failed', service: 'payments', user_id: 'u_123')Rails integration
Create a custom Logger device and attach it to Rails.logger:
ruby
# config/initializers/logflow.rb
require 'net/http'
require 'json'
class LogFlowDevice
SEVERITY_MAP = {
'DEBUG' => 'debug', 'INFO' => 'info', 'WARN' => 'warn',
'ERROR' => 'error', 'FATAL' => 'fatal', 'UNKNOWN' => 'info'
}.freeze
def initialize(service: Rails.application.class.module_parent_name.downcase)
@service = service
@uri = URI('https://api.getlogflow.com/v1/logs')
@api_key = ENV['LOGFLOW_API_KEY']
end
def write(message)
# Rails logger format: "S, [timestamp] SEVERITY -- progname: message"
severity = message.match(/^w+,s[.*?]s+(w+)/i)&.captures&.first || 'INFO'
clean_msg = message.gsub(/^.*?-- .*?: /, '').strip
Thread.new do
send_log(SEVERITY_MAP[severity] || 'info', clean_msg)
end
end
def close; end
private
def send_log(level, message)
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = true
http.open_timeout = 3
req = Net::HTTP::Post.new(@uri)
req['Authorization'] = "Bearer #{@api_key}"
req['Content-Type'] = 'application/json'
req.body = { level:, message:, service: @service }.to_json
http.request(req)
rescue StandardError
nil
end
end
# Attach to Rails.logger
Rails.logger = Logger.new(LogFlowDevice.new(service: 'rails-api'))
Rails.logger.level = Rails.env.production? ? Logger::INFO : Logger::DEBUG💡
The
Thread.new wrapper makes logging non-blocking. Rails request handlers return immediately even under slow network conditions.Batch sending with Faraday
For high-throughput apps, buffer logs and flush in a background thread:
ruby
require 'net/http'
require 'json'
class LogFlowBatcher
def initialize(service:, flush_interval: 2)
@service = service
@uri = URI('https://api.getlogflow.com/v1/logs/batch')
@api_key = ENV['LOGFLOW_API_KEY']
@buffer = []
@mutex = Mutex.new
start_flush_thread(flush_interval)
end
def log(level, message, **attributes)
@mutex.synchronize do
@buffer << { level:, message:, service: @service, attributes: }
end
end
private
def start_flush_thread(interval)
Thread.new do
loop do
sleep interval
flush
end
end
end
def flush
batch = @mutex.synchronize { @buffer.tap { @buffer = [] } }
return if batch.empty?
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(@uri)
req['Authorization'] = "Bearer #{@api_key}"
req['Content-Type'] = 'application/json'
req.body = { logs: batch }.to_json
http.request(req)
rescue StandardError
nil
end
end
# Usage
$logger = LogFlowBatcher.new(service: 'api')
$logger.log('info', 'Request received', path: '/api/orders', duration_ms: 42)
$logger.log('error', 'Stripe timeout', attempt: 2)