txcatcher 0.1.79 → 0.1.80

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d59cc16bf5e45f94d7e985ae349c9df72c0a07c3
4
- data.tar.gz: 4c38a0be61645875a0103e421d6ca6b5119368c1
3
+ metadata.gz: 7d2ec242dcffc29ac886983fba7ab7059465a9c4
4
+ data.tar.gz: f6846d3b51cfbd75e255349869aea3f0025b8162
5
5
  SHA512:
6
- metadata.gz: ace16685e76eca3039acf6b4b91e1f625a431e05a5ea2c07cf5a2dfd11072843a8e027668d2accc25ea776e893d616200003408a5db5552eba49b426368fffea
7
- data.tar.gz: 228a20993a98902b88ce773e2efa25d7442214ccc6f9bfb68ac804e9f3732eefd4e4e96b9629ddd4aceeeb3de220617ce681d688f1787e52b7b0aab4cc62a539
6
+ metadata.gz: '0832cce4418a861b4953ac158c346608f5d8e72ae5cd89a7a08ae89216321c1f0f2770140e3e561e95277da3c3629606b8d3e12f5569e586711ca802d3933d79'
7
+ data.tar.gz: 5a1105b971ec62a6598781eee994e90993cd780fab2cf495dcb05c305dd34766ae9944624390af047fce31340967c1b8d9a29868800ffcbb9795821d67244e1b
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ gem "goliath"
4
4
  gem "sequel"
5
5
  gem "ffi-rzmq"
6
6
  gem "satoshi-unit"
7
+ gem "sentry-raven"
7
8
 
8
9
  group :development do
9
10
  gem "bundler"
data/Gemfile.lock CHANGED
@@ -95,6 +95,8 @@ GEM
95
95
  rspec-support (3.7.1)
96
96
  satoshi-unit (0.2.2)
97
97
  semver2 (3.4.2)
98
+ sentry-raven (2.6.3)
99
+ faraday (>= 0.7.6, < 1.0)
98
100
  sequel (5.5.0)
99
101
  sqlite3 (1.3.13)
100
102
  thread_safe (0.3.6)
@@ -109,6 +111,7 @@ DEPENDENCIES
109
111
  jeweler
110
112
  rspec
111
113
  satoshi-unit
114
+ sentry-raven
112
115
  sequel
113
116
  sqlite3
114
117
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.79
1
+ 0.1.80
@@ -9,7 +9,7 @@ module TxCatcher
9
9
  @sockets = {}
10
10
 
11
11
  {'rawtx' => "#{socket}#{name}.rawtx", 'hashblock' => "#{socket}#{name}.hashblock"}.each do |channel, address|
12
- puts "Start listening on #{name} #{channel}... (#{address})"
12
+ Logger.report "Start listening on #{name} #{channel}... (#{address})"
13
13
  listen_to_zeromq_message(channel: channel, address: address)
14
14
  end
15
15
  end
@@ -32,18 +32,16 @@ module TxCatcher
32
32
  # before we start listening to any messages from ZeroMQ.
33
33
  queue_thread = Thread.new do
34
34
  loop do
35
- puts "in #{channel} queue: #{@queue[channel].size}"
35
+ Logger.report "in #{channel} queue: #{@queue[channel].size}" if Config["logger"]["log_queue_info"]
36
36
  if @queue[channel].empty?
37
37
  sleep 1
38
38
  else
39
39
  begin
40
40
  @queue[channel].pop.call
41
41
  rescue Sequel::ValidationFailed => e
42
- $stdout.puts "[WARNING #{Time.now.to_s}] #{e.class} #{e.to_s}\n"
42
+ Logger.report e, :warn, timestamp: true
43
43
  rescue StandardError => e
44
- File.open(TxCatcher::Config.config_dir + "/error.log", "a") do |f|
45
- f.puts "[ERROR #{Time.now.to_s}] #{e.class} #{e.to_s}\n #{e.backtrace.join("\n ")}\n\n"
46
- end
44
+ Logger.report e, :error, timestamp: true
47
45
  end
48
46
  end
49
47
  end
