oplog_event_handler 0.0.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.
Files changed (3) hide show
  1. checksums.yaml +15 -0
  2. data/lib/oplog_event_handler.rb +163 -0
  3. metadata +43 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjBkYzI1Y2NjNGIyMDg4NmU0MTNhMGNjMTc3ZDMxMDgxZGM3NGYyZA==
5
+ data.tar.gz: !binary |-
6
+ OTIyZWEyMDJmY2RkZjUyMjRjMmFhM2VhMzdlYzAxNDIxMDZlOWMyMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZTcxYjhlMzk3OWYxYmUwMTQxMjIwZmQzYWIzYTU5MzU5MDVkNmUwMDZmMDdi
10
+ ZGQzZTFjZjk0ZGJmNzQ1MzY0NTNiNTc2ZjM4MjMxMGFkNTA1NTAzYTY5OTIy
11
+ MjY2ZDkzM2Y0YTRlODgzYWEwZTlkYWY1NDVmNWUxZjdmODMxZGQ=
12
+ data.tar.gz: !binary |-
13
+ OTQ1ZDM0YmYzZWJkOWEyZWZmOTZkMzE0YzMwMDllOTU2YjVkY2MwMzlmMzdh
14
+ ZTBkMTkzMWEyYTdjNjk4NzZhYmU5NWQyOTI5ZDE1YTI2YzJlNjUwNzhmOTJl
15
+ MzkwMDBlYTkxYzIyY2QyNTdhMTA5NzBjNjZmYThlZWYzZDM4ZTc=
@@ -0,0 +1,163 @@
1
+ require 'mongo'
2
+ module OplogEventHandler
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ OPERATIONS = {
9
+ 'i' => :insert,
10
+ 'u' => :update,
11
+ 'd' => :delete,
12
+ 'c' => :dbcmd,
13
+ 'n' => :noop
14
+ }
15
+
16
+ module ClassMethods
17
+
18
+ def connect_to(h)
19
+ @connection = h
20
+ end
21
+
22
+ def host
23
+ @connection[:host]
24
+ end
25
+
26
+ def port
27
+ @connection[:port]
28
+ end
29
+
30
+ def db_name
31
+ @db_name
32
+ end
33
+
34
+ def for_db(db)
35
+ @db_name = db
36
+ yield
37
+ end
38
+
39
+ def mapping
40
+ return @mapping ||= {}
41
+ end
42
+
43
+ def on_insert(opts)
44
+ mapping[:"insert_#{db_name}_#{opts[:in]}"] = opts[:call]
45
+ end
46
+
47
+ def on_update(opts)
48
+ if opts[:only].nil?
49
+ mapping[:"update_#{db_name}_#{opts[:in]}"] = opts[:call]
50
+ else
51
+ opts[:only].each do |e|
52
+ mapping[:"update_#{db_name}_#{opts[:in]}##{e}"] = opts[:call]
53
+ end
54
+ end
55
+ end
56
+
57
+ def on_delete(opts)
58
+ mapping[:"delete_#{db_name}_#{opts[:in]}"] = opts[:call]
59
+ end
60
+
61
+ end
62
+
63
+ def run()
64
+ tail do |log|
65
+ callbacks = get_callbaks(log)
66
+ unless callbacks.empty?
67
+ send_events(log, callbacks)
68
+ end
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def send_events(log, callbacks)
75
+ callbacks.each do |callback|
76
+ begin
77
+ case log['op']
78
+ when 'u'
79
+ send(callback, id: get_object_id(log), log: log)
80
+ when 'i'
81
+ send(callback, id: get_object_id(log), object: log['o'])
82
+ when 'd'
83
+ send(callback, id: get_object_id(log))
84
+ end
85
+ rescue Exception => e
86
+ puts present_error(e, callback)
87
+ end
88
+ end
89
+ end
90
+
91
+ def present_error(ex, callback)
92
+ """
93
+ =============================
94
+ Erorr in callback
95
+ #{callback}
96
+ #{ex.to_s}
97
+ =============================
98
+ #{ex.backtrace}
99
+ """
100
+ end
101
+
102
+ def get_callbaks(log)
103
+ callbacks = [self.class.mapping[:"#{extract_operation(log)}_#{extract_db_name(log)}_#{extract_collection_name(log)}"]]
104
+ if log['op'] == 'u'
105
+ fields(log).each do |f|
106
+ callbacks << self.class.mapping[:"#{extract_operation(log)}_#{extract_db_name(log)}_#{extract_collection_name(log)}##{f}"]
107
+ end
108
+ end
109
+ callbacks.compact!
110
+ callbacks.uniq!
111
+ return callbacks
112
+ end
113
+
114
+ def extract_db_name(doc)
115
+ doc['ns'].split('.')[0]
116
+ end
117
+
118
+ def extract_collection_name(doc)
119
+ doc['ns'].sub(/\A\w+\./, '')
120
+ end
121
+
122
+ def extract_operation(doc)
123
+ OPERATIONS[doc['op']]
124
+ end
125
+
126
+ def get_object_id(doc)
127
+ case doc['op']
128
+ when 'u'
129
+ doc['o2']['_id']
130
+ else
131
+ doc['o']['_id']
132
+ end
133
+ end
134
+
135
+ def get_keys(h)
136
+ ks = []
137
+ h.each do |k, v|
138
+ k.split('.').each { |e| ks << e }
139
+ ks << get_keys(v) if v.kind_of?(Hash)
140
+ end
141
+ ks.flatten
142
+ end
143
+
144
+ def fields(doc)
145
+ if doc['op'] == 'u'
146
+ get_keys(doc['o']).keep_if { |e| e[0] != '$' }
147
+ end
148
+ end
149
+
150
+ def tail
151
+ oplog_coll = Mongo::Connection.new(self.class.host, self.class.port)['local']['oplog.rs']
152
+ start = oplog_coll.count
153
+ tailable_oplog = Mongo::Cursor.new(oplog_coll, :timeout => false, :tailable => true).skip(start)
154
+ while not tailable_oplog.closed?
155
+ doc = tailable_oplog.next_document
156
+ if doc
157
+ yield doc
158
+ else
159
+ sleep(0.1)
160
+ end
161
+ end
162
+ end
163
+ end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oplog_event_handler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mathieu Laporte
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Just parse the oplog
14
+ email: mathieu.laporte+rubygem@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/oplog_event_handler.rb
20
+ homepage: https://github.com/mathieulaporte/oplog_event_handler
21
+ licenses: []
22
+ metadata: {}
23
+ post_install_message:
24
+ rdoc_options: []
25
+ require_paths:
26
+ - lib
27
+ required_ruby_version: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ required_rubygems_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ requirements: []
38
+ rubyforge_project:
39
+ rubygems_version: 2.0.3
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: oplog parser
43
+ test_files: []