pg_audit_log 0.4.0 → 0.4.4

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.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .vimlog
1
2
  *.gem
2
3
  *~
3
4
  .DS_Store
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm 1.9.2@pg_audit_log --create
1
+ rvm 1.9.3-p0@pg_audit_log --create
@@ -9,7 +9,9 @@ Comes with specs for your project and a rake task to generate the reverse SQL to
9
9
 
10
10
  All SQL INSERTs, UPDATEs, and DELETEs will be captured. Record columns that do not change do not generate an audit log entry.
11
11
 
12
- Compatible with Rails 3.0.x and 3.1.x
12
+ Compatible with Rails 3.0.x, 3.1.x and 3.2.x
13
+
14
+ On a 2.93GHz i7 with postgresql 9.1 the audit log has an overhead of about 0.0035 seconds to each INSERT, UPDATE or DELETE
13
15
 
14
16
  == INSTALL
15
17
 
@@ -1,6 +1,10 @@
1
1
  class PgAuditLog::Entry < ActiveRecord::Base
2
2
  TABLE_NAME = "audit_log"
3
- set_table_name TABLE_NAME
3
+ if ::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR >= 2
4
+ self.table_name = TABLE_NAME
5
+ else
6
+ set_table_name TABLE_NAME
7
+ end
4
8
 
5
9
  class CannotDeleteError < StandardError
6
10
  def message
@@ -30,7 +30,11 @@ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
30
30
  if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
31
31
  PgAuditLog::Triggers.drop_for_table(table_name)
32
32
  end
33
- drop_table_without_auditing(table_name, options)
33
+ if ::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR >= 2
34
+ drop_table_without_auditing(table_name)
35
+ else
36
+ drop_table_without_auditing(table_name, options)
37
+ end
34
38
  end
35
39
  alias_method_chain :drop_table, :auditing
36
40
 
@@ -61,40 +61,39 @@ module PgAuditLog
61
61
  unique_name varchar;
62
62
  column_name varchar;
63
63
  BEGIN
64
+ primary_key_column := NULL;
65
+ EXECUTE 'SELECT pg_attribute.attname
66
+ FROM pg_index, pg_class, pg_attribute
67
+ WHERE pg_class.oid = $1::regclass
68
+ AND indrelid = pg_class.oid
69
+ AND pg_attribute.attrelid = pg_class.oid
70
+ AND pg_attribute.attnum = any(pg_index.indkey)
71
+ AND indisprimary'
72
+ INTO primary_key_column USING TG_RELNAME;
73
+ user_identifier := pg_temp.pg_audit_log_user_identifier();
74
+ unique_name := pg_temp.pg_audit_log_user_unique_name();
75
+ primary_key_value := NULL;
76
+
64
77
  FOR col IN SELECT * FROM information_schema.columns WHERE table_name = TG_RELNAME LOOP
65
78
  new_value := NULL;
66
79
  old_value := NULL;
67
- primary_key_column := NULL;
68
- primary_key_value := NULL;
69
- user_identifier := pg_temp.pg_audit_log_user_identifier();
70
- unique_name := pg_temp.pg_audit_log_user_unique_name();
71
80
  column_name := col.column_name;
72
-
73
- EXECUTE 'SELECT pg_attribute.attname
74
- FROM pg_index, pg_class, pg_attribute
75
- WHERE pg_class.oid = $1::regclass
76
- AND indrelid = pg_class.oid
77
- AND pg_attribute.attrelid = pg_class.oid
78
- AND pg_attribute.attnum = any(pg_index.indkey)
79
- AND indisprimary'
80
- INTO primary_key_column USING TG_RELNAME;
81
-
82
- IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
83
- EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO new_value USING NEW;
84
- IF primary_key_column IS NOT NULL THEN
85
- EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING NEW;
86
- END IF;
87
- END IF;
88
- IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
89
- EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO old_value USING OLD;
90
- IF primary_key_column IS NOT NULL THEN
91
- EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING OLD;
92
- END IF;
93
- END IF;
94
-
95
81
  IF TG_RELNAME = '#{users_table_name}' AND column_name = '#{users_access_column}' THEN
96
82
  NULL;
97
83
  ELSE
84
+ IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
85
+ EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO new_value USING NEW;
86
+ IF primary_key_value IS NULL AND primary_key_column IS NOT NULL THEN
87
+ EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING NEW;
88
+ END IF;
89
+ END IF;
90
+ IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
91
+ EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO old_value USING OLD;
92
+ IF primary_key_value IS NULL AND primary_key_column IS NOT NULL THEN
93
+ EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING OLD;
94
+ END IF;
95
+ END IF;
96
+
98
97
  IF TG_OP != 'UPDATE' OR new_value != old_value OR (TG_OP = 'UPDATE' AND ( (new_value IS NULL AND old_value IS NOT NULL) OR (new_value IS NOT NULL AND old_value IS NULL))) THEN
99
98
  INSERT INTO audit_log("operation",
100
99
  "table_name",
@@ -11,7 +11,11 @@ module PgAuditLog
11
11
 
12
12
  class << self
13
13
  def tables
14
- connection.tables - (PgAuditLog::IGNORED_TABLES + [PgAuditLog::Entry.table_name])
14
+ skip_tables = (PgAuditLog::IGNORED_TABLES + [PgAuditLog::Entry.table_name])
15
+ connection.tables.reject do |table|
16
+ skip_tables.include?(table) ||
17
+ skip_tables.any? { |skip_table| skip_table =~ table if skip_table.is_a? Regexp }
18
+ end
15
19
  end
16
20
 
17
21
  def tables_with_triggers
@@ -28,6 +32,10 @@ module PgAuditLog
28
32
  tables - tables_with_triggers
29
33
  end
30
34
 
35
+ def all_tables_without_triggers
36
+ connection.tables - tables_with_triggers
37
+ end
38
+
31
39
  def install
32
40
  tables.each do |table|
33
41
  create_for_table(table) unless tables_with_triggers.include?(table)
@@ -1,3 +1,3 @@
1
1
  module PgAuditLog
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.4"
3
3
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_dependency("rails", ">= 3.0.0")
21
21
  s.add_dependency("pg", ">= 0.9.0")
22
- s.add_development_dependency('rspec-rails')
22
+ s.add_development_dependency('rspec-rails', "= 2.7")
23
23
  s.add_development_dependency('with_model', '>= 0.1.3')
24
24
  s.add_development_dependency('autotest')
25
25
  end
@@ -222,6 +222,19 @@ describe PgAuditLog do
222
222
  its(:primary_key) { should be_nil }
223
223
  end
224
224
  end
225
+
226
+ describe "performance" do
227
+ xit "should perform well" do
228
+ require "benchmark"
229
+ results = Benchmark.measure do
230
+ 1000.times do
231
+ AuditedModel.create!(attributes)
232
+ end
233
+ end
234
+ puts results.real
235
+ puts results.real / 1000.0
236
+ end
237
+ end
225
238
  end
226
239
 
227
240
  describe "during migrations" do
@@ -17,6 +17,23 @@ describe PgAuditLog::Triggers do
17
17
  PgAuditLog::Triggers.drop_for_table(TableWithoutTriggers.table_name) rescue nil
18
18
  end
19
19
 
20
+ describe ".tables" do
21
+ subject { PgAuditLog::Triggers.tables }
22
+
23
+ with_model :table_to_ignore do
24
+ table {}
25
+ end
26
+
27
+ before do
28
+ PgAuditLog::IGNORED_TABLES << /ignore/
29
+ end
30
+
31
+ it { should include(TableWithTriggers.table_name) }
32
+ it { should include(TableWithoutTriggers.table_name) }
33
+ it { should_not include(PgAuditLog::Entry.table_name) }
34
+ it { should_not include(TableToIgnore.table_name) }
35
+ end
36
+
20
37
  describe ".tables_with_triggers" do
21
38
  it "should return an array of all tables that do have an audit trigger installed" do
22
39
  PgAuditLog::Triggers.tables_with_triggers.should include(TableWithTriggers.table_name)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_audit_log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-03 00:00:00.000000000Z
12
+ date: 2012-02-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &2152506680 !ruby/object:Gem::Requirement
16
+ requirement: &70094371058580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2152506680
24
+ version_requirements: *70094371058580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: pg
27
- requirement: &2152505720 !ruby/object:Gem::Requirement
27
+ requirement: &70094371056820 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,21 +32,21 @@ dependencies:
32
32
  version: 0.9.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2152505720
35
+ version_requirements: *70094371056820
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec-rails
38
- requirement: &2152505120 !ruby/object:Gem::Requirement
38
+ requirement: &70094371056040 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
- - - ! '>='
41
+ - - =
42
42
  - !ruby/object:Gem::Version
43
- version: '0'
43
+ version: '2.7'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2152505120
46
+ version_requirements: *70094371056040
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: with_model
49
- requirement: &2152503960 !ruby/object:Gem::Requirement
49
+ requirement: &70094371055100 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.1.3
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2152503960
57
+ version_requirements: *70094371055100
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: autotest
60
- requirement: &2152503100 !ruby/object:Gem::Requirement
60
+ requirement: &70094371054000 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2152503100
68
+ version_requirements: *70094371054000
69
69
  description: A completely transparent audit logging component for your application
70
70
  using a stored procedure and triggers. Comes with specs for your project and a rake
71
71
  task to generate the reverse SQL to undo changes logged
@@ -120,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
120
  version: '0'
121
121
  segments:
122
122
  - 0
123
- hash: -732310515117041189
123
+ hash: -4309702284919187778
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  none: false
126
126
  requirements:
@@ -129,10 +129,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
129
  version: '0'
130
130
  segments:
131
131
  - 0
132
- hash: -732310515117041189
132
+ hash: -4309702284919187778
133
133
  requirements: []
134
134
  rubyforge_project:
135
- rubygems_version: 1.8.10
135
+ rubygems_version: 1.8.6
136
136
  signing_key:
137
137
  specification_version: 3
138
138
  summary: postgresql only database-level audit logging of all databases changes