trace-util-adv 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG +7 -0
  2. data/VERSION +1 -1
  3. data/lib/README +87 -0
  4. data/lib/TODO.txt +12 -0
  5. data/lib/action_handler.rb +99 -0
  6. data/lib/appenders/appender.rb +97 -0
  7. data/lib/appenders/appender_registration.rb +16 -0
  8. data/lib/appenders/base_appender.rb +82 -0
  9. data/lib/appenders/file_appender.rb +72 -0
  10. data/lib/appenders/html_appender.rb +94 -0
  11. data/lib/appenders/logger_appender.rb +84 -0
  12. data/lib/appenders/stream_appender.rb +37 -0
  13. data/lib/appenders/template_log_appender.rb +28 -0
  14. data/lib/appenders/xml_appender.rb +75 -0
  15. data/lib/core_extensions.rb +101 -0
  16. data/lib/filters/base_filters.rb +178 -0
  17. data/lib/filters/composite_filters.rb +71 -0
  18. data/lib/filters/filter_factory.rb +17 -0
  19. data/lib/filters/message_filters.rb +35 -0
  20. data/lib/filters/tracing_filter.rb +88 -0
  21. data/lib/output_templates.rb +5 -0
  22. data/lib/rule_match.rb +38 -0
  23. data/lib/sample_filters.rb +95 -0
  24. data/lib/templates/base_template.rb +21 -0
  25. data/lib/templates/html_template.rb +48 -0
  26. data/lib/templates/string_template.rb +30 -0
  27. data/lib/templates/trace_output_handler.rb +47 -0
  28. data/lib/templates/xml_template.rb +36 -0
  29. data/lib/test_action_handler.rb +34 -0
  30. data/lib/test_appender.rb +29 -0
  31. data/lib/test_file_appender.rb +32 -0
  32. data/lib/test_filters.rb +112 -0
  33. data/lib/test_filters_chain.rb +100 -0
  34. data/lib/test_filters_create.rb +28 -0
  35. data/lib/test_html_appender.rb +66 -0
  36. data/lib/test_special_filters.rb +78 -0
  37. data/lib/test_xml_appender.rb +66 -0
  38. data/lib/test_xml_gen.rb +46 -0
  39. data/lib/trace_appenders.rb +9 -0
  40. data/lib/trace_calls.rb +86 -0
  41. data/lib/trace_ext.rb +57 -0
  42. data/lib/trace_filters.rb +4 -0
  43. data/trace-util-adv.gemspec +98 -0
  44. metadata +44 -2