@@ -77,14 +75,14 @@ module TxCatcher
77
75
  end # listen_to_zeromq_message
78
76
 
79
77
  def handle_rawtx(txhex)
80
- $stdout.print "received tx hex: #{txhex[0..50]}...\n"
78
+ Logger.report "received tx hex: #{txhex[0..50]}..."
81
79
 
82
80
  @queue["rawtx"] << ( Proc.new {
83
81
  tx = TxCatcher::Transaction.new(hex: txhex)
84
82
  tx.save
85
- $stdout.puts "tx #{tx.txid} saved (id: #{tx.id}), deposits (outputs):"
83
+ Logger.report "tx #{tx.txid} saved (id: #{tx.id}), deposits (outputs):"
86
84
  tx.deposits.each do |d|
87
- $stdout.puts " id: #{d.id}, addr: #{d.address.address}, amount: #{Satoshi.new(d.amount, from_unit: :satoshi).to_btc}"
85
+ Logger.report " id: #{d.id}, addr: #{d.address.address}, amount: #{Satoshi.new(d.amount, from_unit: :satoshi).to_btc}"
88
86
  end
89
87
  })
90
88
  end
@@ -93,7 +91,7 @@ module TxCatcher
93
91
  block_hash = TxCatcher.rpc_node.getblock(block_hex)
94
92
  transactions = block_hash["tx"]
95
93
  height = TxCatcher.current_block_height = block_hash["height"].to_i
96
- $stdout.puts "*** Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
94
+ Logger.report "*** Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
97
95
  @queue["hashblock"] << ( Proc.new {
98
96
  Transaction.where(txid: transactions).update(block_height: height)
99
97
  })
@@ -19,14 +19,14 @@ module TxCatcher
19
19
  else
20
20
  TxCatcher::Transaction.count
21
21
  end
22
- $stdout.print "Cleaning transactions in DB..."
23
- $stdout.print "#{db_tx_count} now, needs to be below #{Config.max_db_transactions_stored}\n"
22
+ Logger.report "Cleaning transactions in DB..."
23
+ Logger.report "#{db_tx_count} now, needs to be below #{Config.max_db_transactions_stored}\n"
24
24
  if db_tx_count > Config.max_db_transactions_stored
25
25
  number_to_delete = (db_tx_count - Config.max_db_transactions_stored) + (Config.max_db_transactions_stored*0.1).round
26
26
  clean_transactions(number_to_delete)
27
- $stdout.puts "DB cleaned: #{@@cleaning_counter.to_s}"
27
+ Logger.report "DB cleaned: #{@@cleaning_counter.to_s}"
28
28
  else
29
- $stdout.puts "Nothing to be cleaned from DB, size is below threshold."
29
+ Logger.report "Nothing to be cleaned from DB, size is below threshold."
30
30
  end
31
31
  if @stop || run_once
32
32
  @@stopped = true
@@ -58,7 +58,7 @@ module TxCatcher
58
58
  t.times do
59
59
  limit = n <= 100 ? n : 100
60
60
  transactions.limit(limit).each do |t|
61
- $stdout.puts "- Removing tx #{t.txid}"
61
+ Logger.report "- Removing tx #{t.txid}"
62
62
  clean_deposits(t)
63
63
  TxCatcher.db_connection[:transactions].filter(id: t.id).delete
64
64
  @@cleaning_counter[:transactions] += 1
@@ -18,17 +18,19 @@ module TxCatcher
18
18
  # Determine config dir or set default. Useful when we want to
19
19
  # have different settings for production or staging or development environments.
20
20
  def set!(path=nil)
