Class: Rack::Objectspace

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/objectspace.rb,
lib/rack/objectspace/version.rb

Constant Summary collapse

KEY_SEPARATOR =
'-'.freeze
VERSION =
"0.1.0"

Instance Method Summary collapse

Constructor Details

#initialize(app, store:, async: true, object_space: ObjectSpace) ⇒ Objectspace

Returns a new instance of Objectspace.



9
10
11
12
13
14
15
# File 'lib/rack/objectspace.rb', line 9

def initialize(app, store:, async: true, object_space: ObjectSpace)
  @app = app
  @store = store
  @async = async
  @object_space = object_space
  @object_space.trace_object_allocations_start
end

Instance Method Details

#call(env) ⇒ Object



17
18
19
20
21
22
23
24
# File 'lib/rack/objectspace.rb', line 17

def call(env)
  result = @app.call(env)

  dumper = Thread.new { dump_allocations(env) }
  dumper.join unless @async

  result
end

#dump_allocations(env) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rack/objectspace.rb', line 26

def dump_allocations(env)
  read, write = IO.pipe

  if pid = fork
    # parent
    read.close
    GC.start
    @object_space.dump_all(output: write)
    write.close
    Process.wait(pid) unless @async
  else
    # child
    write.close
    parse_dump(input: read, key: request_id(request: env, pid: Process.ppid))
    read.close
  end
end

#parse_dump(input:, key:, run: ->(id, obj) { store_object(id, obj) }) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/rack/objectspace.rb', line 44

def parse_dump(input:, key:, run: ->(id, obj) { store_object(id, obj) })
  parser = Yajl::Parser.new
  parser.on_parse_complete = lambda do |obj|
    run.call(key, obj)
  end
  parser.parse(input)
end

#request_id(request:, pid:, time: Time) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/rack/objectspace.rb', line 61

def request_id(request:, pid:, time: Time)
  timestamp = time.now.to_i
  request_path = request['PATH_INFO'].tr_s(::File::SEPARATOR, '-').sub!(/^-/, '').downcase
  request_method = request['REQUEST_METHOD'].downcase
  random_salt = SecureRandom.hex(4)
  ['rack-objectspace', pid, timestamp, request_path, request_method, random_salt].join(KEY_SEPARATOR)
end

#store_object(request_id, obj) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/rack/objectspace.rb', line 52

def store_object(request_id, obj)
  object_id = obj.delete('address')
  if object_id
    obj.each do |attr, value|
      @store[[request_id, object_id, attr].join(KEY_SEPARATOR)] = value
    end
  end
end