Issue tracking in production via Gitlab Ruby API

It’s so easy for you to track production issues/exceptions with Gitlab. It has super sexy issue board and Issue management UI along with RESTful API. Thankfully we need not write REST API, however Ruby API is sufficient. There is an awesome Ruby Gem written by `@NARKOZ` (https://github.com/NARKOZ/gitlab).

Configuration example:

gem 'gitlab'
# in config/initializers/gitlab_config.rb
Gitlab.configure do |config|
  config.endpoint       = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
  config.private_token  = 'qEsq1pt6HJPaNciie3MG'       # user's private token or OAuth2 access token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
  # Optional
  # config.user_agent   = 'Custom User Agent'          # user agent, default: 'Gitlab Ruby Gem [version]'
  # config.sudo         = 'user'                       # username for sudo mode, default: nil
end

You can find API for issues here

Example Library I wrote

This should handler the rest. Make sure you include this module in ApplicationController

# in controller/concerns/exception_handler.rb
module ExceptionHandler
  extend ActiveSupport::Concern
  class InvalidRequest < StandardError;  end

  included do
    unless Rails.application.config.consider_all_requests_local
      rescue_from InvalidRequest,
                  NoMethodError,
                  ActiveRecord::RecordInvalid,
                  NameError,
                  ArgumentError, with: :handle_unauthorized_requests

    end
  end

  private
  def handle_unauthorized_requests(error)
    create_issue_in_gitlab(error)
    render 'errors/unauthorized', status: 400, layout: 'static', locals: {error: error}
  end

  def create_issue_in_gitlab(error)
    title = "#{error.class} : #{error.message}"

    description = "## Details\n"
    description << "**DateTime**: #{DateTime.now}  \n"
    description << "**TimeZone**: #{Time.zone}  \n"
    description << "**Environment**: #{Rails.env}  \n"
    description << "**UserID**: #{current_user && current_user.id}  \n"
    description << "**Requested From**: #{request.ip}  \n"
    description << "**Request Referrer URL**: #{request.referrer}  \n"
    description << "**Requested URL**: #{request.url}  \n"

    description << "## Request\n"
    description << "```ruby\n"
    description << "parameters: #{request.filtered_parameters}\n"
    description << "```\n"

    description << "## Session Dump\n"
    description << "```ruby\n"
    description << "#{session_dump}\n"
    description << "```\n"

    description << "## Backtrace\n"
    description << "```ruby\n"
    description << "#{error.backtrace[0..25].join("\n")}\n"
    description << "```\n"

    # TODO Move this task to ActiveJob
    # project_id is integer you get from gitlab for your project
    #  I figured out using
    #    > Gitlab.projects  # in rails console after configuring the gem
    #    this gives array of projects, you will get ID for project
    Gitlab.create_issue(ENV['gitlab_issifix_project_id'], title,
                        {description: description, labels: 'System Generated, Bug, Production'})
  end

  def session_dump
    keys = ['_csrf_token', 'session_id', 'warden.user.user.key', 'warden.user.user.session']
    keys.map { |key| "#{key}: #{session[key]}" }.join("\n")
  end
end

 

Then you should be seeing issues created in your project.

Screenshot of an example Issue

Screenshot from 2016-09-04 22:44:56

Advertisements

Ruby On Rails : Exception Handling Best practices

There are various ways to rescue from exceptions raised in Rails App.

The most basic is

begin
.........
rescue NameOfException => exc
   logger.error("Message for the log file #{exc.message}")
   flash[:notice] = "Store error message"
   redirect_to(:action => 'index')
end

Or you can render a static HTML file namely public/401.html or public/400.html.erb
Continue reading

Ruby : Not throwing exception even when divided by Zero : Only when operands are floating points

# Throws an Exception when both operands are integers
# However, if operand are floating point numbers then that is not the case
begin
 puts 'Enter the Number'
 quotient = gets.to_i
 puts 'enter the divider'
 divider = gets.to_i
 result = quotient/divider
 puts "The result is #{result}"
rescue ZeroDivisionError
 puts 'Cannot divide by zero'
 retry
end
# Output
Enter the Number
12
enter the divider
0
Cannot divide by zero
# Whole process within begin block retried
Enter the Number
# However
begin
 puts 'Enter the Number'
 quotient = gets.to_f
 puts 'enter the divider'
 divider = gets.to_f
 result = quotient/divider
 puts "The result is #{result}"
rescue ZeroDivisionError
 puts 'Cannot divide by zero'
 retry
end
# Output
Enter the Number
12
enter the divider
0
The result is Infinity

12.12/0.0
=> Infinity

# However
12/0
ZeroDivisionError: divided by 0

Exception handling in Rails

The execution and the exception always go together. If you are opening a file which does not exist then if you did not handle this situation properly then your program is considered to be of bad quality.

The program stops if an exception occurs. So exceptions are used to handle various type of errors which may occur during a program execution and take appropriate action instead of halting program completely.

Exception handling in Ruby on Rails is similar to exception handling in Ruby. Which means, we enclose the code that could raise an exception in a begin/end block and use rescue clauses to tell Ruby the types of exceptions we want to handle