21
- @@config_file = path and return if path
22
- @@config_file = ENV['HOME'] + '/.txcatcher/config.yml'
23
- ARGV.each_with_index do |a,i|
24
- if a =~ /\A--config-file=.+/
25
- @@config_file = File.expand_path(a.sub('--config-file=', ''))
26
- ARGV.delete_at(i)
27
- break
28
- elsif a =~ /\A-c\Z/
29
- @@config_file = File.expand_path(ARGV[1])
30
- ARGV.delete_at(i) and ARGV.delete_at(i+1)
31
- break
21
+ @@config_file = path
22
+ unless path
23
+ @@config_file = ENV['HOME'] + '/.txcatcher/config.yml'
24
+ ARGV.each_with_index do |a,i|
25
+ if a =~ /\A--config-file=.+/
26
+ @@config_file = File.expand_path(a.sub('--config-file=', ''))
27
+ ARGV.delete_at(i)
28
+ break
29
+ elsif a =~ /\A-c\Z/
30
+ @@config_file = File.expand_path(ARGV[1])
31
+ ARGV.delete_at(i) and ARGV.delete_at(i+1)
32
+ break
33
+ end
32
34
  end
33
35
  end
34
36
  TxCatcher::Config.config_dir = File.dirname(@@config_file)
@@ -45,6 +47,7 @@ module TxCatcher
45
47
 
46
48
  def prepare
47
49
  ConfigFile.set!
50
+ initialize_sentry
48
51
  create_config_files
49
52
  read_config_file
50
53
  connect_to_db
@@ -149,6 +152,13 @@ module TxCatcher
149
152
  !Sequel::Migrator.is_current?(TxCatcher.db_connection, MIGRATIONS_ROOT)
150
153
  end
151
154
 
155
+ def initialize_sentry
156
+ Raven.configure do |config|
157
+ config.dsn = Config["sentry"]["dsn"]
158
+ config.environments = ["production"]
159
+ end if Config["sentry"] && Config["sentry"]["dsn"]
160
+ end
161
+
152
162
  end
153
163
 
154
164
  end
@@ -0,0 +1,63 @@
1
+ module TxCatcher
2
+
3
+ class Logger
4
+
5
+ LOG_LEVELS = {
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ fatal: 4,
10
+ unknown: 5
11
+ }
12
+
13
+ class << self
14
+
15
+ def report(message, log_level=:info, data: nil, timestamp: false)
16
+ [:logfile, :stdout, :sentry].each do |out|
17
+ if LOG_LEVELS[log_level] >= LOG_LEVELS[Config["logger"]["#{out}_level"].to_sym]
18
+ send("report_to_#{out}", message, log_level, data: data, timestamp: timestamp)
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def report_to_stdout(message, log_level, data: nil, timestamp: timestamp)
26
+ $stdout.print prepare_message(message, timestamp: timestamp) + "\n"
27
+ $stdout.print " additional data: #{data.to_s}" if data
28
+ $stdout.print("\n\n") if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
29
+ end
30
+
31
+ def report_to_logfile(message, log_level, data: nil, timestamp: timestamp)
32
+ fn = LOG_LEVELS[log_level] >= LOG_LEVELS[:error] ? "error.log" : "txcatcher.log"
33
+ fn = TxCatcher::Config.config_dir + "/#{fn}"
34
+
35
+ File.open(fn, "a") do |f|
36
+ f.print "[#{log_level.to_s.upcase} #{Time.now.to_s}] #{prepare_message(message, timestamp: timestamp)}\n"
37
+ f.print " additional data: #{data.to_s}" if data
38
+ f.print("\n\n") if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
39
+ end
40
+ end
41
+
42
+ def report_to_sentry(e, log_level, data: nil, timestamp: timestamp)
43
+ e.kind_of?(Exception) ? Raven.capture_exception(e, extra: data) : Raven.capture_message(e, extra: data)
44
+ end
45
+
46
+ def prepare_message(e, timestamp: false)
47
+ result = if e.kind_of?(Exception)
48
+ result = e.to_s + "\n"
49
+ result += e.message + "\n\n" if e.message != e.to_s
50
+ result += (e.backtrace&.join("\n") || "[no backtrace]")
51
+ result
52
+ else
53
+ e
54
+ end
55
+ result = "[#{Time.now}] #{result}" if timestamp
56
+ result
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -62,9 +62,9 @@ module TxCatcher
62
62
  block_hash = TxCatcher.rpc_node.getblockhash(TxCatcher.current_block_height - i)
63
63
  block = TxCatcher.rpc_node.getblock(block_hash)
64
64
  i += 1