data/CHANGELOG ADDED
@@ -0,0 +1,7 @@
1
+ 27-10-2009
2
+ ==========
3
+ * Created filter_factory.rb
4
+ - will include convenience methods to create and operate on filters
5
+ - should be used when registering filters in all cases
6
+
7
+ Framework has become overly complex - simplify, and refactor!
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
data/lib/README ADDED
@@ -0,0 +1,87 @@
1
+ Advanced TraceUtils
2
+ ===================
3
+ last update: 26/10/2009
4
+ By kristian mandrup, kmandrup@gmail.com
5
+ ---
6
+
7
+ This project enables advanced TRACING capabilities on any Ruby application, class or module.
8
+
9
+ The project was inspired by TraceUtils, a little meta-programming example (~50 lines of code) by Dave Thomas
10
+ (See Pragmatic Bookstore - http://pragprog.com/)
11
+
12
+ The original TraceUtils has been completely refactored and expanded to include:
13
+ - Indentation according to nesting level of methods calls
14
+ - Define sets of context filters for when to apply tracing on a method, when to apply appenders etc
15
+ - module, class, method, instance variable and composite filters
16
+ - Action handlers to handle each trace/log statement
17
+ - Appenders, similar to log4j appenders, to allow channeling of trace messages to multiple trace consumers
18
+ - Action handlers and Appenders can also have context filters registered
19
+ - Custom Filters
20
+
21
+ Design
22
+ ------
23
+ - Log message
24
+ each log message consists of the message itself and its current context. The context includes:
25
+ - Modules/Classes hierarchy of the method where the log statement is called
26
+ - Method name
27
+ - Instance variables
28
+
29
+ TODO:
30
+ log messages can be inserted in your application code and will be handled by the tracing framework.
31
+ Currently the framework only supports tracing of method entry and exits.
32
+
33
+ - Tracing::TraceExt
34
+ is configured with a set of action handlers (see below)
35
+ can be configured with a set of filters
36
+
37
+ - Tracing::TraceCalls
38
+ each Module/Class which should have tracing applied must include the TraceCalls module
39
+ when TraceCalls is included, the 'included' callback method iterates all instance methods of the module it has been included
40
+ for each such instance method, it will apply a 'before' and 'after' aspect to the instance method only if all filters registered
41
+ directly on TraceExt are passed.
42
+
43
+ When (the application runs and) the instance method is called, each action handler registered with TraceExt is called to handle the "runtime" tracing
44
+
45
+ - Filter
46
+ decides whether the trace message and current context should "pass through". Multiple filters act as a filter chain, where all filters
47
+ in the chain must be passed the filtered item is rejected
48
+ - ModuleFilter, ClassFilter, MethodFilter, CompositeModuleFilter, CompositeClassFilter, InstanceVarFilter, CompositeInstanceVarFilter
49
+
50
+ You can also specify custom filters (see class RangeFilter in filters/message_filters.rb)
51
+ Filters can also include custom include/exclude filters using Procs or Classes (see test_special_filters.rb)
52
+
53
+ TODO
54
+ soon filters will be a lot easier to set up for the simple use cases!
55
+
56
+ - ActionHandler
57
+ handles a runtime logging action
58
+ can be configured with a set of filters and appenders
59
+ if all filters are passed for the given log message and context, each appender is called in turn with the same message and context
60
+ The appenders can also be set using registered appenders with symbols. Default symbol mappings are:
61
+ :logger, :xml, :html, :template
62
+
63
+ For more on Appenders, see section below
64
+
65
+ Usage:
66
+ @ah1 = Tracing::ActionHandler.new(:filters => [Module_filter_A, Method_filter_A], :appenders => [tla1])
67
+
68
+ Alternative appender configuration using symbols:
69
+ @ah1 = Tracing::ActionHandler.new(:filters => [Module_filter_A, Method_filter_A], :appenders => [:template, :xml])
70
+
71
+
72
+ - Appender
73
+ is configured with some appender options specific to the type of Appender
74
+ must be configured with a Tracer that renders the output string which the appender the appends to some consumer, such as a stream
75
+ - LoggerAppender, HtmlAppender, XmlAppender, FileAppender
76
+ - TemplatateLogAppender
77
+
78
+ Usage:
79
+ tla1 = Tracing::TemplateLogAppender.new(:options => {:overwrite => false, :time_limit => 2.minutes}, :tracer => :string)
80
+
81
+ For any Appender, the tracer configuration can be set using a symbol :string, :xml, :html.
82
+ Otherwise the default tracer for the given appender is used, fx HtmlTracer for the HtmlAppender.
83
+
84
+ Examples of use
85
+ --------------
86
+ - test_filters.rb
87
+ - test_special_filters.rb
data/lib/TODO.txt ADDED
@@ -0,0 +1,12 @@
1
+ Test String appender
2
+ - log string to file
3
+
4
+
5
+
6
+ Test library in general
7
+ - functions as expected?
8
+ - easy to use?
9
+ - create RSpec tests?
10
+
11
+
12
+ http://www.extjswithrails.com/2008/03/fitting-ext-js-into-rails-architecture.html
@@ -0,0 +1,99 @@
1
+ require 'filters/tracing_filter'
2
+ require 'trace_appenders'
3
+
4
+ module Tracing
5
+ class ActionHandler
6
+ include Tracing::Filter::Registration
7
+ include Tracing::Filter::Exec
8
+ include Tracing::Appender::Registration
9
+
10
+ attr_accessor :filters
11
+
12
+ # enable registration of action handlers
13
+ module Registration
14
+ attr_accessor :action_handlers
15
+
16
+ def action_handler_from_type(type, options)
17
+ if type.kind_of?(Symbol)
18
+ type_sym = type.to_sym
19
+ # use default mappings if no match found
20
+ appender_class = appender_mappings[type_sym] || action_handler_mappings[:default]
21
+ if appender_class
22
+ appender_class.new(options)
23
+ else
24
+ # nil
25
+ raise Exception, "No appender registered for this type: #{type}"
26
+ end
27
+ elsif appender.kind_of? Tracing::OutputTemplate::Trace
28
+ appender
29
+ else
30
+ nil
31
+ end
32
+ end
33
+
34
+ def create_action_handlers(reg_action_handlers)
35
+ if reg_action_handlers.kind_of? Array
36
+ reg_action_handlers.flatten!
37
+ new_action_handlers = reg_action_handlers.collect do |f|
38
+ create_action_handler(f)
39
+ end
40
+ new_action_handlers
41
+ elsif reg_action_handlers.kind_of?(Symbol) || reg_action_handlers.kind_of?(Hash)
42
+ create_action_handler(reg_action_handlers)
43
+ else
44
+ reg_action_handlers
45
+ end
46
+ end
47
+
48
+ def create_action_handler(options)
49
+ if options.kind_of? Tracing::ActionHandler
50
+ options
51
+ elsif options.kind_of? Hash
52
+ Tracing::ActionHandler.new(options)
53
+ elsif options.kind_of?(Symbol) || options.kind_of?(String)
54
+ type = options.to_sym
55
+ Tracing::Appender.appender_from_type(type, options)
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ # TODO: add convenience way to register action handlers using symbols!
62
+ def register_action_handlers(reg_action_handlers)
63
+ @action_handlers ||= []
64
+ new_action_handlers = create_action_handlers(reg_action_handlers)
65
+ raise Exception, "No action handlers" if !new_action_handlers
66
+ @action_handlers << new_action_handlers
67
+ end
68
+ end
69
+
70
+ # register filters and appenders
71
+ def initialize(init_options)
72
+ register_filters(init_options[:filters])
73
+ register_appenders(init_options[:appenders] || init_options)
74
+ end
75
+
76
+ # action for tracelogs that pass the filters
77
+ # by default send to all appenders for further processing!
78
+ def handle_allow(txt, context)
79
+ appenders.each do |appender|
80
+ appender.handle(txt, context)
81
+ end
82
+ end
83
+
84
+ # action for tracelogs that DO NOT pass the filters
85
+ def handle_not_allow(txt, context)
86
+ end
87
+
88
+ # handle tracelogs by applying filters and action handler methods
89
+ def handle(txt, context)
90
+ if filters_allow?(txt, context)
91
+ # puts "handle_allow: " + context[:method_name]
92
+ handle_allow(txt, context)
93
+ else
94
+ # puts "handle_not_allow: " + context[:method_name]
95
+ handle_not_allow(txt, context)
96
+ end
97
+ end
98
+ end # class
99
+ end # module
@@ -0,0 +1,97 @@
1
+ module Tracing
2
+ module Appender
3
+
4
+ class << self
5
+
6
+ # array of Appender instances
7
+ attr_accessor :appender_mappings
8
+
9
+ # used to help construct/register Appender instances using convenience symbols
10
+ def default_appender_mappings
11
+ {
12
+ :logger => Tracing::LoggerAppender,
13
+ :stream => Tracing::StreamAppender,
14
+ :xml => Tracing::XmlAppender,
15
+ :html => Tracing::HtmlAppender,
16
+ :template => Tracing::TemplateLogAppender,
17
+ :default => Tracing::StreamAppender
18
+ }
19
+ end
20
+
21
+ def register_default_mappings
22
+ @appender_mappings ||= {}
23
+ @appender_mappings.merge!(default_appender_mappings)
24
+ end
25
+
26
+ def register_appender_mappings(_appender_mappings)
27
+ appenders_mappings ||= {}
28
+ appenders_mappings.merge!(_appender_mappings)
29
+ end
30
+
31
+ def unregister_appender_mappings(hash)
32
+ default_appender_mappings.reject!{|key, value| hash.include? key}
33
+ end
34
+
35
+
36
+ def create_appenders(appenders)
37
+ register_default_mappings if !appender_mappings
38
+ if appenders.kind_of? Array
39
+ appenders.flatten!
40
+ new_appenders = appenders.collect do |f|
41
+ Tracing::Appender.create_appender(f)
42
+ end
43
+ new_appenders
44
+ elsif appenders.kind_of?(Symbol) || appenders.kind_of?(Hash)
45
+ Tracing::Appender.create_appender(appenders)
46
+ else
47
+ appenders
48
+ end
49
+ end
50
+
51
+ def appender_options_type(options)
52
+ options[:type]
53
+ end
54
+
55
+ def appender_type(options)
56
+ if options.kind_of? Hash
57
+ appender_options_type(options)
58
+ elsif options.kind_of?(Symbol) || options.kind_of?(String)
59
+ options.to_sym
60
+ end
61
+ end
62
+
63
+ def appender_from_type(type, options)
64
+ register_default_mappings if !appender_mappings
65
+ if type.kind_of?(Symbol)
66
+ type_sym = type.to_sym
67
+ # use default mappings if no match found
68
+ appender_class = appender_mappings[type_sym] || appender_mappings[:default]
69
+ if appender_class
70
+ appender_class.new(options)
71
+ else
72
+ # nil
73
+ raise Exception, "No appender registered for this type: #{type}"
74
+ end
75
+ elsif appender.kind_of? Tracing::OutputTemplate::Trace
76
+ appender
77
+ else
78
+ nil
79
+ end
80
+ end
81
+
82
+ #
83
+ def create_appender(options)
84
+ appender_mappings ||= {}
85
+ type = appender_type(options)
86
+ if type
87
+ appender_from_type(type, options)
88
+ elsif options.kind_of? Tracing::BaseAppender
89
+ options
90
+ else
91
+ nil
92
+ end
93
+ end
94
+ end # class
95
+
96
+ end
97
+ end
@@ -0,0 +1,16 @@
1
+ module Tracing
2
+ module Appender
3
+
4
+ # enable registration of appenders
5
+ module Registration
6
+ attr_accessor :appenders
7
+
8
+ def register_appenders(appenders)
9
+ @appenders ||= []
10
+ new_appenders = Tracing::Appender.create_appenders(appenders)
11
+ @appenders.add(new_appenders) if new_appenders
12
+ end
13
+
14
+ end # registration
15
+ end
16
+ end
@@ -0,0 +1,82 @@
1
+ module Tracing
2
+ # base appender (abstract)
3
+ class BaseAppender
4
+ include Tracing::Filter::Registration
5
+ include Tracing::Filter::Exec
6
+
7
+ attr_accessor :options
8
+ attr_reader :tracer
9
+
10
+ class << self
11
+ attr_accessor :tracers
12
+
13
+ def default_tracers
14
+ {
15
+ :string => Tracing::OutputTemplate::StringTrace,
16
+ :xml => Tracing::OutputTemplate::XmlTrace,
17
+ :html => Tracing::OutputTemplate::HtmlTrace,
18
+ :default => Tracing::OutputTemplate::StringTrace
19
+ }
20
+ end
21
+
22
+ def register_tracers(tracers = nil)
23
+ @tracers ||= default_tracers
24
+ @tracers = @tracers.merge!(tracers || {})
25
+ end
26
+
27
+ def create_tracer(tracer)
28
+ tracers ||= register_tracers
29
+ if tracer.kind_of?(Symbol) || tracer.kind_of?(String)
30
+ tracer_class = tracers[tracer.to_sym] || tracers[:default]
31
+ tracer_class.new
32
+ elsif tracer.kind_of? Tracing::OutputTemplate::Trace
33
+ tracer
34
+ else
35
+ nil
36
+ end
37
+ end
38
+ end
39
+
40
+ def initialize(init_options = nil)
41
+ return if !init_options
42
+ if init_options.kind_of? Hash
43
+ @options = init_options[:options] || init_options
44
+ register_filters(init_options[:filters])
45
+ tracer = @options[:tracer] if @options
46
+ return if !tracer
47
+
48
+ tracer = self.class.create_tracer(tracer)
49
+ @tracer = tracer
50
+ elsif init_options.kind_of? Symbol
51
+ self.class.register_tracers
52
+ tracer = self.class.tracers[init_options]
53
+ return if !tracer
54
+
55
+ tracer = self.class.create_tracer(tracer)
56
+ @tracer = tracer
57
+ else
58
+ raise Exception, "Appender must be initialized with Hash"
59
+ end
60
+ end
61
+
62
+ # default action handler depending on filters result
63
+ def handle(txt, context)
64
+ if filters_allow?(txt, context)
65
+ allow_append(txt, context)
66
+ else
67
+ not_allow_append(txt, context)
68
+ end
69
+ end
70
+
71
+ def allow_append(txt, context)
72
+
73
+ end
74
+
75
+ def not_allow_append(txt, context)
76
+ end
77
+
78
+ def time_limit
79
+ options[:time_limit] || 1.minute
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,72 @@
1
+ module Tracing
2
+ # File Appender
3
+ class FileAppender < BaseAppender
4
+
5
+ class << self
6
+ def default_path
7
+ return if !@default_path
8
+ if !File.exists?(@default_path)
9
+ FileUtils.mkdir_p @default_path
10
+ end
11
+ @default_path
12
+ end
13
+
14
+ def default_path=(path)
15
+ @default_path = path
16
+ end
17
+ end
18
+
19
+ # file
20
+ def write_file(file, txt)
21
+ file = file_path(file)
22
+
23
+ write_mode = mode(file)
24
+ File.open(file, write_mode) do |f|
25
+ f.puts txt
26
+ end
27
+ end
28
+
29
+ def create_initial_file(file)
30
+ end
31
+
32
+ def insert_into_file(file, txt, marker_txt)
33
+ line = marker_txt
34
+
35
+ file = file_path(file)
36
+
37
+ if !File.exist?(file)
38
+ create_initial_file(file)
39
+ end
40
+
41
+ gsub_file file, /(#{Regexp.escape(line)})/mi do |match|
42
+ "#{txt}\n#{match}"
43
+ end
44
+ end
45
+
46
+ # helper for deciding file "write mode"
47
+ def is_old_file?(file)
48
+ File.new(file).mtime < (Time.now - time_limit)
49
+ end
50
+
51
+ def file_path(file)
52
+ file = File.join(self.class.default_path, file) if self.class.default_path
53
+ end
54
+
55
+ protected
56
+ def gsub_file(path, regexp, *args, &block)
57
+ content = File.read(path).gsub(regexp, *args, &block)
58
+ File.open(path, 'wb') { |file| file.write(content) }
59
+ end
60
+
61
+ # default file "write mode"
62
+ def mode(file)
63
+ if !options[:overwrite] && File.exist?(file) && !is_old_file?(file)
64
+ "a+"
65
+ else
66
+ "w+"
67
+ end
68
+ end
69
+
70
+ end # class
71
+
72
+ end # tracing