SolidLog

All-in-one log aggregation gem for Rails applications. Includes core models, database adapters, and Mission Control-style web interface.

Overview

solid_log is the main gem that provides everything you need:

  • Core functionality (from solid_log-core - auto-required):
    • Database models and adapters (SQLite, PostgreSQL, MySQL)
    • Parser for structured JSON logs
    • Background jobs (ParseJob, RetentionJob, etc.)
    • DirectLogger for high-performance logging
  • Mission Control-style UI: Browse, filter, and search logs
  • Dual-mode support:
    • Direct DB: Fast access when UI and service share database
    • HTTP API: Remote access when service runs separately
  • Overridable authentication: Easy integration with your auth system
  • Real-time updates: Live tail support (WebSocket or polling)
  • Full-text search: Powered by database-native FTS
  • Request/job correlation: Timeline views for related logs

Installation

gem 'solid_log'

# Also install database adapter if using direct_db mode
gem 'sqlite3', '>= 2.1'   # or pg, or mysql2

Configuration

Create config/initializers/solid_log_ui.rb:

Direct DB Mode (Default)

SolidLog::UI.configure do |config|
  config.mode = :direct_db
  config.authentication_method = :custom  # Override BaseController
  config.stream_view_style = :compact
  config.per_page = 100
end

HTTP API Mode

SolidLog::UI.configure do |config|
  config.mode = :http_api
  config.service_url = ENV['SOLIDLOG_SERVICE_URL']
  config.service_token = ENV['SOLIDLOG_SERVICE_TOKEN']
  config.authentication_method = :custom
end

Mount in Routes

# config/routes.rb
Rails.application.routes.draw do
  mount SolidLog::UI::Engine => "/admin/logs"
end

Access at: http://yourapp.com/admin/logs

Authentication

The BaseController is designed to be easily overridden in your host application.

Create config/initializers/solid_log_ui_auth.rb:

# Use your existing authentication system
SolidLog::UI::BaseController.class_eval do
  before_action :require_admin

  private

  def require_admin
    redirect_to root_path unless current_user&.admin?
  end

  # Override current_user to use your app's authentication
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end
end

Option 2: HTTP Basic Auth

# config/initializers/solid_log_ui.rb
SolidLog::UI.configure do |config|
  config.authentication_method = :basic
end

# Store credentials in Rails credentials
# rails credentials:edit
solidlog:
  username: admin
  password: secret_password

Or override the auth method:

SolidLog::UI::BaseController.class_eval do
  protected

  def authenticate_with_basic_auth(username, password)
    username == ENV['ADMIN_USER'] && password == ENV['ADMIN_PASSWORD']
  end
end

Option 3: Devise Integration

SolidLog::UI::BaseController.class_eval do
  before_action :authenticate_admin_user!

  private

  def authenticate_admin_user!
    authenticate_user!
    redirect_to root_path unless current_user.admin?
  end

  # Devise provides current_user automatically
end

Option 4: Custom Middleware

SolidLog::UI::BaseController.class_eval do
  before_action :check_api_key

  private

  def check_api_key
    api_key = request.headers['X-Admin-API-Key']
    head :unauthorized unless api_key == ENV['ADMIN_API_KEY']
  end
end

Option 5: IP Whitelist

SolidLog::UI::BaseController.class_eval do
  before_action :check_ip_whitelist

  private

  def check_ip_whitelist
    allowed_ips = ENV['ALLOWED_IPS'].to_s.split(',')
    unless allowed_ips.include?(request.remote_ip)
      render plain: "Access denied", status: :forbidden
    end
  end
end

Deployment Modes

Mode 1: Direct DB (Fast, Same Host)

Use when: UI and service run on same host with shared database

# config/initializers/solid_log_ui.rb
SolidLog::UI.configure do |config|
  config.mode = :direct_db
end

# config/database.yml
production:
  primary:
    adapter: sqlite3
    database: storage/production.sqlite3
  log:
    adapter: sqlite3
    database: storage/production_log.sqlite3  # Shared with service
    migrations_paths: db/log_migrate

Benefits:

  • ✅ Fastest (direct database queries)
  • ✅ No HTTP overhead
  • ✅ Works with shared volume in Kamal

Mode 2: HTTP API (Flexible, Remote)

Use when: Service runs separately from main app

# config/initializers/solid_log_ui.rb
SolidLog::UI.configure do |config|
  config.mode = :http_api
  config.service_url = 'http://solidlog-service:3001'
  config.service_token = ENV['SOLIDLOG_TOKEN']
end

Benefits:

  • ✅ Service can run independently
  • ✅ UI can be in separate app/server
  • ✅ Works across network boundaries

Features

Streams View

  • Filter by level, app, env, controller, action, path, method, status
  • Full-text search
  • Compact or expanded view modes
  • Live tail (auto-refresh)

Entry Details

  • Full log entry with all fields
  • JSON-formatted extra fields
  • Copy to clipboard
  • Related entries (request/job correlation)

Timelines

  • Request timeline: All logs for a request_id
  • Job timeline: All logs for a job_id
  • Duration visualization
  • Level distribution

Dashboard

  • Recent error rate
  • Ingestion metrics
  • Parse backlog status
  • Database size
  • Health indicators

Helper Methods

Available in all UI views:

<% if current_user %>
  Welcome, <%= current_user.email %>
<% end %>

<%= level_badge(entry.level) %>
<%= duration_badge(entry.duration) %>
<%= status_code_badge(entry.status_code) %>

Customizing Views

Override views by creating matching files in your app:

app/views/solid_log/ui/

Customizing Styles

Add custom CSS in your application:

/* app/assets/stylesheets/solid_log_custom.css */
.solid-log-stream-entry {
  border-left: 4px solid #your-brand-color;
}

Then import in your application.css:

@import "solid_log_custom";

Development

cd solid_log
bundle install

License

The gem is available as open source under the terms of the MIT License.