oplog_event_handler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []