sentry_fs 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/sentry_fs +79 -0
- data/lib/sentry_fs.rb +64 -0
- data/sentry_fs.gemspec +23 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/test_sentry_fs.rb +83 -0
- metadata +93 -0
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
|
data/test/test_helper.rb
ADDED
@@ -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:
|