65
- $stdout.puts "--- checking block #{TxCatcher.current_block_height - i} for tx #{self.txid}"
65
+ Logger.report "--- checking block #{TxCatcher.current_block_height - i} for tx #{self.txid}"
66
66
  if block["tx"] && block["tx"].include?(self.txid)
67
- $stdout.puts "tx #{self.txid} block height updated to #{block["height"]}"
67
+ Logger.report "tx #{self.txid} block height updated to #{block["height"]}"
68
68
  self.update(block_height: block["height"])
69
69
  return block["height"].to_i
70
70
  end
data/lib/txcatcher.rb CHANGED
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'thread'
5
5
  require 'satoshi-unit'
6
6
  require 'sequel'
7
+ require 'sentry-raven'
7
8
  Sequel.extension :migration
8
9
 
9
10
  require_relative 'txcatcher/utils/hash_string_to_sym_keys'
@@ -12,6 +13,7 @@ require_relative 'txcatcher/config'
12
13
  require_relative 'txcatcher/initializer'
13
14
  require_relative 'txcatcher/catcher'
14
15
  require_relative 'txcatcher/cleaner'
16
+ require_relative 'txcatcher/logger'
15
17
 
16
18
  include TxCatcher::Initializer
17
19
  prepare
@@ -17,7 +17,17 @@ rpcnode:
17
17
  host: 127.0.0.1
18
18
  port: 8332
19
19
 
20
+ logger:
21
+ log_queue_info: false
22
+ stdout_level: info
23
+ logfile_level: info
24
+ sentry_level: info
25
+ sentry:
26
+ dsn: null
27
+ client_dsn: null
28
+
20
29
  # zeromq: bitcoind
21
30
  max_db_transactions_stored: 10
22
31
  db_clean_period_seconds: 300
23
32
  protected_transactions: true
33
+ environment: development
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require_relative 'spec_helper'
3
+
4
+ RSpec.describe TxCatcher::Logger do
5
+
6
+ describe "logging to logfiles" do
7
+
8
+ it "writes info messages to txcatcher.log" do
9
+ TxCatcher::Logger.report "example info message", :info
10
+ expect(File.read(LOGFILE)).to include("example info message")
11
+ end
12
+
13
+ it "writes errors into a separate error.log file" do
14
+ TxCatcher::Logger.report "example error message", :error
15
+ expect(File.read(ERRFILE)).to include("example error message")
16
+ end
17
+
18
+ end
19
+
20
+ describe "sending to Sentry" do
21
+
22
+ it "logs messages to Sentry" do
23
+ expect(Raven).to receive(:capture_message).once
24
+ TxCatcher::Logger.report "example info message", :info
25
+ TxCatcher::Logger.report "example error message", :error
26
+ end
27
+
28
+ it "logs errors to Sentry" do
29
+ expect(Raven).to receive(:capture_exception).once
30
+ TxCatcher::Logger.report StandardError.new, :error
31
+ end
32
+
33
+ end
34
+
35
+ it "logs to stdout" do
36
+ expect($stdout).to receive(:print).exactly(3).times
37
+ TxCatcher::Logger.report "example info message", :info
38
+ TxCatcher::Logger.report "example error message", :error
39
+ end
40
+
41
+ it "doesn't log an message if its loglevel is below current threshold" do
42
+ TxCatcher::Config["logger"]["stdout_level"] = "fatal"
43
+ expect($stdout).to receive(:print).exactly(2).times
44
+ TxCatcher::Logger.report "example info message", :info
45
+ TxCatcher::Logger.report "example warn message", :warn
46
+ TxCatcher::Logger.report "example error message", :error
47
+ TxCatcher::Logger.report "example fatal message", :fatal
48
+ TxCatcher::Config["logger"]["stdout_level"] = "info"
49
+ end
50
+
51
+ it "converts Exception into a text for logging" do
52
+ expect($stdout).to receive(:print).with("StandardError\n[no backtrace]\n")
53
+ expect($stdout).to receive(:print).with("\n\n")
54
+ TxCatcher::Logger.report StandardError.new, :error
55
+ end
56
+
57
+ it "prints additional data passed along" do
58
+ expect($stdout).to receive(:print).with("example error message\n")
59
+ expect($stdout).to receive(:print).with(' additional data: {:hello=>"world"}')
60
+ expect($stdout).to receive(:print).with("\n\n")
61
+ TxCatcher::Logger.report "example error message", :error, data: { hello: "world" }
62
+ end
63
+
64
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,11 +3,13 @@ require 'yaml'
3
3
  require 'json'
