request-log-analyzer 1.0.2 → 1.6.3

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 (144) hide show
  1. data/.gitignore +10 -0
  2. data/DESIGN.rdoc +41 -0
  3. data/LICENSE +4 -4
  4. data/README.rdoc +38 -0
  5. data/Rakefile +6 -3
  6. data/bin/request-log-analyzer +70 -72
  7. data/lib/cli/command_line_arguments.rb +53 -53
  8. data/lib/cli/database_console.rb +26 -0
  9. data/lib/cli/database_console_init.rb +43 -0
  10. data/lib/cli/progressbar.rb +166 -189
  11. data/lib/cli/tools.rb +49 -0
  12. data/lib/request_log_analyzer/aggregator/database_inserter.rb +83 -0
  13. data/lib/request_log_analyzer/aggregator/echo.rb +17 -12
  14. data/lib/request_log_analyzer/aggregator/summarizer.rb +101 -63
  15. data/lib/request_log_analyzer/{aggregator/base.rb → aggregator.rb} +17 -13
  16. data/lib/request_log_analyzer/controller.rb +251 -98
  17. data/lib/request_log_analyzer/database/base.rb +114 -0
  18. data/lib/request_log_analyzer/database/connection.rb +38 -0
  19. data/lib/request_log_analyzer/database/request.rb +22 -0
  20. data/lib/request_log_analyzer/database/source.rb +13 -0
  21. data/lib/request_log_analyzer/database/warning.rb +14 -0
  22. data/lib/request_log_analyzer/database.rb +102 -0
  23. data/lib/request_log_analyzer/file_format/amazon_s3.rb +74 -0
  24. data/lib/request_log_analyzer/file_format/apache.rb +147 -0
  25. data/lib/request_log_analyzer/file_format/delayed_job.rb +55 -0
  26. data/lib/request_log_analyzer/file_format/merb.rb +65 -29
  27. data/lib/request_log_analyzer/file_format/mysql.rb +101 -0
  28. data/lib/request_log_analyzer/file_format/postgresql.rb +68 -0
  29. data/lib/request_log_analyzer/file_format/rack.rb +9 -0
  30. data/lib/request_log_analyzer/file_format/rails.rb +164 -78
  31. data/lib/request_log_analyzer/file_format/rails3.rb +86 -0
  32. data/lib/request_log_analyzer/file_format/rails_development.rb +12 -0
  33. data/lib/request_log_analyzer/file_format.rb +252 -58
  34. data/lib/request_log_analyzer/filter/anonymize.rb +39 -0
  35. data/lib/request_log_analyzer/filter/field.rb +19 -13
  36. data/lib/request_log_analyzer/filter/timespan.rb +25 -12
  37. data/lib/request_log_analyzer/filter.rb +30 -0
  38. data/lib/request_log_analyzer/line_definition.rb +69 -96
  39. data/lib/request_log_analyzer/log_processor.rb +31 -53
  40. data/lib/request_log_analyzer/mailer.rb +65 -0
  41. data/lib/request_log_analyzer/output/fancy_html.rb +49 -0
  42. data/lib/request_log_analyzer/output/fixed_width.rb +220 -0
  43. data/lib/request_log_analyzer/output/html.rb +187 -0
  44. data/lib/request_log_analyzer/output.rb +117 -0
  45. data/lib/request_log_analyzer/request.rb +125 -40
  46. data/lib/request_log_analyzer/source/database_loader.rb +87 -0
  47. data/lib/request_log_analyzer/source/log_parser.rb +297 -0
  48. data/lib/request_log_analyzer/source.rb +72 -0
  49. data/lib/request_log_analyzer/tracker/duration.rb +28 -64
  50. data/lib/request_log_analyzer/tracker/frequency.rb +108 -0
  51. data/lib/request_log_analyzer/tracker/hourly_spread.rb +76 -49
  52. data/lib/request_log_analyzer/tracker/numeric_value.rb +223 -0
  53. data/lib/request_log_analyzer/tracker/timespan.rb +54 -27
  54. data/lib/request_log_analyzer/tracker/traffic.rb +40 -0
  55. data/lib/request_log_analyzer/tracker.rb +101 -0
  56. data/lib/request_log_analyzer.rb +43 -13
  57. data/request-log-analyzer.gemspec +41 -0
  58. data/spec/database.yml +23 -0
  59. data/spec/fixtures/apache_combined.log +5 -0
  60. data/spec/fixtures/apache_common.log +10 -0
  61. data/spec/fixtures/decompression.log +12 -0
  62. data/spec/fixtures/decompression.log.bz2 +0 -0
  63. data/spec/fixtures/decompression.log.gz +0 -0
  64. data/spec/fixtures/decompression.log.zip +0 -0
  65. data/spec/fixtures/decompression.tar.gz +0 -0
  66. data/spec/fixtures/decompression.tgz +0 -0
  67. data/spec/fixtures/header_and_footer.log +6 -0
  68. data/spec/fixtures/merb_prefixed.log +9 -0
  69. data/spec/fixtures/mysql_slow_query.log +110 -0
  70. data/spec/fixtures/postgresql.log +2980 -0
  71. data/spec/fixtures/rails.db +0 -0
  72. data/spec/fixtures/rails_22.log +1 -1
  73. data/spec/fixtures/sinatra.log +99 -0
  74. data/spec/integration/command_line_usage_spec.rb +84 -0
  75. data/spec/integration/mailer_spec.rb +179 -0
  76. data/spec/integration/munin_plugins_rails_spec.rb +58 -0
  77. data/spec/integration/scout_spec.rb +152 -0
  78. data/spec/lib/helpers.rb +72 -0
  79. data/spec/lib/macros.rb +18 -0
  80. data/spec/lib/matchers.rb +77 -0
  81. data/spec/lib/mocks.rb +77 -0
  82. data/spec/lib/testing_format.rb +46 -0
  83. data/spec/spec_helper.rb +16 -59
  84. data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
  85. data/spec/unit/aggregator/summarizer_spec.rb +26 -0
  86. data/spec/unit/controller/controller_spec.rb +41 -0
  87. data/spec/unit/controller/log_processor_spec.rb +18 -0
  88. data/spec/unit/database/base_class_spec.rb +183 -0
  89. data/spec/unit/database/connection_spec.rb +34 -0
  90. data/spec/unit/database/database_spec.rb +133 -0
  91. data/spec/unit/file_format/amazon_s3_format_spec.rb +67 -0
  92. data/spec/unit/file_format/apache_format_spec.rb +203 -0
  93. data/spec/unit/file_format/common_regular_expressions_spec.rb +53 -0
  94. data/spec/unit/file_format/delayed_job_format_spec.rb +83 -0
  95. data/spec/unit/file_format/file_format_api_spec.rb +69 -0
  96. data/spec/unit/file_format/format_autodetection_spec.rb +40 -0
  97. data/spec/unit/file_format/line_definition_spec.rb +75 -0
  98. data/spec/unit/file_format/merb_format_spec.rb +52 -0
  99. data/spec/unit/file_format/mysql_format_spec.rb +154 -0
  100. data/spec/unit/file_format/postgresql_format_spec.rb +65 -0
  101. data/spec/unit/file_format/rack_format_spec.rb +50 -0
  102. data/spec/unit/file_format/rails3_format_spec.rb +120 -0
  103. data/spec/unit/file_format/rails_format_spec.rb +180 -0
  104. data/spec/unit/filter/anonymize_filter_spec.rb +21 -0
  105. data/spec/unit/filter/field_filter_spec.rb +66 -0
  106. data/spec/unit/filter/filter_spec.rb +17 -0
  107. data/spec/unit/filter/timespan_filter_spec.rb +58 -0
  108. data/spec/unit/mailer_spec.rb +42 -0
  109. data/spec/unit/request_spec.rb +111 -0
  110. data/spec/unit/source/log_parser_spec.rb +119 -0
  111. data/spec/unit/tracker/duration_tracker_spec.rb +49 -0
  112. data/spec/unit/tracker/frequency_tracker_spec.rb +88 -0
  113. data/spec/unit/tracker/hourly_spread_spec.rb +79 -0
  114. data/spec/unit/tracker/numeric_value_tracker_spec.rb +166 -0
  115. data/spec/unit/tracker/timespan_tracker_spec.rb +73 -0
  116. data/spec/unit/tracker/tracker_api_spec.rb +125 -0
  117. data/spec/unit/tracker/traffic_tracker_spec.rb +28 -0
  118. data/tasks/github-gem.rake +290 -139
  119. data/tasks/request_log_analyzer.rake +23 -7
  120. metadata +221 -94
  121. data/DESIGN +0 -14
  122. data/HACKING +0 -7
  123. data/README.textile +0 -36
  124. data/lib/cli/bashcolorizer.rb +0 -60
  125. data/lib/request_log_analyzer/aggregator/database.rb +0 -148
  126. data/lib/request_log_analyzer/filter/base.rb +0 -29
  127. data/lib/request_log_analyzer/log_parser.rb +0 -173
  128. data/lib/request_log_analyzer/source/base.rb +0 -42
  129. data/lib/request_log_analyzer/source/log_file.rb +0 -170
  130. data/lib/request_log_analyzer/tracker/base.rb +0 -54
  131. data/lib/request_log_analyzer/tracker/category.rb +0 -71
  132. data/spec/controller_spec.rb +0 -40
  133. data/spec/database_inserter_spec.rb +0 -101
  134. data/spec/file_format_spec.rb +0 -78
  135. data/spec/file_formats/spec_format.rb +0 -26
  136. data/spec/filter_spec.rb +0 -137
  137. data/spec/line_definition_spec.rb +0 -124
  138. data/spec/log_parser_spec.rb +0 -68
  139. data/spec/log_processor_spec.rb +0 -57
  140. data/spec/merb_format_spec.rb +0 -38
  141. data/spec/rails_format_spec.rb +0 -76
  142. data/spec/request_spec.rb +0 -72
  143. data/spec/summarizer_spec.rb +0 -9
  144. data/tasks/rspec.rake +0 -6
