Ruby
Send logs from Ruby applications to Parseable. Follow the setup steps and practical guidance for using Ruby in your Parseable observability workflow.
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?