Sentry error tracking for Kemal
Kemal ⚡️
Kemal is sinatra-like, lightning fast, super simple web framework written in Crystal. It's perfect for prototyping or simple backend services.
Setup
Create a demo app:
crystal init app your-kemal-app
cd your-kemal-app
Add raven and kemal under dependencies
key inside shard.yml
:
dependencies:
raven:
github: Sija/raven
kemal:
github: kemalcr/kemal
Next, install newly added dependencies:
shards install
Integration
Add the code below to your main entrypoint, src/your-kemal-app.cr
:
require "raven"
require "raven/integrations/kemal"
# Perform basic raven configuration, none of it is required though
Raven.configure do |config|
# Keep main fiber responsive by sending the events in the background
config.async = true
# Set the environment name using `Kemal.config.env`, which uses `KEMAL_ENV` variable under-the-hood
config.current_environment = Kemal.config.env
end
# Replace the built-in `Kemal::LogHandler` with a
# dedicated `Raven::Kemal::LogHandler`, capturing all
# sent messages and requests as Sentry breadcrumbs
# If you'd like to preserve default logging provided by
# Kemal, pass `Kemal::LogHandler.new` to the constructor
if Kemal.config.logging
Kemal.config.logger = Raven::Kemal::LogHandler.new(Kemal::LogHandler.new)
else
Kemal.config.logger = Raven::Kemal::LogHandler.new
end
# Add raven's exception handler in order to capture
# all unhandled exceptions thrown inside your routes.
# Captured exceptions are re-raised afterwards
Kemal.config.add_handler Raven::Kemal::ExceptionHandler.new
# Register your explosive route
get "/will/:name/blend" do |env|
if env.params.url["name"].downcase == "earth"
# Earth doesn't blend, yet
raise "Cling, Scratch, Boom!"
else
# All the rest will, obviously
"Sure it will!"
end
end
# Run, Kemal, run!
Kemal.run
Showtime
Run this in the terminal (replacing ...
with your actual DSN):
SENTRY_DSN=... crystal run src/your-kemal-app.cr
Now visit:
You should be greeted by Kemal's default (only in development env) exception page:
In the meantime Sentry should be already notified of the event:
Fine-tuning
Raven.configure do |config|
# If your requests are failing because of connection
# timeout error, try setting bigger value
# (defaults to `1.second`).
#
# NOTE: Avoid using bigger values without `#async` option enabled
config.connect_timeout = 3.seconds
# In case of hitting rate limit you might want to try
# lower sample rate threshold, in this case to 75%
config.sample_rate = 0.75
# Remove default processors you don't need
config.processors -= [Raven::Processor::Cookies, Raven::Processor::RequestMethodData]
# Ignore certain exception classes
# `Kemal::Exceptions::RouteNotFound` is added automatically
config.excluded_exceptions << NotImplementedError
# Sanitize additional fields
config.sanitize_fields << /\Aaddress_(.*?)\Z/i
# Setup `#before_send` hook, which allows modifying
# the event before sending, or dropping it entirely
config.before_send do |event, hint|
# Group events by topic based on exception message
if hint.try(&.exception).try(&.message) =~ /database unavailable/i
event.fingerprint << "database-unavailable"
end
# Conditionally skip sending the event
event unless ENV["CI"]? == "1"
end
end
What's in the package?
All the goodies offered by raven shard +:
- Log handler, turning server logs and requests into breadcrumbs
- Exception handler, reporting unhandled exceptions to Sentry
- Integration with kemal-basic-auth shard
- Events enhanced with request metadata, i.e.:
- Status code
- Method
- URL (
scheme
included) - Query string
- Headers
- Cookies
JSON
/FormData
payload