Binary file
@@ -9,4 +9,4 @@ Rendered shared/_analytics (0.2ms)
9
9
  Rendered layouts/_actions (0.6ms)
10
10
  Rendered layouts/_menu (2.2ms)
11
11
  Rendered layouts/_tabbar (0.5ms)
12
- Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.coml/demo]
12
+ Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.com/demo]
@@ -0,0 +1,99 @@
1
+ == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel
2
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET / HTTP/1.1" 200 5056 0.0241
3
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /javascripts/cufon-yui.js HTTP/1.1" 304 - 0.0016
4
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /javascripts/CartoGothic_Std_400-CartoGothic_Std_700-CartoGothic_Std_italic_400-CartoGothic_Std_italic_700.font.js HTTP/1.1" 304 - 0.0013
5
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /css/stylesheet.css HTTP/1.1" 304 - 0.0014
6
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/rails_doctors_logo.png HTTP/1.1" 304 - 0.0039
7
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/footer-bg.png HTTP/1.1" 304 - 0.0028
8
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/nav-bg.png HTTP/1.1" 304 - 0.0023
9
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/radial-bg.png HTTP/1.1" 304 - 0.0019
10
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/box-bg.png HTTP/1.1" 304 - 0.0015
11
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/performance_train.png HTTP/1.1" 304 - 0.0011
12
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/lock.png HTTP/1.1" 304 - 0.0025
13
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/contact.png HTTP/1.1" 304 - 0.0015
14
+ 127.0.0.1 - - [23/Nov/2009 22:46:22] "GET /images/rla.png HTTP/1.1" 304 - 0.0008
15
+ 127.0.0.1 - - [23/Nov/2009 22:46:24] "GET /index.html HTTP/1.1" 200 5056 0.0216
16
+ 127.0.0.1 - - [23/Nov/2009 22:46:25] "GET /blog.html HTTP/1.1" 200 8156 0.0115
17
+ 127.0.0.1 - - [23/Nov/2009 22:46:26] "GET /performance.html HTTP/1.1" 200 4751 0.0134
18
+ 127.0.0.1 - - [23/Nov/2009 22:46:26] "GET /blog.html HTTP/1.1" 200 8156 0.0504
19
+ 127.0.0.1 - - [23/Nov/2009 22:46:27] "GET /security.html HTTP/1.1" 200 4503 0.0119
20
+ 127.0.0.1 - - [23/Nov/2009 22:46:27] "GET /performance.html HTTP/1.1" 200 4751 0.0206
21
+ 127.0.0.1 - - [23/Nov/2009 22:46:29] "GET /request_log_analyzer.html HTTP/1.1" 200 5669 0.0129
22
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /request_log_analyzer.html HTTP/1.1" 200 5669 0.0156
23
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /javascripts/cufon-yui.js HTTP/1.1" 304 - 0.0033
24
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /javascripts/CartoGothic_Std_400-CartoGothic_Std_700-CartoGothic_Std_italic_400-CartoGothic_Std_italic_700.font.js HTTP/1.1" 304 - 0.0035
25
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /css/stylesheet.css HTTP/1.1" 304 - 0.0031
26
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/performance_train.png HTTP/1.1" 304 - 0.0026
27
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/footer-bg.png HTTP/1.1" 304 - 0.0029
28
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/nav-bg.png HTTP/1.1" 304 - 0.0048
29
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/box-bg.png HTTP/1.1" 304 - 0.0055
30
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/rails_doctors_logo.png HTTP/1.1" 304 - 0.0049
31
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/radial-bg.png HTTP/1.1" 304 - 0.0029
32
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/lock.png HTTP/1.1" 304 - 0.0022
33
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/rla.png HTTP/1.1" 304 - 0.0014
34
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /images/contact.png HTTP/1.1" 304 - 0.0008
35
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /favicon.ico HTTP/1.1" 404 420 0.0007
36
+ 127.0.0.1 - - [23/Nov/2009 22:46:30] "GET /contact.html HTTP/1.1" 200 4476 0.0149
37
+ 127.0.0.1 - - [23/Nov/2009 22:46:31] "GET /contact.html HTTP/1.1" 200 4476 0.0118
38
+ 127.0.0.1 - - [23/Nov/2009 22:46:31] "GET /contact.html HTTP/1.1" 200 4476 0.0556
39
+ 127.0.0.1 - - [23/Nov/2009 22:46:32] "GET /security.html HTTP/1.1" 200 4503 0.0980
40
+ 127.0.0.1 - - [23/Nov/2009 22:46:32] "GET /performance.html HTTP/1.1" 200 4751 0.0109
41
+ 127.0.0.1 - - [23/Nov/2009 22:46:33] "GET /index.html HTTP/1.1" 200 5056 0.0169
42
+ 127.0.0.1 - - [23/Nov/2009 22:46:33] "GET /blog.html HTTP/1.1" 200 8156 0.0112
43
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /blog.html HTTP/1.1" 200 8156 0.0113
44
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /css/stylesheet.css HTTP/1.1" 304 - 0.0017
45
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /javascripts/cufon-yui.js HTTP/1.1" 304 - 0.0011
46
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /javascripts/CartoGothic_Std_400-CartoGothic_Std_700-CartoGothic_Std_italic_400-CartoGothic_Std_italic_700.font.js HTTP/1.1" 304 - 0.0007
47
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/rails_doctors_logo.png HTTP/1.1" 304 - 0.0045
48
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/performance_train.png HTTP/1.1" 304 - 0.0038
49
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/footer-bg.png HTTP/1.1" 304 - 0.0044
50
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/nav-bg.png HTTP/1.1" 304 - 0.0042
51
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/radial-bg.png HTTP/1.1" 304 - 0.0037
52
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/box-bg.png HTTP/1.1" 304 - 0.0045
53
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/rla.png HTTP/1.1" 304 - 0.0026
54
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/lock.png HTTP/1.1" 304 - 0.0022
55
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /images/contact.png HTTP/1.1" 304 - 0.0024
56
+ 127.0.0.1 - - [23/Nov/2009 22:46:34] "GET /favicon.ico HTTP/1.1" 404 420 0.0007
57
+ 127.0.0.1 - - [23/Nov/2009 22:46:36] "GET /blog.html HTTP/1.1" 200 8156 0.0119
58
+ 127.0.0.1 - - [23/Nov/2009 22:46:36] "GET /css/stylesheet.css HTTP/1.1" 200 3782 0.0030
59
+ 127.0.0.1 - - [23/Nov/2009 22:46:36] "GET /javascripts/cufon-yui.js HTTP/1.1" 200 16944 0.0220
60
+ 127.0.0.1 - - [23/Nov/2009 22:46:36] "GET /javascripts/CartoGothic_Std_400-CartoGothic_Std_700-CartoGothic_Std_italic_400-CartoGothic_Std_italic_700.font.js HTTP/1.1" 200 76594 0.0258
61
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/box-bg.png HTTP/1.1" 200 129 0.0058
62
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/footer-bg.png HTTP/1.1" 200 267 0.0056
63
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/nav-bg.png HTTP/1.1" 200 221 0.0052
64
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/performance_train.png HTTP/1.1" 200 7496 0.0103
65
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/radial-bg.png HTTP/1.1" 200 9288 0.0079
66
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/rails_doctors_logo.png HTTP/1.1" 200 11487 0.0106
67
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/rla.png HTTP/1.1" 200 23857 0.0233
68
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/contact.png HTTP/1.1" 200 23961 0.0228
69
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /images/lock.png HTTP/1.1" 200 31780 0.0494
70
+ 127.0.0.1 - - [23/Nov/2009 22:46:37] "GET /favicon.ico HTTP/1.1" 404 420 0.0007
71
+ 127.0.0.1 - - [23/Nov/2009 22:46:38] "GET /blog.html HTTP/1.1" 200 8156 0.0108
72
+ 127.0.0.1 - - [23/Nov/2009 22:46:38] "GET /javascripts/CartoGothic_Std_400-CartoGothic_Std_700-CartoGothic_Std_italic_400-CartoGothic_Std_italic_700.font.js HTTP/1.1" 304 - 0.0017
73
+ 127.0.0.1 - - [23/Nov/2009 22:46:38] "GET /javascripts/cufon-yui.js HTTP/1.1" 304 - 0.0013
74
+ 127.0.0.1 - - [23/Nov/2009 22:46:38] "GET /css/stylesheet.css HTTP/1.1" 304 - 0.0024
75
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/rails_doctors_logo.png HTTP/1.1" 304 - 0.0073
76
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/performance_train.png HTTP/1.1" 304 - 0.0039
77
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/footer-bg.png HTTP/1.1" 304 - 0.0035
78
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/radial-bg.png HTTP/1.1" 304 - 0.0054
79
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/nav-bg.png HTTP/1.1" 304 - 0.0043
80
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/box-bg.png HTTP/1.1" 304 - 0.0038
81
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/rla.png HTTP/1.1" 304 - 0.0019
82
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/lock.png HTTP/1.1" 304 - 0.0014
83
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /images/contact.png HTTP/1.1" 304 - 0.0012
84
+ 127.0.0.1 - - [23/Nov/2009 22:46:39] "GET /favicon.ico HTTP/1.1" 404 420 0.0007
85
+ 127.0.0.1 - - [23/Nov/2009 22:46:40] "GET /performance.html HTTP/1.1" 200 4751 0.0110
86
+ 127.0.0.1 - - [23/Nov/2009 22:46:40] "GET /performance.html HTTP/1.1" 200 4751 0.0110
87
+ 127.0.0.1 - - [23/Nov/2009 22:46:41] "GET /security.html HTTP/1.1" 200 4503 0.0369
88
+ 127.0.0.1 - - [23/Nov/2009 22:46:41] "GET /performance.html HTTP/1.1" 200 4751 0.0118
89
+ 127.0.0.1 - - [23/Nov/2009 22:46:41] "GET /security.html HTTP/1.1" 200 4503 0.0573
90
+ 127.0.0.1 - - [23/Nov/2009 22:46:42] "GET /security.html HTTP/1.1" 200 4503 0.0426
91
+ 127.0.0.1 - - [23/Nov/2009 22:46:42] "GET /performance.html HTTP/1.1" 200 4751 0.0111
92
+ 127.0.0.1 - - [23/Nov/2009 22:46:43] "GET /security.html HTTP/1.1" 200 4503 0.0108
93
+ 127.0.0.1 - - [23/Nov/2009 22:46:43] "GET /performance.html HTTP/1.1" 200 4751 0.0105
94
+ 127.0.0.1 - - [23/Nov/2009 22:46:43] "GET /security.html HTTP/1.1" 200 4503 0.0147
95
+ 127.0.0.1 - - [23/Nov/2009 22:46:43] "GET /contact.html HTTP/1.1" 200 4476 0.0105
96
+ 127.0.0.1 - - [23/Nov/2009 22:46:44] "GET /contact.html HTTP/1.1" 200 4476 0.0110
97
+ 127.0.0.1 - - [23/Nov/2009 22:46:44] "GET /contact.html HTTP/1.1" 200 4476 0.0109
98
+ ^C
99
+ == Sinatra has ended his set (crowd applauds)
@@ -0,0 +1,84 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RequestLogAnalyzer, 'running from command line' do
4
+
5
+ before(:each) do
6
+ cleanup_temp_files!
7
+ end
8
+
9
+ after(:each) do
10
+ cleanup_temp_files!
11
+ end
12
+
13
+ it "should find 4 requests in default mode" do
14
+ output = run("#{log_fixture(:rails_1x)}")
15
+ output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should be_true
16
+ end
17
+
18
+ it "should find 2 requests when parsing a compressed file" do
19
+ output = run("#{log_fixture(:decompression, :tgz)}")
20
+ output.any? { |line| /^Parsed requests\:\s*2\s/ =~ line }.should be_true
21
+ end
22
+
23
+
24
+ it "should skip 1 requests with a --select option" do
25
+ output = run("#{log_fixture(:rails_1x)} --select controller PeopleController")
26
+ output.any? { |line| /^Skipped requests\:\s*1\s/ =~ line }.should be_true
27
+ end
28
+
29
+ it "should skip 3 requests with a --reject option" do
30
+ output = run("#{log_fixture(:rails_1x)} --reject controller PeopleController")
31
+ output.any? { |line| /^Skipped requests\:\s*3\s/ =~ line }.should be_true
32
+ end
33
+
34
+ it "should write output to a file with the --file option" do
35
+ run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
36
+ File.exist?(temp_output_file(:report)).should be_true
37
+ end
38
+
39
+ it "should write only ASCII characters to a file with the --file option" do
40
+ run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
41
+ /^[\x00-\x7F]*$/.match(File.read(temp_output_file(:report))).should_not be_nil
42
+ end
43
+
44
+ it "should write HTML if --output HTML is provided" do
45
+ output = run("#{log_fixture(:rails_1x)} --output HTML")
46
+ output.any? { |line| /<html[^>]*>/ =~ line}.should be_true
47
+ end
48
+
49
+ it "should run with the --database option" do
50
+ run("#{log_fixture(:rails_1x)} --database #{temp_output_file(:database)}")
51
+ File.exist?(temp_output_file(:database)).should be_true
52
+ end
53
+
54
+ it "should use no colors in the report with the --boring option" do
55
+ output = run("#{log_fixture(:rails_1x)} --boring")
56
+ output.any? { |line| /\e/ =~ line }.should be_false
57
+ end
58
+
59
+ it "should use only ASCII characters in the report with the --boring option" do
60
+ output = run("#{log_fixture(:rails_1x)} --boring")
61
+ output.all? { |line| /^[\x00-\x7F]*$/ =~ line }.should be_true
62
+ end
63
+
64
+ it "should parse a Merb file if --format merb is set" do
65
+ output = run("#{log_fixture(:merb)} --format merb")
66
+ output.any? { |line| /Parsed requests\:\s*11/ =~ line }.should be_true
67
+ end
68
+
69
+ it "should parse a Apache access log file if --apache-format is set" do
70
+ output = run("#{log_fixture(:apache_combined)} --apache-format combined")
71
+ output.any? { |line| /Parsed requests\:\s*5/ =~ line }.should be_true
72
+ end
73
+
74
+ it "should dump the results to a YAML file" do
75
+ run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
76
+ File.exist?(temp_output_file(:yaml)).should be_true
77
+ YAML::load(File.read(temp_output_file(:yaml))).should have_at_least(1).item
78
+ end
79
+
80
+ it "should parse 4 requests from the standard input" do
81
+ output = run("- < #{log_fixture(:rails_1x)}")
82
+ output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should be_true
83
+ end
84
+ end
@@ -0,0 +1,179 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'socket'
3
+
4
+ describe RequestLogAnalyzer, 'running mailer integration' do
5
+
6
+ before(:each) do
7
+ @log_file = temp_output_file('mailtrap.log')
8
+
9
+ Process.fork {
10
+ Mailtrap.new('localhost', 2525, true, @log_file)
11
+ Process.exit! # Do not call rspec after exit hook!
12
+ }
13
+ end
14
+
15
+ after(:each) do
16
+ cleanup_temp_files!
17
+ end
18
+
19
+ it "should send plaintext mail" do
20
+ RequestLogAnalyzer::Controller.build(
21
+ :mail => 'root@localhost',
22
+ :mailhost => 'localhost:2525',
23
+ :source_files => log_fixture(:rails_1x),
24
+ :format => RequestLogAnalyzer::FileFormat::Rails,
25
+ :no_progress => true
26
+ ).run!
27
+
28
+ Process.wait # Wait for mailer to complete
29
+
30
+ find_string_in_file("From: <contact@railsdoctors.com>", @log_file).should_not be_nil
31
+ find_string_in_file("To: <root@localhost>", @log_file).should_not be_nil
32
+ find_string_in_file("From: Request-log-analyzer reporter <contact@railsdoctors.com>", @log_file).should_not be_nil
33
+ find_string_in_file("Request summary", @log_file).should_not be_nil
34
+ find_string_in_file("PeopleController#show.html [ | 1 | 0.29s | 0.29s | 0.00s | 0.29s | 0.29s", @log_file).should_not be_nil
35
+ end
36
+
37
+ it "should send html mail" do
38
+ RequestLogAnalyzer::Controller.build(
39
+ :output => 'HTML',
40
+ :mail => 'root@localhost',
41
+ :mailhost => 'localhost:2525',
42
+ :source_files => log_fixture(:rails_1x),
43
+ :format => RequestLogAnalyzer::FileFormat::Rails,
44
+ :no_progress => true
45
+ ).run!
46
+
47
+ Process.wait # Wait for mailer to complete
48
+
49
+ find_string_in_file("From: <contact@railsdoctors.com>", @log_file).should_not be_nil
50
+ find_string_in_file("To: <root@localhost>", @log_file).should_not be_nil
51
+ find_string_in_file("From: Request-log-analyzer reporter <contact@railsdoctors.com>", @log_file).should_not be_nil
52
+ find_string_in_file('<h1>Request-log-analyzer summary report</h1>', @log_file).should_not be_nil
53
+ find_string_in_file('<td class="alt">0.29s</td></tr><tr><td>DashboardController#index.html [GET]</td>', @log_file).should_not be_nil
54
+ end
55
+ end
56
+
57
+
58
+
59
+ # Mailtrap
60
+ # by Matt Mower <self@mattmower.com>
61
+ # http://matt.blogs.it/
62
+ #
63
+ # Included in RLA because original mailtrap puts anoying stuff when called
64
+ # through ruby.
65
+ #
66
+ # Mailtrap creates a TCP server that listens on a specified port for SMTP
67
+ # clients. Accepts the connection and talks just enough of the SMTP protocol
68
+ # for them to deliver a message which it writes to disk.
69
+ #
70
+ class Mailtrap
71
+ VERSION = '0.2.1'
72
+
73
+ # Create a new Mailtrap on the specified host:port. If once it true it
74
+ # will listen for one message then exit. Specify the msgdir where messages
75
+ # are written.
76
+ def initialize( host, port, once, msgfile )
77
+ @host = host
78
+ @port = port
79
+ @once = once
80
+ @msgfile = msgfile
81
+
82
+ File.open( @msgfile, "a" ) do |file|
83
+ file.puts "\n* Mailtrap started at #{@host}:#{port}\n"
84
+ end
85
+
86
+ service = TCPServer.new( @host, @port )
87
+ accept( service )
88
+ end
89
+
90
+ # Service one or more SMTP client connections
91
+ def accept( service )
92
+ while session = service.accept
93
+
94
+ class << session
95
+ def get_line
96
+ line = gets
97
+ line.chomp! unless line.nil?
98
+ line
99
+ end
100
+ end
101
+
102
+ begin
103
+ serve( session )
104
+ rescue Exception => e
105
+ end
106
+
107
+ break if @once
108
+ end
109
+ end
110
+
111
+ # Write a plain text dump of the incoming email to a text
112
+ # file. The file will be in the @msgdir folder and will
113
+ # be called smtp0001.msg, smtp0002.msg, and so on.
114
+ def write( from, to_list, message )
115
+
116
+ # Strip SMTP commands from To: and From:
117
+ from.gsub!( /MAIL FROM:\s*/, "" )
118
+ to_list = to_list.map { |to| to.gsub( /RCPT TO:\s*/, "" ) }
119
+
120
+ # Append to the end of the messages file
121
+ File.open( @msgfile, "a" ) do |file|
122
+ file.puts "* Message begins"
123
+ file.puts "From: #{from}"
124
+ file.puts "To: #{to_list.join(", ")}"
125
+ file.puts "Body:"
126
+ file.puts message
127
+ file.puts "\n* Message ends"
128
+ end
129
+
130
+ end
131
+
132
+ # Talk pidgeon-SMTP to the client to get them to hand over the message
133
+ # and go away.
134
+ def serve( connection )
135
+ connection.puts( "220 #{@host} MailTrap ready ESTMP" )
136
+ helo = connection.get_line # whoever they are
137
+
138
+ if helo =~ /^EHLO\s+/
139
+ connection.puts "250-#{@host} offers just ONE extension my pretty"
140
+ connection.puts "250 HELP"
141
+ end
142
+
143
+ # Accept MAIL FROM:
144
+ from = connection.get_line
145
+ connection.puts( "250 OK" )
146
+
147
+ to_list = []
148
+
149
+ # Accept RCPT TO: until we see DATA
150
+ loop do
151
+ to = connection.get_line
152
+ break if to.nil?
153
+
154
+ if to =~ /^DATA/
155
+ connection.puts( "354 Start your message" )
156
+ break
157
+ else
158
+ to_list << to
159
+ connection.puts( "250 OK" )
160
+ end
161
+ end
162
+
163
+ # Capture the message body terminated by <CR>.<CR>
164
+ lines = []
165
+ loop do
166
+ line = connection.get_line
167
+ break if line.nil? || line == "."
168
+ lines << line
169
+ end
170
+
171
+ # We expect the client will go away now
172
+ connection.puts( "250 OK" )
173
+ connection.gets # Quit
174
+ connection.puts "221 Seeya"
175
+ connection.close
176
+
177
+ write( from, to_list, lines.join( "\n" ) )
178
+ end
179
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RequestLogAnalyzer, 'when harvesting like munin-plugins-rails the YAML output' do
4
+
5
+ before(:each) do
6
+ cleanup_temp_files!
7
+ run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
8
+ @rla = YAML::load(File.read(temp_output_file(:yaml)))
9
+ end
10
+
11
+ after(:each) do
12
+ cleanup_temp_files!
13
+ end
14
+
15
+ it "should contain database times" do
16
+ @rla["Database time"].each do |item|
17
+ item[1][:min].should_not be_nil
18
+ item[1][:max].should_not be_nil
19
+ item[1][:hits].should_not be_nil
20
+ item[1][:sum].should_not be_nil
21
+ end
22
+ end
23
+
24
+ it "should contain request times" do
25
+ @rla["Request duration"].each do |item|
26
+ item[1][:min].should_not be_nil
27
+ item[1][:max].should_not be_nil
28
+ item[1][:hits].should_not be_nil
29
+ item[1][:sum].should_not be_nil
30
+ end
31
+ end
32
+
33
+ it "should contain failed requests" do
34
+ @rla.keys.should include("Failed requests")
35
+ end
36
+
37
+ it "should contain Process blockers" do
38
+ @rla.keys.should include("Process blockers (> 1 sec duration)")
39
+ end
40
+
41
+ it "should contain HTTP Methods" do
42
+ @rla["HTTP methods"]["GET"].should_not be_nil
43
+ end
44
+
45
+ it "should contain HTTP Methods" do
46
+ @rla["HTTP methods"]["GET"].should_not be_nil
47
+ end
48
+
49
+ it "should contain view rendering times" do
50
+ @rla["View rendering time"].each do |item|
51
+ item[1][:min].should_not be_nil
52
+ item[1][:max].should_not be_nil
53
+ item[1][:hits].should_not be_nil
54
+ item[1][:sum].should_not be_nil
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,152 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ def capture_stdout_and_stderr_with_warnings_on
4
+ $stdout, $stderr, warnings, $VERBOSE =
5
+ StringIO.new, StringIO.new, $VERBOSE, true
6
+ yield
7
+ return $stdout.string, $stderr.string
8
+ ensure
9
+ $stdout, $stderr, $VERBOSE = STDOUT, STDERR, warnings
10
+ end
11
+
12
+ describe RequestLogAnalyzer, 'when using the rla API like the scout plugin' do
13
+
14
+ before(:each) do
15
+ # prepare a place to capture the output
16
+ sio = StringIO.new
17
+
18
+ # place an IO object where I want RequestLogAnalyzer to read from
19
+ open(log_fixture(:rails_1x)) do |log|
20
+ completed_count = 0
21
+ log.each do |line|
22
+ completed_count += 1 if line =~ /\ACompleted\b/
23
+ break if completed_count == 2 # skipping first two requests
24
+ end
25
+
26
+ # trigger the log parse
27
+ @stdout, @stderr = capture_stdout_and_stderr_with_warnings_on do
28
+ RequestLogAnalyzer::Controller.build(
29
+ :output => EmbeddedHTML,
30
+ :file => sio,
31
+ :after => Time.local(2008, 8, 14, 21, 16, 31), # after 3rd req
32
+ :source_files => log,
33
+ :format => RequestLogAnalyzer::FileFormat::Rails
34
+ ).run!
35
+ end
36
+ end
37
+
38
+ # read the resulting output
39
+ @analysis = sio.string
40
+ end
41
+
42
+ it "should generate an analysis" do
43
+ @analysis.should_not be_empty
44
+ end
45
+
46
+ it "should generate customized output using the passed Class" do
47
+ credit = %r{<p>Powered by request-log-analyzer v\d+(?:\.\d+)+</p>\z}
48
+ @analysis.should match(credit)
49
+ end
50
+
51
+ it "should skip requests before :after Time" do
52
+ @analysis.should_not include("PeopleController#show")
53
+ end
54
+
55
+ it "should include requests after IO#pos and :after Time" do
56
+ @analysis.should include("PeopleController#picture")
57
+ end
58
+
59
+ it "should skip requests before IO#pos" do
60
+ @analysis.should_not include("PeopleController#index")
61
+ end
62
+
63
+ it "should not print to $stdout" do
64
+ @stdout.should be_empty
65
+ end
66
+
67
+ it "should not print to $stderr (with warnings on)" do
68
+ @stderr.should be_empty
69
+ end
70
+
71
+ end
72
+
73
+ # Helpers
74
+ class EmbeddedHTML < RequestLogAnalyzer::Output::Base
75
+ def print(str)
76
+ @io << str
77
+ end
78
+ alias_method :<<, :print
79
+
80
+ def puts(str = "")
81
+ @io << "#{str}<br/>\n"
82
+ end
83
+
84
+ def title(title)
85
+ @io.puts(tag(:h2, title))
86
+ end
87
+
88
+ def line(*font)
89
+ @io.puts(tag(:hr))
90
+ end
91
+
92
+ def link(text, url = nil)
93
+ url = text if url.nil?
94
+ tag(:a, text, :href => url)
95
+ end
96
+
97
+ def table(*columns, &block)
98
+ rows = Array.new
99
+ yield(rows)
100
+
101
+ @io << tag(:table, :cellspacing => 0) do |content|
102
+ if table_has_header?(columns)
103
+ content << tag(:tr) do
104
+ columns.map { |col| tag(:th, col[:title]) }.join("\n")
105
+ end
106
+ end
107
+
108
+ odd = false
109
+ rows.each do |row|
110
+ odd = !odd
111
+ content << tag(:tr) do
112
+ if odd
113
+ row.map { |cell| tag(:td, cell, :class => "alt") }.join("\n")
114
+ else
115
+ row.map { |cell| tag(:td, cell) }.join("\n")
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ def header
123
+ end
124
+
125
+ def footer
126
+ @io << tag(:hr) << tag(:p, "Powered by request-log-analyzer v#{RequestLogAnalyzer::VERSION}")
127
+ end
128
+
129
+ private
130
+
131
+ def tag(tag, content = nil, attributes = nil)
132
+ if block_given?
133
+ attributes = content.nil? ? "" : " " + content.map { |(key, value)| "#{key}=\"#{value}\"" }.join(" ")
134
+ content_string = ""
135
+ content = yield(content_string)
136
+ content = content_string unless content_string.empty?
137
+ "<#{tag}#{attributes}>#{content}</#{tag}>"
138
+ else
139
+ attributes = attributes.nil? ? "" : " " + attributes.map { |(key, value)| "#{key}=\"#{value}\"" }.join(" ")
140
+ if content.nil?
141
+ "<#{tag}#{attributes} />"
142
+ else
143
+ if content.class == Float
144
+ "<#{tag}#{attributes}><div class='color_bar' style=\"width:#{(content*200).floor}px;\"/></#{tag}>"
145
+ else
146
+ "<#{tag}#{attributes}>#{content}</#{tag}>"
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+
@@ -0,0 +1,72 @@
1
+ module RequestLogAnalyzer::Spec::Helpers
2
+
3
+ # Create or return a new TestingFormat
4
+ def testing_format
5
+ @testing_format ||= TestingFormat.create
6
+ end
7
+
8
+ # Load a log file from the fixture folder
9
+ def log_fixture(name, extention = "log")
10
+ File.dirname(__FILE__) + "/../fixtures/#{name}.#{extention}"
11
+ end
12
+
13
+ # Creates a log file given some lines
14
+ def log_stream(*lines)
15
+ StringIO.new(lines.join("\n") + "\n")
16
+ end
17
+
18
+ # Request loopback
19
+ def request(fields, format = testing_format)
20
+ if fields.kind_of?(Array)
21
+ format.request(*fields)
22
+ else
23
+ format.request(fields)
24
+ end
25
+ end
26
+
27
+ # Run a specific command
28
+ # Used to call request-log-analyzer through binary
29
+ def run(arguments)
30
+ binary = "#{File.dirname(__FILE__)}/../../bin/request-log-analyzer"
31
+ arguments = arguments.join(' ') if arguments.kind_of?(Array)
32
+
33
+ output = []
34
+ IO.popen("#{binary} #{arguments}") do |pipe|
35
+ output = pipe.readlines
36
+ end
37
+ $?.exitstatus.should == 0
38
+ output
39
+ end
40
+
41
+ # Cleanup all temporary files generated by specs
42
+ def cleanup_temp_files!
43
+ Dir["#{File.dirname(__FILE__)}/../../tmp/spec.*tmp"].each do |file|
44
+ File.unlink(file)
45
+ end
46
+ end
47
+
48
+ # Return a filename that can be used as temporary file in specs
49
+ def temp_output_file(file_type)
50
+ File.expand_path("#{File.dirname(__FILE__)}/../../tmp/spec.#{file_type}.tmp")
51
+ end
52
+
53
+ # Check if a given string can be found in the given file
54
+ # Returns the line number if found, nil otherwise
55
+ def find_string_in_file(string, file, options = {})
56
+ return nil unless File::exists?(file)
57
+
58
+ line_counter = 0
59
+
60
+ File.open( file ) do |io|
61
+ io.each {|line|
62
+ line_counter += 1
63
+ line.chomp!
64
+
65
+ p line if options[:debug]
66
+ return line_counter if line.include? string
67
+ }
68
+ end
69
+
70
+ return nil
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ module RequestLogAnalyzer::Spec::Macros
2
+
3
+ def test_databases
4
+ require 'yaml'
5
+ hash = YAML.load(File.read("#{File.dirname(__FILE__)}/../database.yml"))
6
+ hash.inject({}) { |res, (name, h)| res[name] = h.map { |(k,v)| "#{k}=#{v}" }.join(';'); res }
7
+ end
8
+
9
+ # Create or return a new TestingFormat
10
+ def testing_format
11
+ @testing_format ||= TestingFormat.create
12
+ end
13
+
14
+ def default_orm_class_names
15
+ ['Warning', 'Request', 'Source']
16
+ end
17
+
18
+ end