4
4
  require 'satoshi-unit'
5
5
  require 'sequel'
6
+ require 'sentry-raven'
6
7
  Sequel.extension :migration
7
8
 
8
9
  db_file = File.dirname(__FILE__) + "/config/txcatcher_test.db"
9
10
  File.delete(db_file) if File.exists?(db_file)
10
11
 
12
+ require_relative '../lib/txcatcher/logger'
11
13
  require_relative '../lib/txcatcher/utils/hash_string_to_sym_keys'
12
14
  require_relative '../lib/txcatcher/config'
13
15
  require_relative '../lib/txcatcher/initializer'
@@ -17,6 +19,7 @@ include TxCatcher::Initializer
17
19
  ConfigFile.set!(File.dirname(__FILE__) + "/config/config.yml")
18
20
 
19
21
  read_config_file
22
+ initialize_sentry
20
23
  connect_to_db
21
24
  run_migrations if migrations_pending?
22
25
  connect_to_rpc_node
@@ -31,8 +34,10 @@ end
31
34
 
32
35
  RSpec.configure do |config|
33
36
 
34
- config.default_formatter = 'doc'
37
+ LOGFILE = File.expand_path(File.dirname(__FILE__) + "/config/txcatcher.log")
38
+ ERRFILE = File.expand_path(File.dirname(__FILE__) + "/config/error.log")
35
39
 
40
+ config.default_formatter = 'doc'
36
41
  config.before(:all) do
37
42
  end
38
43
 
@@ -45,4 +50,10 @@ RSpec.configure do |config|
45
50
  TxCatcher::Address.select_all.delete
46
51
  end
47
52
 
53
+ config.after(:each) do
54
+ [LOGFILE, ERRFILE].each do |f|
55
+ FileUtils.rm(f) if File.exist?(f)
56
+ end
57
+ end
58
+
48
59
  end
data/templates/config.yml CHANGED
@@ -17,8 +17,18 @@ rpcnode:
17
17
  host: 127.0.0.1
18
18
  port: 8332
19
19
 
20
+ logger:
21
+ log_queue_info: false
22
+ stdout_level: info
23
+ logfile_level: warn
24
+ sentry_level: error
25
+ sentry:
26
+ dsn: null
27
+ client_dsn: null
28
+
20
29
  zeromq: bitcoind
21
30
  max_db_transactions_stored: 100000
22
31
  db_clean_period_seconds: 300
23
32
  server_port: 9498
24
33
  daemonize: false
34
+ environment: production
data/txcatcher.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: txcatcher 0.1.79 ruby lib
5
+ # stub: txcatcher 0.1.80 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "txcatcher"
9
- s.version = "0.1.79"
9
+ s.version = "0.1.80"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: txcatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.79
4
+ version: 0.1.80
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Snitko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-01 00:00:00.000000000 Z
11
+ date: 2018-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: goliath
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sentry-raven
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -130,6 +144,7 @@ files:
130
144
  - lib/txcatcher/cleaner.rb
131
145
  - lib/txcatcher/config.rb
132
146
  - lib/txcatcher/initializer.rb
147
+ - lib/txcatcher/logger.rb
133
148
  - lib/txcatcher/models/address.rb
134
149
  - lib/txcatcher/models/deposit.rb
135
150
  - lib/txcatcher/models/transaction.rb
@@ -140,6 +155,7 @@ files:
140
155
  - spec/config/config.yml.sample
141
156
  - spec/fixtures/transaction.txt
142
157
  - spec/fixtures/transaction_decoded_no_outputs.txt
158
+ - spec/logger_spec.rb
143
159
  - spec/models/transaction_spec.rb
144
160
  - spec/spec_helper.rb
145
161
  - templates/config.yml