Ruby
Send logs from Ruby applications to Parseable
Send logs from Ruby applications to Parseable using HTTP or logging libraries.
Overview
Integrate Ruby with Parseable to:
- Application Logs - Send structured logs from Ruby apps
- Rails Integration - Works with Ruby on Rails
- Multiple Frameworks - Sinatra, Hanami, and more
- Structured Logging - JSON-formatted log entries
Prerequisites
- Ruby 2.7+
- Parseable instance accessible
- HTTP client gem (net/http, faraday, or httparty)
Basic HTTP Integration
Using Net::HTTP
require 'net/http'
require 'json'
require 'uri'
class ParseableLogger
def initialize(url:, dataset:, username:, password:)
@uri = URI.parse("#{url}/api/v1/ingest")
@dataset = dataset
@auth = Base64.strict_encode64("#{username}:#{password}")
end
def log(level:, message:, **metadata)
entry = {
timestamp: Time.now.utc.iso8601(3),
level: level.to_s,
message: message,
**metadata
}
send_log([entry])
end
def info(message, **metadata)
log(level: :info, message: message, **metadata)
end
def error(message, **metadata)
log(level: :error, message: message, **metadata)
end
def warn(message, **metadata)
log(level: :warn, message: message, **metadata)
end
private
def send_log(entries)
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = @uri.scheme == 'https'
request = Net::HTTP::Post.new(@uri.path)
request['Content-Type'] = 'application/json'
request['Authorization'] = "Basic #{@auth}"
request['X-P-Stream'] = @dataset
request.body = entries.to_json
response = http.request(request)
raise "Failed to send log: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
end
end
# Usage
logger = ParseableLogger.new(
url: 'http://parseable:8000',
dataset: 'ruby-app',
username: 'admin',
password: 'admin'
)
logger.info('Application started', service: 'my-app', version: '1.0.0')
logger.error('Database connection failed', error: 'Connection refused')Using Faraday
require 'faraday'
require 'json'
class ParseableLogger
def initialize(url:, dataset:, username:, password:)
@dataset = dataset
@conn = Faraday.new(url: url) do |f|
f.request :json
f.request :authorization, :basic, username, password
f.adapter Faraday.default_adapter
end
end
def log(level:, message:, **metadata)
entry = {
timestamp: Time.now.utc.iso8601(3),
level: level.to_s,
message: message,
**metadata
}
@conn.post('/api/v1/ingest') do |req|
req.headers['X-P-Stream'] = @dataset
req.body = [entry].to_json
end
end
endRails Integration
Custom Logger
Create lib/parseable_logger.rb:
require 'net/http'
require 'json'
class ParseableLogger < Logger
def initialize(url:, dataset:, username:, password:)
super(nil)
@uri = URI.parse("#{url}/api/v1/ingest")
@dataset = dataset
@auth = Base64.strict_encode64("#{username}:#{password}")
@buffer = []
@mutex = Mutex.new
@batch_size = 100
@flush_interval = 5
start_flush_thread
end
def add(severity, message = nil, progname = nil)
message = yield if block_given?
entry = {
timestamp: Time.now.utc.iso8601(3),
level: severity_name(severity),
message: message.to_s,
progname: progname
}
@mutex.synchronize do
@buffer << entry
flush_buffer if @buffer.size >= @batch_size
end
end
private
def severity_name(severity)
%w[DEBUG INFO WARN ERROR FATAL UNKNOWN][severity] || 'UNKNOWN'
end
def start_flush_thread
Thread.new do
loop do
sleep @flush_interval
@mutex.synchronize { flush_buffer }
end
end
end
def flush_buffer
return if @buffer.empty?
entries = @buffer.dup
@buffer.clear
Thread.new { send_logs(entries) }
end
def send_logs(entries)
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = @uri.scheme == 'https'
request = Net::HTTP::Post.new(@uri.path)
request['Content-Type'] = 'application/json'
request['Authorization'] = "Basic #{@auth}"
request['X-P-Stream'] = @dataset
request.body = entries.to_json
http.request(request)
rescue => e
STDERR.puts "Failed to send logs to Parseable: #{e.message}"
end
endConfigure in Rails
In config/environments/production.rb:
config.logger = ParseableLogger.new(
url: ENV['PARSEABLE_URL'],
dataset: 'rails-app',
username: ENV['PARSEABLE_USERNAME'],
password: ENV['PARSEABLE_PASSWORD']
)Semantic Logger Integration
Use Semantic Logger for structured logging:
# Gemfile
gem 'semantic_logger'
# config/initializers/semantic_logger.rb
require 'semantic_logger'
class ParseableAppender < SemanticLogger::Subscriber
def initialize(url:, dataset:, username:, password:)
super()
@uri = URI.parse("#{url}/api/v1/ingest")
@dataset = dataset
@auth = Base64.strict_encode64("#{username}:#{password}")
end
def log(log)
entry = {
timestamp: log.time.utc.iso8601(3),
level: log.level.to_s,
message: log.message,
name: log.name,
duration: log.duration,
payload: log.payload,
exception: log.exception&.message,
backtrace: log.exception&.backtrace&.first(10)
}.compact
send_log([entry])
end
private
def send_log(entries)
# Same as above
end
end
SemanticLogger.add_appender(appender: ParseableAppender.new(
url: ENV['PARSEABLE_URL'],
dataset: 'rails-app',
username: ENV['PARSEABLE_USERNAME'],
password: ENV['PARSEABLE_PASSWORD']
))Best Practices
- Use Batching - Buffer logs and send in batches
- Async Sending - Don't block application threads
- Handle Failures - Implement retry logic
- Add Context - Include request ID, user ID
- Use Structured Logs - Send JSON-formatted entries
Troubleshooting
Connection Errors
- Verify Parseable URL is accessible
- Check SSL certificate if using HTTPS
- Verify credentials
Missing Logs
- Check buffer is being flushed
- Verify dataset name is correct
- Check for exceptions in send thread
Next Steps
- Configure alerts for error patterns
- Create dashboards for Ruby metrics
- Explore OpenTelemetry for tracing
Was this page helpful?