sentry_fs 0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a7385144932acf7cdd009fbb6713e7527cb67d2
4
+ data.tar.gz: 347b2e26ade28383bc1ae89c9ac46dce2d178eed
5
+ SHA512:
6
+ metadata.gz: 07050064749397a234c45643b51f0b9f99139fa4d67d21380cce86bf317a7e6b78eceddf899cf3fbf55ab633fc9416d96a6f90f569ff50f0d814e5e2a5396411
7
+ data.tar.gz: 5f7d27f2ed638e61440972f73179cf82ee4b15401482f83671ef276361797f4f9ccd2e89d00e215494d7fb0c5d0cf734de03913faa8e2201d05b34a7049aa2c0
data/bin/sentry_fs ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "logger"
5
+ require "raven"
6
+ require "file/tail"
7
+ require "sentry_fs"
8
+
9
+ logger = Logger.new(STDOUT)
10
+ options = {}
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: sentry_fs [options]"
14
+
15
+ opts.on("--fslog PATH", "PATH to FreeSWITCH log") {|path|
16
+ options[:fs_log] = path
17
+ }
18
+
19
+ opts.on("--dsn DSN", "Sentry DSN") {|dsn|
20
+ options[:dsn] = dsn
21
+ }
22
+
23
+ opts.on("--log PATH", "PATH to sentry_fs log") {|path|
24
+ logger = Logger.new(path)
25
+ }
26
+
27
+ opts.on("--daemon", "Run in background") {|daemon|
28
+ options[:daemon] = daemon
29
+ }
30
+
31
+ opts.on("--pidfile PATH", "PATH to pidfile") {|path|
32
+ options[:pidfile] = path
33
+ }
34
+ end.parse!
35
+
36
+ if !options[:fs_log]
37
+ $stderr.puts "--fslog required"
38
+ exit 1
39
+ end
40
+
41
+ if !options[:dsn]
42
+ $stderr.puts "--dsn required"
43
+ exit 2
44
+ end
45
+
46
+ if !File.exists?(options[:fs_log])
47
+ $stderr.puts "#{options[:fs_log]} does not exist"
48
+ exit 3
49
+ end
50
+
51
+ if options[:daemon]
52
+ Process.daemon(nochdir=true)
53
+ end
54
+
55
+ if options[:pidfile]
56
+ File.open(options[:pidfile], "w") {|f| f.write(Process.pid)}
57
+ end
58
+
59
+ Raven.configure do |config|
60
+ config.dsn = options[:dsn]
61
+ config.logger = logger
62
+ config.current_environment = "production"
63
+ end
64
+
65
+ File.open(options[:fs_log]) do |log|
66
+ log.extend(File::Tail)
67
+ log.interval = 10
68
+ log.backward 0
69
+ log.tail {|line|
70
+ begin
71
+ event = SentryFS.parse(line)
72
+ SentryFS.capture(event) if event
73
+ rescue => e
74
+ logger.error line
75
+ logger.error e.message
76
+ logger.error e.backtrace
77
+ end
78
+ }
79
+ end
data/lib/sentry_fs.rb ADDED
@@ -0,0 +1,64 @@
1
+ require "json"
2
+
3
+ module SentryFS
4
+ class Event
5
+ attr_reader :uuid
6
+ attr_reader :message
7
+ attr_reader :extra
8
+ attr_reader :full_message
9
+ attr_reader :level
10
+
11
+ def initialize(uuid:, message:, extra: {}, full_message: nil, level: "err")
12
+ @uuid = uuid
13
+ @message = message
14
+ @extra = extra
15
+ @full_message = full_message
16
+ @level = level
17
+ end
18
+ end
19
+
20
+ EXPRESSIONS = {
21
+ global: /\A\S+ \S+ \[(?<level>WARNING|ALERT|CRIT|ERR)\] (?<line>\S+) (?<message>.*)\z/,
22
+ session: /\A(?<uuid>\S+) \S+ \S+ \[(?<level>WARNING|ALERT|CRIT|ERR)\] (?<line>\S+) (?<message>.*)\z/,
23
+ odbc: /\A(?<message>.*CODE.*ERROR.*)\z/
24
+ }
25
+
26
+ def self.parse(log_line)
27
+ log_line.chomp!
28
+ EXPRESSIONS.each {|name, regexp|
29
+ match = log_line.match(regexp)
30
+ if match
31
+ uuid = match.names.include?("uuid") ? match[:uuid] : nil
32
+ line = match.names.include?("line") ? match[:line] : nil
33
+ level = match.names.include?("level") ? match[:level].downcase : "err"
34
+ begin
35
+ json = JSON.parse(match[:message])
36
+ message = json["message"]
37
+ extra = json["extra"]
38
+ rescue JSON::ParserError
39
+ message = [line, match[:message]].compact.join(" ")
40
+ extra = {}
41
+ end
42
+ event = Event.new(
43
+ uuid: uuid,
44
+ message: message,
45
+ full_message: log_line,
46
+ extra: extra,
47
+ level: level
48
+ )
49
+ return event
50
+ end
51
+ }
52
+ nil
53
+ end
54
+
55
+ def self.capture(event)
56
+ Raven.capture_message(event.message, {
57
+ level: event.level,
58
+ extra: {
59
+ uuid: event.uuid,
60
+ full_message: event.full_message
61
+ }.merge(event.extra)
62
+ })
63
+ end
64
+ end
data/sentry_fs.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "sentry_fs"
3
+ s.version = "0.6"
4
+ s.date = "2015-10-21"
5
+ s.summary = "Parse FreeSWITCH logs and report errors to Sentry"
6
+ s.email = "hv@firmafon.dk"
7
+ s.homepage = "http://github.com/firmafon/sentry_fs"
8
+ s.description = "Parse FreeSWITCH logs and report errors to Sentry"
9
+ s.authors = ["Harry Vangberg"]
10
+ s.executables = ["sentry_fs"]
11
+ s.files = [
12
+ "sentry_fs.gemspec",
13
+ "lib/sentry_fs.rb",
14
+ "bin/sentry_fs"
15
+ ]
16
+ s.test_files = [
17
+ "test/test_helper.rb",
18
+ "test/unit/test_sentry_fs.rb"
19
+ ]
20
+ s.add_dependency "file-tail", "~> 1.0"
21
+ s.add_dependency "sentry-raven", "~> 0.14.0"
22
+ s.add_dependency "json"
23
+ end
@@ -0,0 +1,2 @@
1
+ require "minitest/autorun"
2
+ require "sentry_fs"
@@ -0,0 +1,83 @@
1
+ require "test_helper"
2
+
3
+ class TestSentryFS < MiniTest::Unit::TestCase
4
+ LOG_LEVELS = %w(WARNING ALERT CRIT ERR)
5
+
6
+ LOG_LEVELS.each do |level|
7
+ define_method(:"test_parse_global_#{level}") do
8
+ log = "2013-03-19 10:41:53.556663 [#{level}] mod_db.c:117 Error Opening DB\n"
9
+ event = SentryFS.parse(log)
10
+
11
+ assert_nil event.uuid
12
+ assert_equal "mod_db.c:117 Error Opening DB", event.message
13
+ assert_equal log, event.full_message
14
+ assert_equal level.downcase, event.level
15
+ end
16
+ end
17
+
18
+ LOG_LEVELS.each do |level|
19
+ define_method(:"test_parse_session_#{level}") do
20
+ log = "447d3058-90be-11e2-906b-d954932e9cdf 2013-03-19 10:56:04.307690 [#{level}] mod_sofia.c:4224 Invalid Gateway\n"
21
+ event = SentryFS.parse(log)
22
+
23
+ assert_equal "447d3058-90be-11e2-906b-d954932e9cdf", event.uuid
24
+ assert_equal "mod_sofia.c:4224 Invalid Gateway", event.message
25
+ assert_equal log, event.full_message
26
+ assert_equal level.downcase, event.level
27
+ end
28
+ end
29
+
30
+ def test_parse_global_json_error
31
+ log = '2013-03-19 10:41:53.556663 [ERR] utils.js:123 {"message":"error 123", "extra": {"some_var":"some_data"}}' + "\n"
32
+ event = SentryFS.parse(log)
33
+
34
+ assert_nil event.uuid
35
+ assert_equal "error 123", event.message
36
+ assert_equal log, event.full_message
37
+ assert_equal({"some_var" => "some_data"}, event.extra)
38
+ assert_equal "err", event.level
39
+ end
40
+
41
+ def test_parse_session_json_error
42
+ log = '447d3058-90be-11e2-906b-d954932e9cdf 2013-03-19 10:56:04.307690 [ERR] utils.js:123 {"message":"error 123", "extra":{"some_var":"some_data"}}' + "\n"
43
+ event = SentryFS.parse(log)
44
+
45
+ assert_equal "447d3058-90be-11e2-906b-d954932e9cdf", event.uuid
46
+ assert_equal "error 123", event.message
47
+ assert_equal log, event.full_message
48
+ assert_equal({"some_var" => "some_data"}, event.extra)
49
+ assert_equal "err", event.level
50
+ end
51
+
52
+ def test_parse_odbc_error_without_timestamp
53
+ log = "[STATE: 42S22 CODE 1054 ERROR: [unixODBC][MySQL][ODBC 3.51 Driver][mysqld-5.1.39-ndb-7.0.9-1ubuntu7]Unknown column 'undefined' in 'where clause'\n"
54
+
55
+ event = SentryFS.parse(log)
56
+
57
+ assert_nil event.uuid
58
+ assert_equal log, event.message
59
+ assert_equal log, event.full_message
60
+ assert_equal "err", event.level
61
+ end
62
+
63
+ def test_parse_odbc_error_with_timestamp
64
+ log = "2013-04-24 07:28:09.347700 [ERR] switch_core_sqldb.c:476 SQL ERR [STATE: HY000 CODE 1205 ERROR: [unixODBC][MySQL][ODBC 3.51 Driver][mysqld-5.1.39-ndb-7.0.9-1ubuntu7]Lock wait timeout exceeded; try restarting transaction\n"
65
+
66
+ event = SentryFS.parse(log)
67
+
68
+ message = "switch_core_sqldb.c:476 SQL ERR [STATE: HY000 CODE 1205 ERROR: [unixODBC][MySQL][ODBC 3.51 Driver][mysqld-5.1.39-ndb-7.0.9-1ubuntu7]Lock wait timeout exceeded; try restarting transaction"
69
+
70
+ assert_nil event.uuid
71
+ assert_equal message, event.message
72
+ assert_equal log, event.full_message
73
+ assert_equal "err", event.level
74
+ end
75
+
76
+ def test_parse_something_else
77
+ log = "0ea0aa02-acd2-11e2-87e3-2f16ea487161 EXECUTE sofia/external/22334455@192.168.90.1 javascript(voicemail.js 4571992020)\n"
78
+
79
+ event = SentryFS.parse(log)
80
+
81
+ assert_nil event
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sentry_fs
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.6'
5
+ platform: ruby
6
+ authors:
7
+ - Harry Vangberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: file-tail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sentry-raven
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.14.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.14.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Parse FreeSWITCH logs and report errors to Sentry
56
+ email: hv@firmafon.dk
57
+ executables:
58
+ - sentry_fs
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/sentry_fs
63
+ - lib/sentry_fs.rb
64
+ - sentry_fs.gemspec
65
+ - test/test_helper.rb
66
+ - test/unit/test_sentry_fs.rb
67
+ homepage: http://github.com/firmafon/sentry_fs
68
+ licenses: []
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.4.5
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Parse FreeSWITCH logs and report errors to Sentry
90
+ test_files:
91
+ - test/test_helper.rb
92
+ - test/unit/test_sentry_fs.rb
93
+ has_rdoc: