iron_trail 0.0.6 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34fb140276f60147f1c5d4beb71a3ba39a8f2c552a76e3b3c7e749e94ec518a2
4
- data.tar.gz: 4e7700b3f5c53090a623e1be9ed5b0e6a513869450176c58bdc8fdd1352decf1
3
+ metadata.gz: e0eaa9c2070ae46d7386af196b943c47c495fba0485bc1b1956691e182ad099e
4
+ data.tar.gz: 732e39b8d5edba42b54a0f6bc67f6389d89fe1d037930c10dc4dff72a1afeb18
5
5
  SHA512:
6
- metadata.gz: 0faa78641a209ccc88bed839b8988e1cc250465e6621e08158e38f1c68c0a4be421ab7f5346cbed7b6a25a658eeca9a51d015a1b23572ee2e91eab6aa04e29ce
7
- data.tar.gz: 563248c156fb4716cb0befa64cfcd7a81f8b98594db3008853ccc2625e5e4b2e9a2948de12dbced48d018c3e1a915536baeef65d606deb973bcc0c0afe7853e3
6
+ metadata.gz: 21577368bee6f5560d27488a4bfbc3cd064bdca3869a8538002838e10f64bcaf6c20f7ec2a0a1ce56d5690b9959adbe780e6b4d7b41e59af1a78f281f1ef413a
7
+ data.tar.gz: 7e6b3c94d40059c22aa929efb07f93fdcef8abc1ffc6ef63dfe10c7d862c31d39880cc1175ad953231675bb2dd644e23d7a0b2ba1e426544af330309c77e26bb
@@ -56,11 +56,32 @@ module IronTrail
56
56
  connection.execute(query)
57
57
  end
58
58
 
59
+ # Counting rows in Postgres is known to be a slow operation for large tables.
60
+ # Because of this, avoid using this for monitoring new errors. Instead,
61
+ # use the trigger_errors_metrics method.
59
62
  def trigger_errors_count
60
63
  stmt = 'SELECT COUNT(*) AS c FROM "irontrail_trigger_errors"'
61
64
  connection.execute(stmt).first['c']
62
65
  end
63
66
 
67
+ # This returns metrics intended to be used for monitoring. One can send
68
+ # these values to something like a Prometheus deployment and add monitoring
69
+ # on top of it.
70
+ # It should be much faster to run than trigger_errors_count.
71
+ #
72
+ # If the irontrail_trigger_errors table is empty, the resulting values
73
+ # will all be zero and never nil. This is so that data in a monitoring setup
74
+ # can tell apart a failure from a no-data scenario.
75
+ def trigger_errors_metrics
76
+ stmt = 'SELECT MAX(created_at) maxdate, MAX(id) AS maxid FROM "irontrail_trigger_errors"'
77
+ res = connection.execute(stmt).first
78
+
79
+ {
80
+ max_created_at: (res && res['maxdate'] && res['maxdate'].to_i) || 0,
81
+ max_id: (res && res['maxid']) || 0,
82
+ }
83
+ end
84
+
64
85
  def collect_all_tables(schema: 'public')
65
86
  # query pg_class rather than information schema because this way
66
87
  # we can get only regular tables and ignore partitions.
@@ -11,10 +11,12 @@ DECLARE
11
11
  new_obj JSONB;
12
12
  actor_type TEXT;
13
13
  actor_id TEXT;
14
+ created_at TIMESTAMP;
14
15
 
15
16
  err_text TEXT; err_detail TEXT; err_hint TEXT; err_ctx TEXT;
16
17
  BEGIN
17
18
  SELECT split_part(split_part(current_query(), '/*IronTrail ', 2), ' IronTrail*/', 1) INTO it_meta;
19
+
18
20
  IF (it_meta <> '') THEN
19
21
  it_meta_obj = it_meta::JSONB;
20
22
 
@@ -28,17 +30,30 @@ BEGIN
28
30
  END IF;
29
31
  END IF;
30
32
 
33
+ old_obj = row_to_json(OLD);
34
+ new_obj = row_to_json(NEW);
35
+
36
+ IF (TG_OP = 'INSERT' AND new_obj ? 'created_at') THEN
37
+ created_at = NEW.created_at;
38
+ ELSIF (TG_OP = 'UPDATE' AND new_obj ? 'updated_at') THEN
39
+ created_at = NEW.updated_at;
40
+ END IF;
41
+
42
+ IF (created_at IS NULL) THEN
43
+ created_at = STATEMENT_TIMESTAMP();
44
+ ELSE
45
+ it_meta_obj = jsonb_set(COALESCE(it_meta_obj, '{}'::jsonb), array['_db_created_at'], TO_JSONB(STATEMENT_TIMESTAMP()));
46
+ END IF;
47
+
31
48
  IF (TG_OP = 'INSERT') THEN
