pg-connection-general_log 0.0.1

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: 867e6e436c5d596d967ce3752bb0d6628ce265ee
4
+ data.tar.gz: '092e57f1a54da5a7d549e46731e3a25950f7cbb6'
5
+ SHA512:
6
+ metadata.gz: bd28c680fc41cd5373a542b6f53824026c0faf0f6363c520e6b349a5bae2500dfa0737d51912d7b80886bc84fab5faf43675e1a53e9d4dfeada2ef50d4e4b111
7
+ data.tar.gz: daa5b3ccefa426f44ab11f42d7a2943aa1de20d50514a0151e4691525dd1a98550cc4e8dae2196955765a22d2c4f6ea8c6124f06856540a3dcafb45a3ebd4fb7
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.5
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pg-connection-general_log.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 abcang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,83 @@
1
+ PG:Connection::GeneralLog
2
+ ===
3
+
4
+ [![Build Status](https://travis-ci.org/abcang/pg-connection-general_log.svg?branch=v0.0.1)](https://travis-ci.org/abcang/pg-connection-general_log)
5
+
6
+ A monkey patch for pg.
7
+ Stock all general logs.
8
+
9
+ Inspired by [mysql2-client-general_log](https://github.com/ksss/mysql2-client-general_log)
10
+
11
+ ```ruby
12
+ #! /usr/bin/env ruby
13
+
14
+ require "pg/connection/general_log"
15
+
16
+ client = PG::Connection.new(config)
17
+ client.query("SELECT * FROM users LIMIT 1")
18
+
19
+ p client.general_log #=>
20
+ # [
21
+ # #<struct PG::Connection::GeneralLog::Log
22
+ # sql="SELECT * FROM users LIMIT 1",
23
+ # args=[],
24
+ # backtrace=["script.rb:6:in `<main>'"],
25
+ # time=0.0909838349907659>
26
+ # ]
27
+ ```
28
+
29
+ ## Examples
30
+
31
+ ### sinatra
32
+
33
+ test.rb:
34
+ ```ruby
35
+ require 'sinatra'
36
+ require 'pg'
37
+ require "pg/connection/general_log"
38
+
39
+ helpers do
40
+ def db
41
+ Thread.current[:db] ||= PG::Connection.new(config)
42
+ end
43
+ end
44
+
45
+ get '/' do
46
+ db.exec("SELECT * FROM users WHERE name = 'hoge'")
47
+ db.exec_params('SELECT * FROM users WHERE name = $1', ['hoge'])
48
+
49
+ db.prepare('select', 'SELECT * FROM users WHERE name = $1')
50
+ db.exec_prepared('select', ['bar'])
51
+ db.exec_prepared('select', ['foo'])
52
+ end
53
+
54
+ after do
55
+ db.general_log.writefile(path: '/tmp/sql.log', req: request, backtrace: true)
56
+ end
57
+ ```
58
+
59
+ /tmp/sql.log:
60
+ ```
61
+ REQUEST GET / 4
62
+ SQL (0000.89ms) SELECT * FROM users WHERE name = 'hoge' [] /path/to/test.rb:12:in `block in <main>'
63
+ SQL (0000.78ms) SELECT * FROM users WHERE name = $1 ["hoge"] /path/to/test.rb:13:in `block in <main>'
64
+ SQL (0000.66ms) SELECT * FROM users WHERE name = $1 ["barr"] /path/to/test.rb:16:in `block in <main>'
65
+ SQL (0000.65ms) SELECT * FROM users WHERE name = $1 ["foo"] /path/to/test.rb:17:in `block in <main>'
66
+ ```
67
+
68
+ ## Installation
69
+
70
+ Add this line to your application's Gemfile:
71
+
72
+ ```ruby
73
+ gem 'pg-connection-general_log'
74
+ ```
75
+
76
+ And then execute:
77
+
78
+ $ bundle
79
+
80
+
81
+ ## License
82
+
83
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task :test do
4
+ sh "rgot -v #{Dir.glob('lib/**/*_test.rb').join(' ')}"
5
+ end
6
+
7
+ task default: [:test]
@@ -0,0 +1,48 @@
1
+ require 'sinatra'
2
+ require 'pg'
3
+ require 'pg/connection/general_log'
4
+
5
+ helpers do
6
+ def db
7
+ Thread.current[:db] ||= PG.connect(
8
+ host: '127.0.0.1',
9
+ user: 'postgres',
10
+ dbname: 'pg_connection_general_log_test'
11
+ )
12
+ end
13
+
14
+ def init
15
+ db.exec('DROP TABLE IF EXISTS users')
16
+ db.exec(<<-SQL)
17
+ CREATE TABLE users (
18
+ id SERIAL NOT NULL PRIMARY KEY,
19
+ name varchar(255) NOT NULL UNIQUE,
20
+ password varchar(255) NOT NULL
21
+ );
22
+ SQL
23
+ db.exec(<<-SQL)
24
+ INSERT INTO users (name, password)
25
+ VALUES ('hoge', 'cheap-pass'),
26
+ ('foo', 'fooo'),
27
+ ('bar', 'barr')
28
+ ;
29
+ SQL
30
+ end
31
+ end
32
+
33
+ get '/' do
34
+ db.exec("SELECT * FROM users WHERE name = 'hoge'")
35
+ db.exec_params('SELECT * FROM users WHERE name = $1', ['hoge'])
36
+
37
+ db.prepare('select', 'SELECT * FROM users WHERE name = $1')
38
+ db.exec_prepared('select', ['bar'])
39
+ db.exec_prepared('select', ['foo'])
40
+ end
41
+
42
+ get '/init' do
43
+ init
44
+ end
45
+
46
+ after do
47
+ db.general_log.writefile(req: request, backtrace: true)
48
+ end
@@ -0,0 +1,89 @@
1
+ require 'pg'
2
+ require 'benchmark'
3
+
4
+ module PG
5
+ class Connection
6
+ module GeneralLog
7
+ require 'pg/connection/general_log/version'
8
+
9
+ class Log < Struct.new(:sql, :args, :backtrace, :time)
10
+ def format(use_bt = false)
11
+ ret = [
12
+ 'SQL',
13
+ '(%07.2fms)' % (time * 1000),
14
+ sql.gsub(/[\r\n]/, ' ').gsub(/ +/, ' ').strip,
15
+ args.to_s
16
+ ]
17
+ ret << backtrace[0] if use_bt
18
+
19
+ ret.join("\t")
20
+ end
21
+ end
22
+
23
+ class Logger < Array
24
+ def writefile(path: '/tmp/sql.log', req: nil, backtrace: false)
25
+ File.open(path, 'a') do |file|
26
+ if req
27
+ file.puts "REQUEST\t#{req.request_method}\t#{req.path}\t#{self.length}"
28
+ end
29
+
30
+ file.puts self.map { |log| log.format(backtrace) }.join("\n")
31
+ file.puts ''
32
+ end
33
+ self.clear
34
+ end
35
+
36
+ def push(sql, args, backtrace, time)
37
+ super(Log.new(sql, args, backtrace, time))
38
+ end
39
+ end
40
+
41
+ attr_accessor :general_log
42
+
43
+ def initialize(opts = {})
44
+ @general_log = Logger.new
45
+ @stmt_map = {}
46
+ super
47
+ end
48
+
49
+ def exec(sql)
50
+ ret = nil
51
+ time = Benchmark.realtime do
52
+ ret = super
53
+ end
54
+ @general_log.push(sql, [], caller_locations, time)
55
+ ret
56
+ end
57
+
58
+ def exec_params(*args)
59
+ sql, params = args
60
+ ret = nil
61
+ time = Benchmark.realtime do
62
+ ret = super
63
+ end
64
+ @general_log.push(sql, params, caller_locations, time)
65
+ ret
66
+ end
67
+
68
+ def prepare(*args)
69
+ stmt_name, sql = args
70
+ @stmt_map[stmt_name] = sql
71
+ super
72
+ end
73
+
74
+ def exec_prepared(*args)
75
+ stmt_name, params = args
76
+ sql = @stmt_map[stmt_name]
77
+
78
+ ret = nil
79
+ time = Benchmark.realtime do
80
+ ret = super
81
+ end
82
+ @general_log.push(sql, params, caller_locations, time)
83
+ ret
84
+ end
85
+ end
86
+
87
+ prepend GeneralLog
88
+ end
89
+ end
@@ -0,0 +1,5 @@
1
+ module PG
2
+ module GeneralLog
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,144 @@
1
+ require 'pg/connection/general_log'
2
+
3
+ module PGConnectionGeneralLogTest
4
+ def test_main(m)
5
+ client = PG.connect(
6
+ host: '127.0.0.1',
7
+ user: 'postgres'
8
+ )
9
+ client.exec('DROP DATABASE IF EXISTS pg_connection_general_log_test')
10
+ client.exec('CREATE DATABASE pg_connection_general_log_test')
11
+
12
+ @client = PG.connect(
13
+ host: '127.0.0.1',
14
+ user: 'postgres',
15
+ dbname: 'pg_connection_general_log_test'
16
+ )
17
+ exit m.run
18
+
19
+ client.exec('DROP DATABASE IF EXISTS pg_connection_general_log_test')
20
+ end
21
+
22
+ def db_init
23
+ @client.exec('DROP TABLE IF EXISTS users')
24
+ @client.exec(<<~SQL)
25
+ CREATE TABLE users (
26
+ id SERIAL NOT NULL PRIMARY KEY,
27
+ name varchar(255) NOT NULL UNIQUE,
28
+ password varchar(255) NOT NULL
29
+ );
30
+ SQL
31
+ @client.exec(<<~SQL)
32
+ INSERT INTO users (name, password)
33
+ VALUES ('hoge', 'cheap-pass'),
34
+ ('foo', 'fooo'),
35
+ ('bar', 'barr')
36
+ ;
37
+ SQL
38
+ @client.general_log.clear
39
+ end
40
+
41
+ def test_init(t)
42
+ unless @client.general_log.is_a?(Array)
43
+ t.error("initial value expect Array class got #{@client.general_log.class}")
44
+ end
45
+ unless @client.general_log.empty?
46
+ t.error("initial value expect [] got #{@client.general_log}")
47
+ end
48
+ end
49
+
50
+ def test_values(t)
51
+ db_init
52
+ ret = @client.exec("SELECT * FROM users WHERE name = '#{'hoge'}'").first
53
+ @client.exec("SELECT * FROM users WHERE name = '#{'bar'}'")
54
+ @client.exec("SELECT * FROM users WHERE name = '#{'foo'}'")
55
+
56
+ if @client.general_log.length != 3
57
+ t.error("expect log length 3 got #{@client.general_log.length}")
58
+ end
59
+ if @client.general_log.any?{|log| !log.is_a?(PG::Connection::GeneralLog::Log)}
60
+ t.error("expect all collection item is instance of PG::Connection::GeneralLog::Log got #{@client.general_log.map(&:class).uniq}")
61
+ end
62
+ expect = { 'id' => '1', 'name' => 'hoge', 'password' => 'cheap-pass' }
63
+ if ret != expect
64
+ t.error("expect exec output not change from #{expect} got #{ret}")
65
+ end
66
+ unless @client.general_log.first.format =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = 'hoge'\t\[\]$/
67
+ t.error("expect log format not correct got `#{@client.general_log.first.format}`")
68
+ end
69
+ unless @client.general_log.first.format(true) =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = 'hoge'\t\[\].+in `test_values'$/
70
+ t.error("expect log format not correct got `#{@client.general_log.first.format(true)}`")
71
+ end
72
+ end
73
+
74
+ def test_params_values(t)
75
+ db_init
76
+ ret = @client.exec_params('SELECT * FROM users WHERE name = $1', ['hoge']).first
77
+ @client.exec_params('SELECT * FROM users WHERE name = $1', ['bar'])
78
+ @client.exec_params('SELECT * FROM users WHERE name = $1', ['foo'])
79
+
80
+ if @client.general_log.length != 3
81
+ t.error("expect log length 3 got #{@client.general_log.length}")
82
+ end
83
+ if @client.general_log.any?{|log| !log.is_a?(PG::Connection::GeneralLog::Log)}
84
+ t.error("expect all collection item is instance of PG::Connection::GeneralLog::Log got #{@client.general_log.map(&:class).uniq}")
85
+ end
86
+ expect = { 'id' => '1', 'name' => 'hoge', 'password' => 'cheap-pass' }
87
+ if ret != expect
88
+ t.error("expect exec output not change from #{expect} got #{ret}")
89
+ end
90
+ unless @client.general_log.first.format =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = \$1\t\["hoge"\]$/
91
+ t.error("expect log format not correct got `#{@client.general_log.first.format}`")
92
+ end
93
+ unless @client.general_log.first.format(true) =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = \$1\t\["hoge"\].+in `test_params_values'$/
94
+ t.error("expect log format not correct got `#{@client.general_log.first.format(true)}`")
95
+ end
96
+ end
97
+
98
+ def test_prepare_values(t)
99
+ db_init
100
+ @client.prepare('select', 'SELECT * FROM users WHERE name = $1')
101
+ ret = @client.exec_prepared('select', ['hoge']).first
102
+ @client.exec_prepared('select', ['bar'])
103
+ @client.exec_prepared('select', ['foo'])
104
+
105
+ if @client.general_log.length != 3
106
+ t.error("expect log length 3 got #{@client.general_log.length}")
107
+ end
108
+ if @client.general_log.any?{|log| !log.is_a?(PG::Connection::GeneralLog::Log)}
109
+ t.error("expect all collection item is instance of PG::Connection::GeneralLog::Log got #{@client.general_log.map(&:class).uniq}")
110
+ end
111
+ expect = { 'id' => '1', 'name' => 'hoge', 'password' => 'cheap-pass' }
112
+ if ret != expect
113
+ t.error("expect exec output not change from #{expect} got #{ret}")
114
+ end
115
+ unless @client.general_log.first.format =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = \$1\t\["hoge"\]$/
116
+ t.error("expect log format not correct got `#{@client.general_log.first.format}`")
117
+ end
118
+ unless @client.general_log.first.format(true) =~ /^SQL\t\(\d+\.\d+ms\)\tSELECT \* FROM users WHERE name = \$1\t\["hoge"\].+in `test_prepare_values'$/
119
+ t.error("expect log format not correct got `#{@client.general_log.first.format(true)}`")
120
+ end
121
+ end
122
+
123
+ def test_log_class(t)
124
+ if PG::Connection::GeneralLog::Log.members != %i[sql args backtrace time]
125
+ t.error("expect PG::Connection::GeneralLog::Log.members is [:sql, :args, :backtrace, :time] got #{PG::Connection::GeneralLog::Log.members}")
126
+ end
127
+ end
128
+
129
+ def example_general_log
130
+ db_init
131
+ @client.exec("SELECT * FROM users WHERE name = '#{'hoge'}'")
132
+ @client.exec_params('SELECT * FROM users WHERE name = $1', ['hoge'])
133
+
134
+ @client.prepare('select2', 'SELECT * FROM users WHERE name = $1')
135
+ @client.exec_prepared('select2', ['bar'])
136
+ @client.exec_prepared('select2', ['foo'])
137
+ puts @client.general_log.map { |log| [log.sql, log.args.to_s, log.backtrace.find{|c| %r{/gems/} !~ c.to_s}.to_s.gsub(/.*?:/, '')].join(' ') }
138
+ # Output:
139
+ # SELECT * FROM users WHERE name = 'hoge' [] in `example_general_log'
140
+ # SELECT * FROM users WHERE name = $1 ["hoge"] in `example_general_log'
141
+ # SELECT * FROM users WHERE name = $1 ["bar"] in `example_general_log'
142
+ # SELECT * FROM users WHERE name = $1 ["foo"] in `example_general_log'
143
+ end
144
+ end
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ File.read('lib/pg/connection/general_log/version.rb') =~ /.*VERSION\s*=\s*['"](.*?)['"]\s.*/
4
+ version = Regexp.last_match(1)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'pg-connection-general_log'
8
+ spec.version = version
9
+ spec.authors = ['abcang']
10
+ spec.email = ['abcang1015@gmail.com']
11
+
12
+ spec.summary = 'Simple stocker general log for pg gem.'
13
+ spec.description = 'Simple stocker general log for pg gem.'
14
+ spec.homepage = 'https://github.com/abcang/pg-connection-general_log'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_runtime_dependency 'pg'
21
+ spec.add_development_dependency 'bundler', '~> 1.15'
22
+ spec.add_development_dependency 'rake', '~> 12.2'
23
+ spec.add_development_dependency 'rgot'
24
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pg-connection-general_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - abcang
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rgot
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
+ description: Simple stocker general log for pg gem.
70
+ email:
71
+ - abcang1015@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - example/test.rb
83
+ - lib/pg/connection/general_log.rb
84
+ - lib/pg/connection/general_log/version.rb
85
+ - lib/pg/connection/general_log_test.rb
86
+ - pg-connection-general_logs.gemspec
87
+ homepage: https://github.com/abcang/pg-connection-general_log
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.6.13
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Simple stocker general log for pg gem.
111
+ test_files: []