app/server.rb in sqlui-0.1.51 vs app/server.rb in sqlui-0.1.52

- old
+ new

@@ -2,12 +2,15 @@ require 'base64' require 'csv' require 'erb' require 'json' +require 'prometheus/middleware/collector' +require 'prometheus/middleware/exporter' require 'sinatra/base' require 'uri' +require 'webrick' require_relative 'database_metadata' require_relative 'mysql_types' require_relative 'sql_parser' require_relative 'sqlui' @@ -16,10 +19,33 @@ def self.logger @logger ||= WEBrick::Log.new end def self.init_and_run(config, resources_dir) + logger.info("Airbrake enabled: #{config.airbrake[:server]&.[](:enabled) || false}") + if config.airbrake[:server]&.[](:enabled) + require 'airbrake' + require 'airbrake/rack' + + Airbrake.configure do |c| + c.app_version = File.read('.version').strip + c.environment = config.environment + c.logger.level = Logger::DEBUG if config.environment != :production? + config.airbrake[:server].each do |key, value| + c.send("#{key}=".to_sym, value) unless key == :enabled + end + end + Airbrake.add_filter(Airbrake::Rack::RequestBodyFilter.new) + Airbrake.add_filter(Airbrake::Rack::HttpParamsFilter.new) + Airbrake.add_filter(Airbrake::Rack::HttpHeadersFilter.new) + use Airbrake::Rack::Middleware + end + + use Rack::Deflater + use Prometheus::Middleware::Collector + use Prometheus::Middleware::Exporter + Mysql2::Client.default_query_options[:as] = :array Mysql2::Client.default_query_options[:cast_booleans] = true Mysql2::Client.default_query_options[:database_timezone] = :utc Mysql2::Client.default_query_options[:cache_rows] = false @@ -51,21 +77,17 @@ get "#{database.url_path}/?" do redirect "#{database.url_path}/query", 301 end get "#{database.url_path}/sqlui.css" do - @css ||= File.read(File.join(resources_dir, 'sqlui.css')) - status 200 headers 'Content-Type' => 'text/css; charset=utf-8' - body @css + send_file File.join(resources_dir, 'sqlui.css') end get "#{database.url_path}/sqlui.js" do - @js ||= File.read(File.join(resources_dir, 'sqlui.js')) - status 200 headers 'Content-Type' => 'text/javascript; charset=utf-8' - body @js + send_file File.join(resources_dir, 'sqlui.js') end post "#{database.url_path}/metadata" do metadata = database.with_client do |client| { @@ -97,11 +119,13 @@ headers 'Content-Type' => 'application/json; charset=utf-8' body metadata.to_json end post "#{database.url_path}/query" do - params.merge!(JSON.parse(request.body.read, symbolize_names: true)) + data = request.body.read + request.body.rewind # since Airbrake will read the body on error + params.merge!(JSON.parse(data, symbolize_names: true)) break client_error('missing sql') unless params[:sql] variables = params[:variables] || {} sql = find_selected_query(params[:sql], params[:selection]) @@ -109,33 +133,46 @@ headers 'Content-Type' => 'application/json; charset=utf-8' database.with_client do |client| query_result = execute_query(client, variables, sql) stream do |out| - json = <<~RES.chomp - { - "columns": #{query_result.fields.to_json}, - "column_types": #{MysqlTypes.map_to_google_charts_types(query_result.field_types).to_json}, - "total_rows": #{query_result.size.to_json}, - "selection": #{params[:selection].to_json}, - "query": #{params[:sql].to_json}, - "rows": [ - RES - out << json - bytes = json.bytesize - query_result.each_with_index do |row, i| - json = "#{i.zero? ? '' : ','}\n #{row.to_json}" - bytes += json.bytesize - break if i == Sqlui::MAX_ROWS || bytes > Sqlui::MAX_BYTES - + if query_result + json = <<~RES.chomp + { + "columns": #{query_result.fields.to_json}, + "column_types": #{MysqlTypes.map_to_google_charts_types(query_result.field_types).to_json}, + "total_rows": #{query_result.size.to_json}, + "selection": #{params[:selection].to_json}, + "query": #{params[:sql].to_json}, + "rows": [ + RES out << json - end - out << <<~RES + bytes = json.bytesize + query_result.each_with_index do |row, i| + json = "#{i.zero? ? '' : ','}\n #{row.to_json}" + bytes += json.bytesize + break if i == Sqlui::MAX_ROWS || bytes > Sqlui::MAX_BYTES - ] - } - RES + out << json + end + out << <<~RES + + ] + } + RES + else + out << <<~RES + { + "columns": [], + "column_types": [], + "total_rows": 0, + "selection": #{params[:selection].to_json}, + "query": #{params[:sql].to_json}, + "rows": [] + } + RES + end end end end get "#{database.url_path}/download_csv" do @@ -159,13 +196,17 @@ end end end get(%r{#{Regexp.escape(database.url_path)}/(query|graph|structure|saved)}) do - @html ||= File.read(File.join(resources_dir, 'sqlui.html')) status 200 - headers 'Content-Type' => 'text/html; charset=utf-8' - body @html + client_config = config.airbrake[:client] || {} + erb :sqlui, locals: { + environment: config.environment.to_s, + airbrake_enabled: client_config[:enabled] || false, + airbrake_project_id: client_config[:project_id] || '', + airbrake_project_key: client_config[:project_key] || '' + } end end error 400..510 do exception = env['sinatra.error']