32
49
  INSERT INTO "irontrail_changes" ("actor_id", "actor_type",
33
50
  "rec_table", "operation", "rec_id", "rec_new", "metadata", "created_at")
34
51
  VALUES (actor_id, actor_type,
35
- TG_TABLE_NAME, 'i', NEW.id, row_to_json(NEW), it_meta_obj, NOW());
52
+ TG_TABLE_NAME, 'i', NEW.id, new_obj, it_meta_obj, created_at);
36
53
 
37
54
  ELSIF (TG_OP = 'UPDATE') THEN
38
55
  IF (OLD <> NEW) THEN
39
56
  u_changes = jsonb_build_object();
40
- old_obj = row_to_json(OLD);
41
- new_obj = row_to_json(NEW);
42
57
 
43
58
  FOR key IN (SELECT jsonb_object_keys(old_obj) UNION SELECT jsonb_object_keys(new_obj))
44
59
  LOOP
@@ -51,14 +66,13 @@ BEGIN
51
66
 
52
67
  INSERT INTO "irontrail_changes" ("actor_id", "actor_type", "rec_table", "operation",
53
68
  "rec_id", "rec_old", "rec_new", "rec_delta", "metadata", "created_at")
54
- VALUES (actor_id, actor_type, TG_TABLE_NAME, 'u', NEW.id, row_to_json(OLD), row_to_json(NEW),
55
- u_changes, it_meta_obj, NOW());
69
+ VALUES (actor_id, actor_type, TG_TABLE_NAME, 'u', NEW.id, old_obj, new_obj, u_changes, it_meta_obj, created_at);
56
70
 
57
71
  END IF;
58
72
  ELSIF (TG_OP = 'DELETE') THEN
59
73
  INSERT INTO "irontrail_changes" ("actor_id", "actor_type", "rec_table", "operation",
60
74
  "rec_id", "rec_old", "metadata", "created_at")
61
- VALUES (actor_id, actor_type, TG_TABLE_NAME, 'd', OLD.id, row_to_json(OLD), it_meta_obj, NOW());
75
+ VALUES (actor_id, actor_type, TG_TABLE_NAME, 'd', OLD.id, old_obj, it_meta_obj, created_at);
62
76
 
63
77
  END IF;
64
78
  RETURN NULL;
@@ -74,7 +88,7 @@ EXCEPTION
74
88
  "err_text", "ex_detail", "ex_hint", "ex_ctx", "op", "table_name",
75
89
  "old_data", "new_data", "query", "created_at")
76
90
  VALUES (SQLSTATE, SQLERRM, err_text, err_detail, err_hint, err_ctx,
77
- TG_OP, TG_TABLE_NAME, row_to_json(OLD), row_to_json(NEW), current_query(), NOW());
91
+ TG_OP, TG_TABLE_NAME, row_to_json(OLD), row_to_json(NEW), current_query(), STATEMENT_TIMESTAMP());
78
92
  RETURN NULL;
79
93
  END;
80
94
  $$ LANGUAGE plpgsql;
@@ -1,5 +1,5 @@
1
1
  # frozen_literal_string: true
2
2
 
3
3
  module IronTrail
4
- VERSION = '0.0.6'
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/iron_trail.rb CHANGED
@@ -52,17 +52,6 @@ module IronTrail
52
52
  config.enable
53
53
  end
54
54
 
55
- # def test_mode!
56
- # if [ENV['RAILS_ENV'], ENV['RACK_ENV']].include?('production')
57
- # raise "IronTrail test mode cannot be enabled in production!"
58
- # end
59
- # @test_mode = true
60
- # end
61
- #
62
- # def test_mode?
63
- # @test_mode
64
- # end
65
-
66
55
  def ignore_table?(name)
67
56
  (OWN_TABLES + (config.ignored_tables || [])).include?(name)
68
57
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iron_trail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Diego Piske
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-22 00:00:00.000000000 Z
10
+ date: 2025-02-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -153,7 +153,13 @@ files:
153
153
  homepage: https://github.com/trusted/iron_trail
154
154
  licenses:
155
155
  - MIT
156
- metadata: {}
156
+ metadata:
157
+ bug_tracker_uri: https://github.com/trusted/iron_trail/issues
158
+ changelog_uri: https://github.com/trusted/iron_trail/blob/main/CHANGELOG.md
159
+ documentation_uri: https://github.com/trusted/iron_trail/blob/main/README.md
160
+ homepage_uri: https://github.com/trusted/iron_trail
161
+ source_code_uri: https://github.com/trusted/iron_trail
162
+ wiki_uri: https://github.com/trusted/iron_trail/wiki
157
163
  rdoc_options: []
158
164
  require_paths:
159
165
  - lib