insight_agent 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gemtest ADDED
File without changes
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2011-02-25
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,23 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/agent.rb
7
+ lib/agent/frame.rb
8
+ lib/agent/frame.rb
9
+ lib/agent/frame_builder.rb
10
+ lib/agent/operation.rb
11
+ lib/agent/trace.rb
12
+ lib/agent/trace_builder.rb
13
+ lib/agent/trace_dispatcher.rb
14
+ lib/agent/trace_queue.rb
15
+ lib/agent/insight_agent.rb
16
+ lib/agent/event_tree.rb
17
+ lib/agent/wrap_method.rb
18
+ lib/agent/method_operation.rb
19
+ script/console
20
+ script/destroy
21
+ script/generate
22
+ test/test_agent.rb
23
+ test/test_helper.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on agent, see http://agent.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,37 @@
1
+ = insight_agent
2
+
3
+ * http://git.springsource.com/insight
4
+
5
+ == DESCRIPTION:
6
+
7
+ Provides preliminary support for rails applications for
8
+ Insight
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * Need to change the module name from Agent to InsightAgent
13
+ * Not all events are captured
14
+ * events which do not have a "closing" event may stick around
15
+ in an eventtree permenantly
16
+ * REST is not the best
17
+
18
+ == SYNOPSIS:
19
+
20
+ Modify guestbook.demo/Gemfile add the line:
21
+ gem 'insight_agent'
22
+
23
+ Add the agent/integration_test/rails_init.rb to
24
+ the guestbook.demo/config/initializers directory
25
+ and customize
26
+
27
+ == REQUIREMENTS:
28
+
29
+ * Rails 3.0
30
+
31
+ == INSTALL:
32
+
33
+ * sudo gem install insight_agent
34
+
35
+ == LICENSE:
36
+
37
+ Copyright VMware 2011
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+
3
+ gem 'hoe', '>= 2.1.0'
4
+ require 'hoe'
5
+ require 'fileutils'
6
+ require './lib/agent'
7
+
8
+ Hoe.plugin :newgem
9
+ # Hoe.plugin :website
10
+ # Hoe.plugin :cucumberfeatures
11
+
12
+ # Generate all the Rake tasks
13
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
14
+ $hoe = Hoe.spec 'insight_agent' do
15
+ self.developer 'John V Kew', 'jkew@vmware.com'
16
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
17
+ self.rubyforge_name = self.name # TODO this is default value
18
+ self.summary = 'An agent for Insight'
19
+ self.description = 'This agent will report traces to Insight'
20
+ self.extra_deps = [['activesupport','>= 3.0.0']]
21
+ end
22
+
23
+ # require 'newgem/tasks'
24
+ Dir['tasks/**/*.rake'].each { |t| load t }
25
+
26
+ # TODO - want other tests/tasks run by default? Add them to the list
27
+ # remove_task :default
28
+ # task :default => [:spec, :features]
@@ -0,0 +1,120 @@
1
+ # Constructs a frame tree from a series of
2
+ # related ActiveSupport::events
3
+ class EventTree
4
+ class Event
5
+ @name = nil
6
+ @label = nil
7
+ @startTime = nil
8
+ @endTime = nil
9
+ @invertEndTime = nil
10
+ @duration = nil
11
+ @payload = {}
12
+ def initialize(name, label, startTime, endTime, payload)
13
+ if startTime > endTime
14
+ raise "Invalid event, startTime is greater than endTime " + startTime.to_s + "->" + endTime.to_s
15
+ end
16
+ @name = name
17
+ @label = label
18
+ @startTime = startTime
19
+ @endTime = endTime
20
+ @payload = payload
21
+ @invertEndTime = - endTime.to_f
22
+ @duration = endTime - startTime
23
+ end
24
+ attr_accessor :name, :label, :duration, :invertEndTime, :startTime, :endTime, :payload
25
+
26
+ def contains(event)
27
+ event.startTime >= @startTime && event.endTime <= @endTime
28
+ end
29
+ end
30
+
31
+ # To separate lists are maintained, events is sorted by
32
+ # start time and duration, and eventsEnd
33
+ # by only endTime.
34
+ @events = []
35
+ @eventsEnd = []
36
+ @@DEFAULT_EVENT = "DEFAULT"
37
+
38
+ def initialize
39
+ @events = []
40
+ @eventsEnd = []
41
+ end
42
+
43
+ attr_accessor :DEFAULT_EVENT
44
+
45
+ # Prefer event with the longest duration
46
+ def chooseBestDefaultLabel(eventA, eventB)
47
+ if eventA.duration > eventB.duration
48
+ return eventA.label
49
+ end
50
+ return eventB.label
51
+ end
52
+
53
+ # Add an event to this tree
54
+ def addEvent(name, label, startTime, endTime, payload = {})
55
+ e = Event.new(name, label, startTime, endTime, payload)
56
+ @events << e
57
+ @events = @events.sort_by { |a| [ a.startTime, a.invertEndTime ] }
58
+ @eventsEnd << e
59
+ @eventsEnd = @eventsEnd.sort_by { |a| [ a.endTime, a.duration ]}
60
+ end
61
+
62
+ def dumpFrames
63
+ FrameBuilder.instance.reset
64
+ if @events == nil
65
+ raise "Trying to dump frame stack before any events collected"
66
+ end
67
+
68
+ # if needed, create a wrapper event if the events do not have
69
+ # a spanning parent
70
+ firstEvent = @events.first
71
+ lastEvent = @eventsEnd.last
72
+ if firstEvent != lastEvent
73
+ firstStartTime = @events.first.startTime
74
+ lastEndTime = @eventsEnd.last.endTime
75
+ puts " NEW DEFAULT " + firstStartTime.to_f.to_s + "->" + lastEndTime.to_f.to_s
76
+ label = chooseBestDefaultLabel(firstEvent, lastEvent)
77
+ @events << Event.new(@@DEFAULT_EVENT, label, firstStartTime, lastEndTime, {})
78
+ @events = @events.sort_by { |a| [ a.startTime, a.invertEndTime ] }
79
+ end
80
+
81
+ # run through the event list
82
+ stack = []
83
+ @events.each {|e|
84
+
85
+ # Create the root
86
+ if stack.size == 0
87
+ op = Operation.new(e.payload, e.label, e.name)
88
+ FrameBuilder.instance.enter(op, e.startTime)
89
+ stack << e
90
+ next
91
+ end
92
+
93
+ # If the last event on the stack cannot contain this one, crawl
94
+ # up the stack until we find one that does
95
+ while stack.size > 1 && !stack.last.contains(e)
96
+ FrameBuilder.instance.exit(stack.last.endTime, false)
97
+ stack.pop
98
+ end
99
+
100
+ # Add the event, enter the frame
101
+ op = Operation.new(e.payload, e.label, e.name)
102
+ FrameBuilder.instance.enter(op, e.startTime)
103
+ stack << e
104
+ }
105
+
106
+ # crawl back up the stack
107
+ while stack.size > 1
108
+ FrameBuilder.instance.exit(stack.last.endTime, false)
109
+ stack.pop
110
+ end
111
+
112
+ # final exit
113
+ trace = FrameBuilder.instance.exit(stack.last.endTime, false)
114
+ if trace != nil
115
+ return trace
116
+ end
117
+ raise "Unable to create complete frame stack from events. Your algorithm is broken."
118
+ end
119
+
120
+ end
@@ -0,0 +1,35 @@
1
+ # Ruby version of a Frame Object
2
+ # Self-time is not maintained here, only start and end time
3
+ class Frame
4
+ @id = 1
5
+ @startNanos = 0
6
+ @endNanos = 0
7
+ @operation = nil
8
+ @parent = nil
9
+ @children = []
10
+
11
+ def initialize(id, startNanos, endNanos, op, parentFrame = nil, childFrames=[])
12
+ @id = id
13
+ @startNanos = startNanos
14
+ @endNanos = endNanos
15
+ @operation = op
16
+ @parent = parentFrame
17
+ @children = childFrames
18
+ if @startNanos >= @endNanos
19
+ raise(ArgumentError, "StartNanos " + ("%d" % @startNanos) + " must be less than EndNanos " + ("%d" % @endNanos), Kernel.caller)
20
+ end
21
+ end
22
+
23
+ attr_accessor :startNanos, :endNanos, :operation, :parent, :children
24
+
25
+ # Used to handle the circular reference for the parent frame
26
+ def as_json(*a)
27
+ {
28
+ 'id' => @id,
29
+ 'startNanos' => "%d" % @startNanos, # must not be in scientific notation
30
+ 'endNanos' => "%d" % @endNanos,
31
+ 'operation' => @operation,
32
+ 'children' => @children
33
+ }.as_json(*a)
34
+ end
35
+ end
@@ -0,0 +1,83 @@
1
+ # Ruby version of the Java FrameBuilder Contructs a tree
2
+ # of frames through calls to enter and exit. One FrameBuilder
3
+ # is maintained per thread.
4
+ class FrameBuilder
5
+ @last = nil
6
+
7
+ def initialize()
8
+ @id = 0
9
+ @depth = 0
10
+ @current = nil
11
+ @parent = nil
12
+ end
13
+
14
+ attr_accessor :last, :depth
15
+
16
+ def self.instance
17
+ instance = Thread.current['instance']
18
+ if instance == nil
19
+ instance = Thread.current['instance'] = FrameBuilder.new
20
+ puts "Creating new instance of frame builder for thread " + Thread.current.object_id.to_s
21
+ end
22
+ return instance
23
+ end
24
+
25
+
26
+ def createFrame(id, operation, startTime, endTime, children = [])
27
+ startTimeNanos = startTime.to_f * 1000000000
28
+ endTimeNanos = endTime.to_f * 1000000000
29
+ if endTimeNanos.to_i <= startTimeNanos.to_i
30
+ endTimeNanos = startTimeNanos + 1000
31
+ end
32
+ Frame.new(id, startTimeNanos, endTimeNanos, operation, nil, children)
33
+ end
34
+
35
+ def enter(operation, time = Time.now )
36
+ startTimeNanos = time.to_f * 1000000000
37
+ @id += 1
38
+ @depth += 1
39
+ @parent = @current
40
+ initialEndTime = startTimeNanos + 1000
41
+ @current = Frame.new(@id, startTimeNanos, initialEndTime, operation, @parent, [])
42
+ end
43
+
44
+ def exit(time = Time.now, addTrace = true)
45
+ endTimeNanos = time.to_f * 1000000000
46
+
47
+ @depth -= 1
48
+ @current.endNanos = endTimeNanos
49
+ if @current.endNanos < @current.startNanos
50
+ raise "end time less than or equal to start time for frame " + @current.operation.label + "StartNanos " + ("%d" % @current.startNanos) + " must be less than EndNanos " + ("%d" % @current.endNanos)
51
+ end
52
+
53
+ # At root already
54
+ if @parent == nil
55
+ trace = TraceBuilder.instance.createTrace(@current)
56
+ if addTrace
57
+ TraceQueue.instance.addTrace(trace)
58
+ end
59
+ @last = @current
60
+ reset
61
+ trace
62
+ else
63
+ @parent.children << @current
64
+ @current = @parent
65
+ @parent = @current.parent
66
+ nil
67
+ end
68
+ end
69
+
70
+ def reset()
71
+ @id = 0
72
+ @depth = 0
73
+ @current = nil
74
+ @parent = nil
75
+ end
76
+
77
+
78
+ def lastStart
79
+ if last != null
80
+ @last.startNanos / 1000000
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,59 @@
1
+ # Rails entry point for the insight-agent
2
+ class InsightAgent
3
+ @@dispatcher = nil
4
+
5
+ # Hash of eventId => EventTree
6
+ @@events = {}
7
+ def initialize(app, url, user, pass)
8
+ @@dispatcher = TraceDispatcher.new(url, user, pass)
9
+ TraceBuilder.instance.setApplication(app)
10
+ @@dispatcher.start
11
+ puts "dispatcher started"
12
+ initialize_active_support()
13
+ end
14
+
15
+ def initialize_plugins()
16
+ # load a series of plugins from a known location
17
+
18
+ end
19
+
20
+ def initialize_active_support()
21
+ # Subscribe to every event in the system
22
+ ActiveSupport::Notifications.subscribe do |name, start, finish, id, payload|
23
+ #puts id + " " + name + " " + start.to_f.to_s + "->" + finish.to_f.to_s
24
+ eventTree = @@events[id]
25
+ if eventTree == nil
26
+ eventTree = EventTree.new
27
+ @@events[id] = eventTree
28
+ end
29
+
30
+ # All properties should be simple strings
31
+ properties = {}
32
+ payload.each { |key, value| properties[key] = value.to_s }
33
+
34
+ # Effectively endpoint analyzers; events are collected by id
35
+ # until the event with the name, "process_action.action_controller"
36
+ # at that point the events are dumped into a trace/frame stack and
37
+ # stored on the TraceQueue.
38
+ # TODO:
39
+ # - Deletes on the model do not seem to be picked up here
40
+ # - If a series of events are collected which do not end
41
+ # with this named event, a dud EventTree could be sitting
42
+ # around in the hash
43
+ if name == "process_action.action_controller"
44
+ label = payload[:path]
45
+ eventTree.addEvent(name, label, start, finish, properties)
46
+ trace = eventTree.dumpFrames
47
+ TraceQueue.instance.addTrace(trace)
48
+ @@events[id] = nil
49
+ else
50
+ eventTree.addEvent(name, name, start, finish, properties)
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ def stop
57
+ @@dispatcher.stop
58
+ end
59
+ end
@@ -0,0 +1,26 @@
1
+ class MethodOperation
2
+
3
+ def initialize(clazz, methodName)
4
+ WrapMethod.instance.wrap(clazz, methodName, createOperation)
5
+ end
6
+
7
+ def createOperation(point, clazz, method, args)
8
+ if point == :enter
9
+ properties = {}
10
+ if args != nil
11
+ index = 0
12
+ args.each do |arg|
13
+ properties["arg" + index.to_s] = arg.to_s
14
+ index += 1
15
+ end
16
+ end
17
+ label = clazz.to_s + ":" + method.to_s
18
+ op = Operation.new(properties, label, label)
19
+ FrameBuilder.instance.enter(op)
20
+ end
21
+ if point == :exit
22
+ FrameBuilder.instance.exit()
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,16 @@
1
+ # Ruby version of the Operation
2
+ class Operation
3
+ @properties = {}
4
+ @label = ""
5
+ @operationType = ""
6
+
7
+ def initialize(properties, label, operationType)
8
+ @properties = properties
9
+ @label = label
10
+ @operationType = operationType
11
+ end
12
+
13
+ attr_accessor :label, :operationType
14
+
15
+
16
+ end
@@ -0,0 +1,20 @@
1
+ # Ruby version of a Trace
2
+ class Trace
3
+ @id = nil
4
+ @date = nil
5
+ @server = nil
6
+ @root = nil
7
+ @appName = nil
8
+
9
+ attr_accessor :root
10
+
11
+ def initialize(id, date, server, appName, root)
12
+ @id = id
13
+ @date = date
14
+ @server = server
15
+ @appName = appName
16
+ @root = root
17
+ end
18
+ end
19
+
20
+
@@ -0,0 +1,28 @@
1
+ # Builds a trace using configured values for the server, pid, and application
2
+ require 'monitor'
3
+ require 'singleton'
4
+ require "socket"
5
+
6
+ class TraceBuilder < Monitor
7
+ include Singleton
8
+ @@server = Socket.gethostname
9
+ @@pid = Process.pid.to_s
10
+ @@application = "myapplication"
11
+ @@id = 0
12
+ @@random = rand(10000).to_s
13
+
14
+ def createTrace(frame)
15
+ synchronize do
16
+ @@id += 1
17
+ Trace.new(@@random + "-" + @@id.to_s, frame.startNanos, @@server + "-" + @@pid, @@application, frame)
18
+ end
19
+ end
20
+
21
+ def setApplication(app)
22
+ @@application = app
23
+ end
24
+
25
+ def setServer(srv)
26
+ @@server = srv
27
+ end
28
+ end
@@ -0,0 +1,84 @@
1
+ # Simplistic, asynchronous trace dispatcher. Pulls
2
+ # traces off the TraceQueue and sends them along to
3
+ # Spring Insight over REST as JSON
4
+ #
5
+ # Requires ActiveSupport::JSON
6
+ # The rails JSON is used here due to incompatibilities
7
+ # when using the non-rails JSON inside of Rails
8
+ # ActiveSupport::JSON overrides JSON behaviour in wierd
9
+ # ways
10
+ class TraceDispatcher
11
+ require 'net/http'
12
+ require 'rubygems'
13
+ require 'active_support/json'
14
+ require 'active_support/ordered_hash'
15
+
16
+ @host = "localhost"
17
+ @port = 8080
18
+ @user = ""
19
+ @pass = ""
20
+ @thread = nil
21
+ @running = false
22
+
23
+ def initialize(url, user, pass)
24
+ uri = URI.parse(url)
25
+ @host = uri.host
26
+ @port = uri.port
27
+ @user = user
28
+ @pass = pass
29
+ end
30
+
31
+ public
32
+
33
+ def start()
34
+ @running = true
35
+ @thread = Thread.new {
36
+ while @running do
37
+ while poll() do
38
+ ## noop
39
+ end
40
+ sleep(0.1)
41
+ end
42
+ }
43
+ end
44
+
45
+ def stop()
46
+ if @thread != nil
47
+ @running = false
48
+ @thread.join
49
+ end
50
+ end
51
+
52
+ def poll()
53
+ trace = TraceQueue.instance.getTrace()
54
+ if trace != nil
55
+ send(trace)
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ def self.convert_to_json(trace)
63
+ trace.to_json
64
+ end
65
+
66
+ def send(trace)
67
+ dispatch(@host, @port, @user, @pass, TraceDispatcher.convert_to_json(trace))
68
+ end
69
+
70
+ def dispatch(host, port, user, pass, traceJSON)
71
+ puts traceJSON
72
+ path="/insight/services/traces/rest/dispatch"
73
+ headers = {'Content-Type' =>'application/json'}
74
+ http = Net::HTTP.new(host, port)
75
+ req = Net::HTTP::Put.new(path,headers)
76
+ req.basic_auth user, pass
77
+ req.body = traceJSON
78
+ res, data = http.request(req)
79
+ puts data
80
+ end
81
+
82
+ end
83
+
84
+
@@ -0,0 +1,22 @@
1
+ # Maintains a simple queue of traces
2
+ # We want to use the Ruby Queue implementation
3
+ # here, except for this:
4
+ # http://redmine.ruby-lang.org/issues/2092
5
+ require 'singleton'
6
+ require 'monitor'
7
+
8
+ class TraceQueue < Monitor
9
+ include Singleton
10
+ @@trace_queue = []
11
+ def addTrace(trace)
12
+ synchronize do
13
+ @@trace_queue << trace
14
+ end
15
+ end
16
+
17
+ def getTrace()
18
+ synchronize do
19
+ @@trace_queue.shift
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ # Worthy ideas for this were taken from
2
+ # https://github.com/jordansissel/ruby-minstrel/blob/master/lib/minstrel.rb
3
+ require 'singleton'
4
+ require 'monitor'
5
+
6
+ class WrapMethod < Monitor
7
+ include Singleton
8
+
9
+ @@wrapped = []
10
+
11
+ def key(clazz, method)
12
+ clazz.to_s + ":" + method.to_s
13
+ end
14
+
15
+ def wrap(clazz, methodName, &block)
16
+ methodKey = key(clazz, methodName)
17
+ if @@wrapped.index(methodKey) != nil
18
+ raise methodKey + " Previously wrapped"
19
+ end
20
+ synchronize do
21
+ clazz.instance_methods.each do |inst_method|
22
+ if inst_method == methodName
23
+ # crack the class
24
+ clazz.instance_eval do
25
+ # rename the original method
26
+ inst_method_sym = inst_method.to_sym
27
+ renamed_inst_method_sym = ("insight_wrapped_" + inst_method).to_sym
28
+ puts "Aliasing " + inst_method.to_s + " -> " + renamed_inst_method_sym.to_s + "\n"
29
+ alias_method renamed_inst_method_sym, inst_method_sym
30
+ insight_method_name = ("insight_wrapper_" + inst_method).to_sym
31
+
32
+ # Define a new method which executes our code at the beginning
33
+ # and end
34
+ puts "Creating " + insight_method_name.to_s + "\n"
35
+ define_method insight_method_name do |*args, &argblock|
36
+ block.call(:enter, clazz, inst_method, *args)
37
+ if renamed_inst_method_sym.is_a?(Symbol)
38
+ val = send(renamed_inst_method_sym, *args, &argblock)
39
+ else
40
+ val = renamed_inst_method_sym.call(*args, &argblock)
41
+ end
42
+ block.call(:exit, clazz, inst_method, *args)
43
+ end
44
+
45
+ # Alias our method over the original one
46
+ puts "Aliasing " + inst_method.to_s + " -> " + insight_method_name.to_s + "\n"
47
+ alias_method inst_method_sym, insight_method_name
48
+ end
49
+ @@wrapped << methodKey
50
+ @@wrapped.sort
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/agent.rb ADDED
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ require 'agent/frame'
4
+ require 'agent/frame_builder.rb'
5
+ require 'agent/operation.rb'
6
+ require 'agent/trace.rb'
7
+ require 'agent/frame_builder.rb'
8
+ require 'agent/trace_dispatcher.rb'
9
+ require 'agent/trace_queue.rb'
10
+ require 'agent/trace_builder.rb'
11
+ require 'agent/insight_agent.rb'
12
+ require 'agent/event_tree.rb'
13
+ require 'agent/wrap_method.rb'
14
+ require 'agent/method_operation.rb'
15
+
16
+ module Agent
17
+ VERSION = '0.0.7'
18
+ end
19
+
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/agent.rb'}"
9
+ puts "Loading agent gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'stringio'
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/agent'
5
+
6
+ class TraceDispatcher
7
+ @@count = 0
8
+ def getDispatchCount()
9
+ @@count
10
+ end
11
+
12
+ def dispatch(host, port, user, pass, trace)
13
+ @@count += 1
14
+ end
15
+ end
16
+
17
+ class TestAgent < Test::Unit::TestCase
18
+
19
+ def setup
20
+ end
21
+
22
+ def test_trace_flow
23
+ salt="test"
24
+ dispatcher = TraceDispatcher.new("http://localhost:8080", "admin", "insight")
25
+
26
+ builder = TraceBuilder.instance
27
+ builder.setApplication("App" + salt)
28
+ builder.setServer("Svr" + salt)
29
+
30
+ t1 = Thread.new { 4.times { createTrace(salt) } }
31
+ t2 = Thread.new { 4.times { createTrace(salt) } }
32
+ t3 = Thread.new { 4.times { createTrace(salt) } }
33
+ t4 = Thread.new { 4.times { createTrace(salt) } }
34
+ dispatcher.start
35
+ t1.join
36
+ t2.join
37
+ t3.join
38
+ t4.join
39
+ sleep(0.2)
40
+ dispatcher.stop
41
+ assert_equal(16,dispatcher.getDispatchCount())
42
+
43
+ end
44
+ end
45
+
46
+
47
+ def fakeMethod(salt)
48
+ op = Operation.new({}, "fakeMethod" + salt, "SuperOperation" + salt)
49
+ FrameBuilder.instance.enter op
50
+ sleep(0.2)
51
+ fakeSubMethod salt
52
+ sleep(0.1)
53
+ FrameBuilder.instance.exit
54
+ end
55
+
56
+ def fakeSubMethod(salt)
57
+ op = Operation.new({}, "fakeSubMethod" + salt, "PunyOperation" + salt)
58
+ FrameBuilder.instance.enter op
59
+ sleep(0.1)
60
+ FrameBuilder.instance.exit
61
+ end
62
+
63
+
64
+ def createTrace(salt)
65
+ mysalt = salt + Thread.current.object_id.to_s
66
+ fakeMethod mysalt
67
+ frame = FrameBuilder.instance.last
68
+ trace = Trace.new(salt + "worthy-9", frame.startNanos, "MyServer" + salt, "MyApp" + salt, frame)
69
+ end
70
+
71
+
72
+
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'stringio'
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/agent'
5
+ require 'active_support/json'
6
+ require 'active_support/ordered_hash'
7
+
8
+ class TestFrameBuilder < Test::Unit::TestCase
9
+
10
+ def setup
11
+ end
12
+
13
+ def printTree(frame, depth)
14
+ ot = frame.operation.operationType
15
+ printf("%" + depth.to_s + "s %d\n",ot, depth)
16
+ children = frame.children
17
+ children.each {|c| printTree(c, 1 + depth)}
18
+ end
19
+
20
+ def isCorrect(frame, map)
21
+ ot = frame.operation.operationType
22
+ assert(map[ot] != nil, "Frame with operation " + ot + " is not in map " + map.to_s)
23
+ children = frame.children
24
+ children.each {|c| isCorrect(c, map[ot])}
25
+ end
26
+
27
+ def test_event_tree_normal_order
28
+ et = EventTree.new
29
+ et.addEvent("B", "B Label", Time.at(5), Time.at(20))
30
+ et.addEvent("C", "C Label",Time.at(22), Time.at(80))
31
+ et.addEvent("D", "D Label",Time.at(5), Time.at(90))
32
+ et.addEvent("E", "E Label",Time.at(92), Time.at(95))
33
+ et.addEvent("A", "A Label",Time.at(0), Time.at(100))
34
+ trace = et.dumpFrames
35
+ expected = {"A" => {"D" => {"B" => {}, "C" => {}}, "E" => {}}}
36
+ isCorrect(trace.root, expected)
37
+ end
38
+
39
+ # The root of this should be the DEFAULT operation type,
40
+ # formed from the rootless remains of other out-of-order
41
+ # events
42
+ def test_event_tree_wierd_order
43
+ et = EventTree.new
44
+ et.addEvent("B", "B Label",Time.at(5), Time.at(20))
45
+ et.addEvent("A", "A Label",Time.at(0), Time.at(100))
46
+ et.addEvent("E", "E Label",Time.at(92), Time.at(95))
47
+ et.addEvent("C", "C Label",Time.at(22), Time.at(80))
48
+ et.addEvent("D", "D Label",Time.at(5), Time.at(90))
49
+ trace = et.dumpFrames
50
+ puts "\n"
51
+ printTree(trace.root, 1)
52
+
53
+ #INSIGHT_STUB 0
54
+ # A 1
55
+ # B 2
56
+ # E 1
57
+ # C 1
58
+ # D 1
59
+ expected = {"A" => {"D" => {"B" => {}, "C" => {}}, "E" => {}}}
60
+
61
+ #expected = {"DEFAULT" => {"A" => {"B" => {}}, "E" => {}, "C" => {}, "D" => {}}}
62
+ isCorrect(trace.root, expected)
63
+ end
64
+
65
+ def test_overlap
66
+ et = EventTree.new
67
+ et.addEvent("S", "S-start_processing.action_controller", Time.at(1298858931.01111), Time.at(1298858931.01111))
68
+ et.addEvent("SQL", "SQL-sql.active_record", Time.at(1298858931.06312), Time.at(1298858931.10826))
69
+ et.addEvent("R1", "R1-!render_template.action_view", Time.at(1298858931.06312), Time.at(1298858931.10826))
70
+ et.addEvent("R2", "R2-!render_template.action_view", Time.at(1298858931.10888), Time.at(1298858931.11169))
71
+ et.addEvent("R3", "R3-render_template.action_view", Time.at(1298858931.06305), Time.at(1298858931.11211))
72
+ et.addEvent("P", "P-process_action.action_controller", Time.at(1298858931.01187), Time.at(1298858931.11537))
73
+
74
+ trace = et.dumpFrames
75
+ puts "\n"
76
+ printTree(trace.root, 1)
77
+ expected={"DEFAULT" => {"S" => {}, "P" => { "R3" => {"R1" => {"SQL" => {}}, "R2" => {}}}}}
78
+ isCorrect(trace.root, expected)
79
+ end
80
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'stringio'
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/agent'
5
+
6
+ class TestFrameBuilder < Test::Unit::TestCase
7
+
8
+ def setup
9
+ end
10
+
11
+ def test_builder
12
+ op = Operation.new({}, "fakeSubMethod", "PunyOperation")
13
+ fb = FrameBuilder.instance
14
+ t = TraceBuilder.instance.createTrace(
15
+ fb.createFrame(0, op, 0, 20, [ fb.createFrame(1, op, 0, 10), fb.createFrame(2, op, 10, 20) ]))
16
+ traceJSON = TraceDispatcher.convert_to_json(t)
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/agent'
@@ -0,0 +1,110 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'stringio'
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/agent'
5
+
6
+ class TestClass
7
+
8
+ def initialize()
9
+ @noargcalls = 0
10
+ @argscalls = 0
11
+ @yields = 0
12
+ end
13
+
14
+ def noarg()
15
+ @noargcalls += 1
16
+ end
17
+
18
+ def argsmethod(myarg)
19
+ @argscalls += 1
20
+ end
21
+
22
+ def blockmethod()
23
+ @yields += 1
24
+ yield
25
+ end
26
+
27
+ attr_accessor :noargcalls, :argscalls, :yields
28
+ end
29
+
30
+ class TestWrapMethod < Test::Unit::TestCase
31
+ @enters = nil
32
+ @exits = nil
33
+ @args = nil
34
+ @blocks = nil
35
+ @@wrapper = WrapMethod.instance
36
+ def setup
37
+ @enters = 0
38
+ @exits = 0
39
+ @args = nil
40
+ @blocks = nil
41
+ end
42
+
43
+ def wrapit(method)
44
+ WrapMethod.instance.wrap(TestClass, method) do |point, clazz, method, args|
45
+ puts point.to_s + ":" + method.to_s
46
+ if args != nil
47
+ args.each do |arg|
48
+ puts "\t" + arg
49
+ end
50
+ end
51
+
52
+ if point == :enter
53
+ @enters += 1
54
+ @args = args
55
+ end
56
+ if point == :exit
57
+ @exits += 1
58
+ end
59
+
60
+ end
61
+ end
62
+
63
+ def test_wrap_no_arg
64
+ wrapit("noarg")
65
+ go = TestClass.new
66
+ go.insight_wrapped_noarg
67
+ assert go.noargcalls == 1
68
+ assert @enters == 0
69
+ assert @exits == 0
70
+ assert @args == nil
71
+ go.noarg
72
+ assert go.noargcalls == 2
73
+ assert @enters == 1
74
+ assert @exits == 1
75
+ assert @args == nil
76
+ end
77
+
78
+ def test_wrap_argsmethod
79
+ wrapit("argsmethod")
80
+ go = TestClass.new
81
+ go.insight_wrapped_argsmethod "Hi There"
82
+ assert go.argscalls == 1
83
+ assert @enters == 0
84
+ assert @exits == 0
85
+ assert @args == nil
86
+ go.argsmethod "Oats"
87
+ assert go.argscalls == 2
88
+ assert @enters == 1
89
+ assert @exits == 1
90
+ assert @args == "Oats"
91
+ end
92
+
93
+ def test_wrap_blockmethod
94
+ wrapit("blockmethod")
95
+ inblocks = 0
96
+ go = TestClass.new
97
+ go.insight_wrapped_blockmethod { puts "In Block1"; inblocks += 1 }
98
+ assert go.yields == 1
99
+ assert @enters == 0
100
+ assert @exits == 0
101
+ assert @args == nil
102
+ assert inblocks == 1
103
+ go.blockmethod { puts "In Block2"; inblocks += 1 }
104
+ assert go.yields == 2
105
+ assert @enters == 1
106
+ assert @exits == 1
107
+ assert @args == nil
108
+ assert inblocks == 2
109
+ end
110
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: insight_agent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John V Kew
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-19 00:00:00.000000000 +03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ requirement: &22063820 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *22063820
26
+ - !ruby/object:Gem::Dependency
27
+ name: hoe
28
+ requirement: &22063120 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 2.9.4
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *22063120
37
+ description: This agent will report traces to Insight
38
+ email:
39
+ - jkew@vmware.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - PostInstall.txt
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - PostInstall.txt
50
+ - README.rdoc
51
+ - Rakefile
52
+ - lib/agent.rb
53
+ - lib/agent/frame.rb
54
+ - lib/agent/frame_builder.rb
55
+ - lib/agent/operation.rb
56
+ - lib/agent/trace.rb
57
+ - lib/agent/trace_builder.rb
58
+ - lib/agent/trace_dispatcher.rb
59
+ - lib/agent/trace_queue.rb
60
+ - lib/agent/insight_agent.rb
61
+ - lib/agent/event_tree.rb
62
+ - lib/agent/wrap_method.rb
63
+ - lib/agent/method_operation.rb
64
+ - script/console
65
+ - script/destroy
66
+ - script/generate
67
+ - test/test_agent.rb
68
+ - test/test_helper.rb
69
+ - test/test_wrap_method.rb
70
+ - test/test_event_tree.rb
71
+ - test/test_frame_builder.rb
72
+ - .gemtest
73
+ has_rdoc: true
74
+ homepage:
75
+ licenses: []
76
+ post_install_message: PostInstall.txt
77
+ rdoc_options:
78
+ - --main
79
+ - README.txt
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project: insight_agent
96
+ rubygems_version: 1.6.2
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: An agent for Insight
100
+ test_files:
101
+ - test/test_agent.rb
102
+ - test/test_wrap_method.rb
103
+ - test/test_helper.rb
104
+ - test/test_event_tree.rb
105
+ - test/test_frame_builder.rb