arproxy-plugin-mysql_casual_log 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ce505a834c6485baec733aa14d3e3a79c1b452ec
4
+ data.tar.gz: 12a3ddb2958602d8bee4c7f027ecd53b0df2fa69
5
+ SHA512:
6
+ metadata.gz: 084e9db772cb7a63b5f46821569346f50e8f7ab88caafe1e98ae1a27138b37a0ef8450e600630b460084f81c872c5a4b2da41251ec1d726e050340d0e525a87f
7
+ data.tar.gz: 23d5095d4a2eb537558ee706a8055e11d6682412e7c12aa9e38519dbd8cd20b1fd91d4604add1f9d359f716b4c8002df078a8a6cf254000a23f0c50770a584bf
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --require spec_helper
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.5
5
+ - 2.2.1
6
+ script:
7
+ - bundle install
8
+ - bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in arproxy-plugin-casual_log.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # Arproxy::Plugin::MysqlCasualLog
2
+
3
+ Plug-in that colorize MySQL bad query for [Arproxy](https://github.com/cookpad/arproxy).
4
+ It is porting of [MySQLCasualLog.pm](https://gist.github.com/kamipo/839e8a5b6d12bddba539).
5
+
6
+ see http://kamipo.github.io/talks/20140711-mysqlcasual6
7
+
8
+ [![Gem Version](https://badge.fury.io/rb/arproxy-plugin-mysql_casual_log.svg)](http://badge.fury.io/rb/arproxy-plugin-mysql_casual_log)
9
+ [![Build Status](https://travis-ci.org/winebarrel/arproxy-plugin-mysql_casual_log.svg?branch=master)](https://travis-ci.org/winebarrel/arproxy-plugin-mysql_casual_log)
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'arproxy-plugin-mysql_casual_log'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install arproxy-plugin-mysql_casual_log
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ Arproxy.configure do |config|
31
+ config.adapter = "mysql2"
32
+ config.plugin :mysql_casual_log
33
+ end
34
+ ```
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new("spec")
5
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ Gem::Specification.new do |spec|
3
+ spec.name = "arproxy-plugin-mysql_casual_log"
4
+ spec.version = "0.1.0"
5
+ spec.authors = ["Genki Sugawara"]
6
+ spec.email = ["sugawara@cookpad.com"]
7
+ spec.summary = %q{Plug-in that colorize MySQL bad query for Arproxy.}
8
+ spec.description = %q{Plug-in that colorize MySQL bad query for Arproxy.}
9
+ spec.homepage = "https://github.com/winebarrel/arproxy-plugin-mysql_casual_log"
10
+ spec.license = "MIT"
11
+
12
+ spec.files = `git ls-files -z`.split("\x0")
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_dependency "arproxy", "~> 0.2.0"
18
+ spec.add_dependency "mysql2"
19
+ spec.add_dependency "term-ansicolor"
20
+ spec.add_development_dependency "bundler"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "timecop"
24
+ end
@@ -0,0 +1,115 @@
1
+ require "arproxy"
2
+ require "mysql2"
3
+ require "term/ansicolor"
4
+
5
+ module Arproxy::Plugin
6
+ class MysqlCasualLog < Arproxy::Base
7
+ Arproxy::Plugin.register(:mysql_casual_log, self)
8
+
9
+ REGEXPS = {
10
+ 'select_type' => Regexp.union(
11
+ /DEPENDENT\sUNION/,
12
+ /DEPENDENT\sSUBQUERY/,
13
+ /UNCACHEABLE\sUNION/,
14
+ /UNCACHEABLE\sSUBQUERY/
15
+ ),
16
+ 'type' => Regexp.union(
17
+ /index/,
18
+ /ALL/
19
+ ),
20
+ 'possible_keys' => Regexp.union(
21
+ /NULL/
22
+ ),
23
+ 'key' => Regexp.union(
24
+ /NULL/
25
+ ),
26
+ 'Extra' => Regexp.union(
27
+ /Using\sfilesort/,
28
+ /Using\stemporary/
29
+ )
30
+ }
31
+
32
+ def initialize(*args)
33
+ @options = args.first || {}
34
+ @out = @options[:out] || $stdout
35
+ @raw_connection = @options[:raw_connection] || proc {|conn, sql| conn.raw_connection }
36
+ end
37
+
38
+ def execute(sql, name=nil)
39
+ if sql =~ /\ASELECT\b/i
40
+ proxy(sql)
41
+ end
42
+
43
+ super(sql, name)
44
+ end
45
+
46
+ private
47
+
48
+ def proxy(sql)
49
+ if @raw_connection.respond_to?(:call)
50
+ conn = @raw_connection.call(proxy_chain.connection, sql)
51
+ else
52
+ conn = @raw_connection
53
+ end
54
+
55
+ if conn
56
+ explain(conn, sql)
57
+ end
58
+ end
59
+
60
+ def explain(conn, sql)
61
+ badquery = false
62
+ explains = []
63
+
64
+ conn.query("EXPLAIN #{sql}", :as => :hash).each_with_index do |result, i|
65
+ colorize_explain(result).tap {|bq| badquery ||= bq }
66
+ explains << format_explain(result, i + 1)
67
+ end
68
+
69
+ if badquery
70
+ query_options = conn.query_options.dup
71
+ query_options.delete(:password)
72
+
73
+ @out << <<-EOS
74
+ # Time: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}
75
+ # Query options: #{query_options.inspect}
76
+ # Query: #{sql}
77
+ #{explains.join("\n")}
78
+ EOS
79
+ end
80
+ rescue => e
81
+ $stderr.puts colored([e.message, e.backtrace.first].join("\n"))
82
+ end
83
+
84
+ def colorize_explain(explain_result)
85
+ badquery = false
86
+
87
+ REGEXPS.each do |key, regexp|
88
+ value = explain_result[key] ||= 'NULL'
89
+ value = value.to_s
90
+
91
+ value.gsub!(regexp) do |m|
92
+ badquery = true
93
+ colored(m)
94
+ end
95
+ end
96
+
97
+ badquery
98
+ end
99
+
100
+ def colored(str)
101
+ Term::ANSIColor.red(Term::ANSIColor.bold(str))
102
+ end
103
+
104
+ def format_explain(explain, i)
105
+ message = "*************************** #{i}. row ***************************\n"
106
+ max_key_length = explain.keys.map(&:length).max
107
+
108
+ explain.each do |key, value|
109
+ message << "%*s: %s\n" % [max_key_length, key, value]
110
+ end
111
+
112
+ message.chomp
113
+ end
114
+ end # CasualLog
115
+ end # Arproxy::Plugin
@@ -0,0 +1,68 @@
1
+ describe Arproxy::Plugin::MysqlCasualLog do
2
+ before do
3
+ allow_any_instance_of(Arproxy::Base).to receive(:execute)
4
+ end
5
+
6
+ let(:today) { Time.parse("2015-05-15 20:15:55 +0000") }
7
+ let(:out) { StringIO.new }
8
+
9
+ let(:raw_connection) do
10
+ Mysql2::Client.new(host: "localhost", username: "root", database: "mysql")
11
+ end
12
+
13
+ let(:plugin) do
14
+ Arproxy::Plugin::MysqlCasualLog.new(out: out, raw_connection: raw_connection)
15
+ end
16
+
17
+ describe "#initialize" do
18
+ describe "@out" do
19
+ subject { plugin.instance_variable_get(:@out) }
20
+ it { is_expected.to eq out }
21
+ end
22
+
23
+ describe "@raw_connection" do
24
+ subject { plugin.instance_variable_get(:@raw_connection) }
25
+ it { is_expected.to eq raw_connection }
26
+ end
27
+ end
28
+
29
+ describe "#execute" do
30
+ subject { out.string.sub(/Query options:.*/, "Query options:").sub(/rows: \d+/, "rows:") }
31
+
32
+ before do
33
+ Timecop.freeze(today) do
34
+ plugin.execute(sql)
35
+ end
36
+ end
37
+
38
+ context "when bad query" do
39
+ let(:sql) { "select * from user" }
40
+
41
+ let(:explain) do
42
+ <<-EOS
43
+ # Time: 2015-05-15 20:15:55
44
+ # Query options:
45
+ # Query: select * from user
46
+ *************************** 1. row ***************************
47
+ id: 1
48
+ select_type: SIMPLE
49
+ table: user
50
+ type: #{red bold "ALL"}
51
+ possible_keys: #{red bold "NULL"}
52
+ key: #{red bold "NULL"}
53
+ key_len:\s
54
+ ref:\s
55
+ rows:
56
+ Extra:\s
57
+ EOS
58
+ end
59
+
60
+ it { is_expected.to eq explain }
61
+ end
62
+
63
+ context "when bad query" do
64
+ let(:sql) { "select 1 from user where Host = 'localhost'" }
65
+ it { is_expected.to eq "" }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ require "arproxy/plugin/mysql_casual_log"
2
+ require "stringio"
3
+ require "time"
4
+ require "timecop"
5
+
6
+ ENV["TZ"] = "UTC"
7
+ include Term::ANSIColor
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: arproxy-plugin-mysql_casual_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Genki Sugawara
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: arproxy
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: mysql2
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: term-ansicolor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Plug-in that colorize MySQL bad query for Arproxy.
112
+ email:
113
+ - sugawara@cookpad.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - .travis.yml
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - arproxy-plugin-mysql_casual_log.gemspec
126
+ - lib/arproxy/plugin/mysql_casual_log.rb
127
+ - spec/arproxy-plugin-mysql_casual_log_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: https://github.com/winebarrel/arproxy-plugin-mysql_casual_log
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.0.14
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Plug-in that colorize MySQL bad query for Arproxy.
153
+ test_files:
154
+ - spec/arproxy-plugin-mysql_casual_log_spec.rb
155
+ - spec/spec_helper.rb