trace-util-adv 0.1.1 → 0.2.0

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.
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