class Sqreen::Session
Constants
- MAX_DELAY
- MUTEX
- RETRY_CONNECT_SECONDS
- RETRY_FOREVER
- RETRY_MANY
- RETRY_REQUEST_SECONDS
Attributes
request_compression[RW]
Public Class Methods
new(server_url, cert_store, token, app_name = nil, proxy_url = nil)
click to toggle source
# File lib/sqreen/session.rb, line 53 def initialize(server_url, cert_store, token, app_name = nil, proxy_url = nil) @token = token @app_name = app_name @session_id = nil @server_url = server_url @request_compression = false @connected = nil @con = nil uri = parse_uri(server_url) use_ssl = (uri.scheme == 'https') proxy_params = [] if proxy_url proxy_uri = parse_uri(proxy_url) proxy_params = [proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password] end @req_nb = 0 @http = Net::HTTP.new(uri.host, uri.port, *proxy_params) @http.use_ssl = use_ssl @http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY'] # for testing @http.cert_store = cert_store if use_ssl self.use_signals = false end
Public Instance Methods
compress(data)
click to toggle source
# File lib/sqreen/session.rb, line 228 def compress(data) return data unless request_compression out = StringIO.new w = Zlib::GzipWriter.new(out) w.write(data) w.close out.string end
connect()
click to toggle source
# File lib/sqreen/session.rb, line 112 def connect return if connected? Sqreen.log.warn "connection to #{@server_url}..." @session_id = nil @conn_retry = 0 begin @con = @http.start rescue StandardError => e Sqreen.log.debug { "Caught exception during request: #{e.inspect}" } Sqreen.log.debug { e.backtrace } Sqreen.log.debug { "Cannot connect, retry in #{RETRY_CONNECT_SECONDS} seconds" } sleep RETRY_CONNECT_SECONDS @conn_retry += 1 retry else Sqreen.log.warn 'connection success.' end end
connected?()
click to toggle source
# File lib/sqreen/session.rb, line 104 def connected? @con && @con.started? end
disconnect()
click to toggle source
# File lib/sqreen/session.rb, line 108 def disconnect @http.finish if connected? end
do_http_request(method, path, data, headers = {}, max_retry = 2)
click to toggle source
# File lib/sqreen/session.rb, line 167 def do_http_request(method, path, data, headers = {}, max_retry = 2) now = Time.now.utc headers['X-Session-Key'] = @session_id if @session_id headers['X-Sqreen-Time'] = now.to_f.to_s headers['User-Agent'] = "sqreen-ruby/#{Sqreen::VERSION}" headers['X-Sqreen-Beta'] = format('pid=%d;tid=%s;nb=%d;t=%f', Process.pid, thread_id, @req_nb, Time.now.utc.to_f) headers['Content-Type'] = 'application/json' headers['Accept'] = 'application/json' if request_compression && !method.casecmp(:GET).zero? headers['Content-Encoding'] = 'gzip' end @req_nb += 1 path = prefix_path(path) payload = {} resiliently(RETRY_REQUEST_SECONDS, max_retry) do Sqreen.log.debug { format('%s %s %s %s (%s)', method, path, JSON.dump(data), headers.inspect, @token) } res = nil MUTEX.synchronize do res = case method.upcase when :GET @con.get(path, headers) when :POST json_data = nil unless data.nil? serialized = Serializer.serialize(data) json_data = compress(SafeJSON.dump(serialized)) end @con.post(path, json_data, headers) else Sqreen.log.debug { format('unknown method %s', method) } raise Sqreen::NotImplementedYet end end if res && res.code == '401' raise Sqreen::Unauthorized, 'HTTP 401: shall relogin' end if res && res.body if res['Content-Type'] && res['Content-Type'].start_with?('application/json') payload = JSON.parse(res.body) unless payload['status'] Sqreen.log.debug { format('Cannot %s %s. Parsed response body was: %s', method, path, payload.inspect) } end else Sqreen.log.debug { "Unexpected response Content-Type: #{res['Content-Type']}" } Sqreen.log.debug { "Unexpected response body: #{res.body.inspect}" } end else Sqreen.log.debug { 'warning: empty return value' } end Sqreen.log.debug { format('%s %s (DONE: %s in %f ms)', method, path, res && res.code, (Time.now.utc - now) * 1000) } end payload end
get(path, headers = {}, max_retry = 2)
click to toggle source
# File lib/sqreen/session.rb, line 135 def get(path, headers = {}, max_retry = 2) do_http_request(:GET, path, nil, headers, max_retry) end
get_actionspack()
click to toggle source
# File lib/sqreen/session.rb, line 291 def get_actionspack get('actionspack', {}, RETRY_MANY) end
heartbeat(cmd_res = {}, metrics = [])
click to toggle source
# File lib/sqreen/session.rb, line 265 def heartbeat(cmd_res = {}, metrics = []) payload = {} unless metrics.nil? || metrics.empty? # never reached with signals payload['metrics'] = metrics.map do |m| Sqreen::Legacy::EventToHash.convert_agg_metric(m) end end payload['command_results'] = cmd_res unless cmd_res.nil? || cmd_res.empty? post('app-beat', payload.empty? ? nil : payload, {}, RETRY_MANY) end
login(framework)
click to toggle source
# File lib/sqreen/session.rb, line 237 def login(framework) headers = prelogin_auth_headers(framework) Sqreen.log.warn "Using app name: #{headers['x-app-name']}" res = post('app-login', RuntimeInfos.all(framework), headers, RETRY_FOREVER) if !res || !res['status'] public_error = format('Cannot login. Token may be invalid: %s', @token) Sqreen.log.error public_error raise(Sqreen::TokenInvalidException, format('invalid response: %s', res.inspect)) end Sqreen.log.info 'Login success.' @session_id = res['session_id'] Kit::Configuration.session_key = @session_id Kit.reset Sqreen.log.debug { "received session_id #{@session_id}" } Sqreen.logged_in = true res end
logout(retrying = true)
click to toggle source
Perform agent logout @param retrying [Boolean] whether to try again on error
# File lib/sqreen/session.rb, line 316 def logout(retrying = true) # Do not try to connect if we are not connected unless connected? Sqreen.log.debug('Not connected: not trying to logout') return end # Perform not very resilient logout not to slow down client app shutdown get('app-logout', {}, retrying ? 2 : 1) Sqreen.logged_in = false disconnect end
parse_uri(uri)
click to toggle source
# File lib/sqreen/session.rb, line 91 def parse_uri(uri) # This regexp is the Ruby constant URI::PATTERN::HOSTNAME augmented # with the _ character that is frequent in Docker linked containers. re = '(?:(?:[a-zA-Z\\d](?:[-_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.)*(?:[a-zA-Z](?:[-_a-zA-Z\\d]*[a-zA-Z\\d])?)\\.?' parser = URI::Parser.new :HOSTNAME => re parser.parse(uri) end
post(path, data, headers = {}, max_retry = 2)
click to toggle source
# File lib/sqreen/session.rb, line 131 def post(path, data, headers = {}, max_retry = 2) do_http_request(:POST, path, data, headers, max_retry) end
post_agent_message(framework, agent_message)
click to toggle source
# File lib/sqreen/session.rb, line 309 def post_agent_message(framework, agent_message) headers = prelogin_auth_headers(framework) post('app_agent_message', agent_message.to_h, headers, 0) end
post_attack(attack)
click to toggle source
XXX never called
# File lib/sqreen/session.rb, line 283 def post_attack(attack) @evt_sub_strategy.post_attack(attack) end
post_batch(events)
click to toggle source
# File lib/sqreen/session.rb, line 305 def post_batch(events) @evt_sub_strategy.post_batch(events) end
post_bundle(bundle_sig, dependencies)
click to toggle source
# File lib/sqreen/session.rb, line 287 def post_bundle(bundle_sig, dependencies) post('bundle', { 'bundle_signature' => bundle_sig, 'dependencies' => dependencies }, {}, RETRY_MANY) end
post_metrics(metrics)
click to toggle source
# File lib/sqreen/session.rb, line 278 def post_metrics(metrics) @evt_sub_strategy.post_metrics(metrics) end
post_request_record(request_record)
click to toggle source
# File lib/sqreen/session.rb, line 295 def post_request_record(request_record) @evt_sub_strategy.post_request_record(request_record) end
post_sqreen_exception(exception)
click to toggle source
prefix_path(path)
click to toggle source
# File lib/sqreen/session.rb, line 99 def prefix_path(path) return '/sqreen/v1/' + path if path == 'app-login' || path == 'app-beat' @@path_prefix + path end
resiliently(retry_request_seconds, max_retry, current_retry = 0) { || ... }
click to toggle source
# File lib/sqreen/session.rb, line 139 def resiliently(retry_request_seconds, max_retry, current_retry = 0) connect unless connected? return yield rescue => e Sqreen.log.debug { "Caught exception during request: #{e.inspect}" } Sqreen.log.debug { e.backtrace } current_retry += 1 raise e if max_retry != RETRY_FOREVER && current_retry >= max_retry || e.is_a?(Sqreen::NotImplementedYet) || e.is_a?(Sqreen::Unauthorized) sleep_delay = [MAX_DELAY, retry_request_seconds * current_retry].min Sqreen.log.debug { format("Sleeping %ds before retry #{current_retry}/#{max_retry}", sleep_delay) } sleep(sleep_delay) retry end
rules()
click to toggle source
# File lib/sqreen/session.rb, line 261 def rules get('rulespack', {}, RETRY_MANY) end
thread_id()
click to toggle source
# File lib/sqreen/session.rb, line 157 def thread_id th = Thread.current return '' unless th re = th.to_s.scan(/:(0x.*)>/) return '' unless re && !re.empty? res = re[0] return '' unless res && !res.empty? res[0] end
use_signals=(do_use)
click to toggle source
# File lib/sqreen/session.rb, line 80 def use_signals=(do_use) return if do_use == @use_signals @use_signals = do_use if do_use @evt_sub_strategy = Sqreen::Signals::SignalsSubmissionStrategy.new else @evt_sub_strategy = Sqreen::Legacy::OldEventSubmissionStrategy.new(method(:post)) end end
Private Instance Methods
prelogin_auth_headers(framework)
click to toggle source
# File lib/sqreen/session.rb, line 330 def prelogin_auth_headers(framework) { 'x-api-key' => @token, 'x-app-name' => @app_name || framework.application_name, }.reject { |_k, v| v == nil } end