Integrating Telebugs with a Ruby application

Any Ruby application or script can be integrated with Telebugs using the telebugs gem. In this guide, you will learn how to install and configure Telebugs in your Ruby application.

For Ruby on Rails applications, please refer to the Ruby on Rails integration guide.


Installation

Bundler

Add the telebugs gem to your Gemfile:

bundle add telebugs

Manual

Invoke the following command from your terminal:

gem install telebugs

Basic example

This is the minimal example that you can use to test Telebugs for Ruby with your project:

require "telebugs"

Telebugs.configure do |c|
  c.api_key = "YOUR_API_KEY"
end

begin
  1 / 0
rescue ZeroDivisionError => e
  Telebugs.report(e)
end

sleep 2

puts "An error was sent to Telebugs asynchronously.",
  "It will appear in your dashboard shortly.",
  "A notification was also sent to your Telegram chat."

Replace YOUR_API_KEY with your actual API key. You can ask @TelebugsBot for your API key or find it in your project's dashboard.

The example above will raise a ZeroDivisionError and send the error to Telebugs.


Configuration

Telebugs for Ruby can be configured using the Telebugs.configure method. The method takes a block with a single argument, which is the configuration object.

The configuration object can be used to set the API key and other options. Check the list of all the available options below.

Config options

Option Type Description
api_key String Your project's API key
root_directory String Optional. The working directory of your project. Providing this option helps us filter out repetitive data from backtrace frames.
environment String Optional. The environment in which your project is running. This option is used for ignoring errors in certain environments. By default, it is set to an empty string.
ignore_environments Array<String> Optional. A list of environments in which errors should be ignored. By default, it is set to an empty array.
middleware MiddlewareStack Optional. The middleware stack to be used when reporting an error. You can use this option to add custom middleware to the stack.

Example configuration

Telebugs.configure do |c|
  c.api_key = "1:abcdef"
  c.root_directory = "/path/to/your/project"
  c.environment = "production"
  c.ignore_environments = ["development", "test"]
  c.middleware.use MyCustomMiddleware.new
end

Usage

Telebugs for Ruby provides a simple API to report errors asynchronously to Telebugs.

Reporting an error

To report an error, use the Telebugs.report method. The method supports the following keyword arguments:

Name Description
error The error object to report. It can be an instance of any class that inherits from the Ruby's standard Exception class.

Async reporting

Telebugs for Ruby reports errors asynchronously by default. This means that the Telebugs.report method will return immediately without waiting for the error to be sent to Telebugs.

Telebugs.report(error)

Synchronous reporting

If you want to report an error synchronously, you can use the wait method on the promise object returned by the Telebugs.report method:

Telebugs.report(error).wait

Using custom middleware

What is a middleware in Telebugs?

Middleware in Telebugs is a class that processes the error report before it is sent to Telebugs. You can use middleware to filter sensitive information, ignore certain errors, or perform other actions on the error report.

All middlewares are attached to the Telebugs::MiddlewareStack object. The middleware stack is processed in the order in which the middleware objects are added to the stack.

You can control the order of middleware in the stack by defining the weight method in your middleware class. The method should return an integer value that represents the weight of the middleware object.

The "heavier" the middleware object, the later it will be processed in the stack.

Built-in middlewares

Telebugs for Ruby provides the following built-in middlewares:

Middleware Weight Description
Telebugs::Middleware::IgnoreEnvironments -1000 Ignores errors in certain environments.
Telebugs::Middleware::RootDirectoryFilter -999 Filters the root directory information from the backtrace of the error, so that the backtrace is more readable.
Telebugs::Middleware::GemRootFilter -999 Filters out the root path of the gems. It replaces the root path with the gem name and version.

How to use custom middlewares

To add custom middleware, use the Telebugs.configure method with the middleware option.

To use custom middleware, you need to define a class that inherits from Telebugs::BaseMiddleware and implements the call method. The call method is called with the Telebugs::Report object before it is sent to Telebugs.

The following example demonstrates how to add a custom middleware that filters the error message before it is sent to Telebugs:

class MyCustomMiddleware < Telebugs::BaseMiddleware
  def call(report)
    report.data[:errors][0][:message] = "[Filtered]"
  end
end

Telebugs.configure do |c|
  c.middleware.use MyCustomMiddleware.new
end

error = Exception.new("Cannot connect to the Docker daemon")
Telebugs.report(error)

The Telebugs::Report object is passed through each middleware object in the stack.

Changing middleware order

You can change the order of middleware in the stack by defining the weight method in your middleware class. The method should return an integer value that represents the weight of the middleware object.

class MyCustomMiddleware < Telebugs::Middleware
  def call(report)
    report.data[:errors][0][:message] = "[Filtered]"
  end

  def weight
    10
  end
end

Telebugs.configure do |c|
  c.middleware.use MyCustomMiddleware.new
end

error = Exception.new("Cannot connect to the Docker daemon")
Telebugs.report(error)

The default return value of the weight method is 0. Middleware objects with a lower weight value will be processed first.

Ignoring certain errors

You can use custom middleware to ignore certain errors before they are sent to Telebugs. To ignore an error, you can mark the report as ignored in the middleware's call method.

The ignored flag is set to false by default. If the flag is set to true, the error report will not be sent to Telebugs:

class MyCustomMiddleware < Telebugs::Middleware
  def call(report)
    if report.data[:errors][0][:message] == "Cannot connect to the Docker daemon"
      report.ignored = true
    end
  end
end

Telebugs.configure do |c|
  c.middleware.use MyCustomMiddleware.new
end

error = Exception.new("Cannot connect to the Docker daemon")
Telebugs.report(error)

Ignoring all errors in a certain environment

You can use the ignore_environments option to ignore all errors in certain environments. The ignore_environments option is an array of environment names in which errors should be ignored:

Telebugs.configure do |c|
  c.environment = "test"
  c.ignore_environments = ["development", "test"]
end

The ignore_environments option takes precedence over custom middleware. If an error is reported in an ignored environment, it will not be sent to Telebugs.


You must set the environment option to use the ignore_environments option. Otherwise, the ignore_environments option will have no effect.

Handling the return value

Normally, you would want to know if the error report was sent successfully or if there was an issue with the request. Telebugs for Ruby provides a promise object that you can use to track the status of the error report.

The Telebugs.report method returns a promise that will resolve with the error ID once the error is sent to Telebugs. If the error report fails, the promise will be rejected with an error. Usually, this happens when the API key is invalid or the request to the Telebugs API fails due to network issues, etc.

You can use the promise to handle the error ID and perform additional actions once the error is sent to Telebugs.

Asynchronous error reporting and promise support is powered by the concurrent-ruby gem. The promise object returned by the Telebugs.report method is a wrapper around the Concurrent::Promises::Future class.

Using "then" and "rescue"

The then method allows you to define a callback that will be executed once the promise is resolved:

e = Exception.new("Cannot connect to the Docker daemon")
Telebugs.report(e).then do |result|
  puts "Error #{result['id']} was sent to Telebugs asynchronously."
end

The rescue method allows you to define a callback that will be executed once the promise is rejected:

e = StandardError.new("Cannot connect to the Docker daemon")
Telebugs.report(e).rescue do |error|
  puts "You probably forgot to set the API key: #{error.message}"
end

Using "value" and "reason"

The value method allows you to retrieve the value of the promise once it is resolved:

promise = Telebugs.report(error)
puts "The error ID is #{promise.value['id']}"

The reason method allows you to retrieve the reason why the promise was rejected:

promise = Telebugs.report(error)
puts "The error message is: #{promise.reason.message}"

These calls are blocking. They will wait for the promise to be resolved or rejected and return the value.

Using "wait"

The wait method allows you to block the current thread until the promise is resolved or rejected:

promise = Telebugs.report(error)
promise.wait
puts "The error was sent to Telebugs asynchronously."

Using "fulfilled?" and "rejected?"

The fulfilled? and rejected? methods allow you to check the status of the promise:

promise = Telebugs.report(error)
promise.wait
puts "The promise was fulfilled: #{promise.fulfilled?}"
puts "The promise was rejected: #{promise.rejected?}"

Reporting critical errors

Critical errors are unhandled errors that terminate your program. By default, Telebugs for Ruby doesn't report them. However, you can add the following code somewhere in your app:

at_exit do
  if $!
    Telebugs.report($!).wait
  end
end