fluent-plugin-sentry 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ vendor/*
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.1.0
5
+ - 2.0.0
6
+ - 1.9.3
7
+
8
+ before_script:
9
+ - export RAILS_ENV=default
10
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-sentry.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2014- Kentaro Yoshida
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # fluent-plugin-sentry [![Build Status](https://travis-ci.org/y-ken/fluent-plugin-sentry.png?branch=master)](https://travis-ci.org/y-ken/fluent-plugin-sentry)
2
+
3
+ ## Overview
4
+
5
+ Fluentd output plugin to send aggregated errors/exception events to Sentry which are a realtime event logging and aggregation platform.<br>
6
+
7
+ If you have sent events to Sentry directory from front webpage without aggregation, you may got down response time and performance problem (e.g. PHP).<br>
8
+ To use Sentry and Fluentd together, it will got best perfomance because Fluentd acts messege queue for Sentry.
9
+
10
+ * [Sentry Official web](https://getsentry.com/welcome/)
11
+ * [Sentry Documents](http://sentry.readthedocs.org/en/latest/) [Screenshots](https://github.com/getsentry/sentry#screenshots)
12
+
13
+ ## Installation
14
+
15
+ install with gem or fluent-gem command as:
16
+
17
+ `````
18
+ ### native gem
19
+ gem install fluent-plugin-sentry
20
+
21
+ ### td-agent gem
22
+ /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-sentry
23
+ `````
24
+
25
+ ## Preparation
26
+
27
+ create sentry dashboard first. It could start with cost free!!
28
+
29
+ * Create an account at https://getsentry.com/pricing/
30
+
31
+ OR
32
+
33
+ * Launch Sentry at the self manager server with https://github.com/getsentry/sentry
34
+
35
+ ## Usage
36
+
37
+ ```xml
38
+ <source>
39
+ type forward
40
+ </source>
41
+
42
+ <match notify.**>
43
+ type sentry
44
+
45
+ # Set endpoint API URL
46
+ endpoint_url https://${api_key}:${api_password}@app.getsentry.com/${project_id}
47
+
48
+ # Set default events value of 'server_name'
49
+ hostname_command hostname -s
50
+
51
+ # rewrite shown tag name for Sentry dashboard
52
+ remove_tag_prefix notify.
53
+ </match>
54
+ ```
55
+
56
+ ## Parameters
57
+
58
+ * endpoint_url (Required)<br>
59
+ Set endpoint API URL which shows at Sentry dashboard. (it is not sentry account information)
60
+
61
+ * default_level<br>
62
+ [default] error
63
+
64
+ * defalut_logger<br>
65
+ [default] flunetd
66
+
67
+ * hostname_command<br>
68
+ Set default frontend value of 'server_name'
69
+
70
+ * flush_interval<br>
71
+ [default] 0sec
72
+
73
+ It also support rewriting Tag with SetTagKeyMixin.
74
+
75
+ * remove_tag_prefix
76
+ * remove_tag_suffix
77
+ * add_tag_prefix
78
+ * add_tag_suffix
79
+
80
+ ## Blog Articles
81
+
82
+ ## TODO
83
+
84
+ Pull requests are very welcome!!
85
+
86
+ ## Copyright
87
+
88
+ Copyright © 2014- Kentaro Yoshida ([@yoshi_ken](https://twitter.com/yoshi_ken))
89
+
90
+ ## License
91
+
92
+ Apache License, Version 2.0
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ Rake::TestTask.new(:test) do |test|
4
+ test.libs << 'lib' << 'test'
5
+ test.pattern = 'test/**/test_*.rb'
6
+ test.verbose = true
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-sentry"
7
+ spec.version = "0.0.1"
8
+ spec.authors = ["Kentaro Yoshida"]
9
+ spec.email = ["y.ken.studio@gmail.com"]
10
+ spec.summary = %q{Fluentd output plugin to send aggregated errors/exception events to sentry which are a realtime event logging and aggregation platform.}
11
+ spec.homepage = "https://github.com/y-ken/fluent-plugin-sentry"
12
+ spec.license = "Apache License, Version 2.0"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "webmock"
22
+ spec.add_runtime_dependency "fluentd"
23
+ spec.add_runtime_dependency "sentry-raven"
24
+ end
@@ -0,0 +1,81 @@
1
+ class Fluent::SentryOutput < Fluent::BufferedOutput
2
+ Fluent::Plugin.register_output('sentry', self)
3
+
4
+ include Fluent::HandleTagNameMixin
5
+
6
+ LOG_LEVEL = %w(fatal error warning info debug)
7
+ EVENT_KEYS = %w(logger level tags modules message)
8
+ DEFAULT_HOSTNAME_COMMAND = 'hostname'
9
+
10
+ config_param :default_level, :string, :default => 'error'
11
+ config_param :default_logger, :string, :default => 'fluentd'
12
+ config_param :endpoint_url, :string
13
+ config_param :flush_interval, :time, :default => 0
14
+ config_param :hostname_command, :string, :default => 'hostname'
15
+
16
+ def initialize
17
+ require 'time'
18
+ require 'raven'
19
+
20
+ super
21
+ end
22
+
23
+ def configure(conf)
24
+ super
25
+
26
+ if @endpoint_url.nil?
27
+ raise Fluent::ConfigError, "sentry: missing parameter for 'endpoint_url'"
28
+ end
29
+
30
+ unless LOG_LEVEL.include?(@default_level)
31
+ raise Fluent::ConfigError, "sentry: unsupported default reporting log level for 'default_level'"
32
+ end
33
+
34
+ hostname_command = @hostname_command || DEFAULT_HOSTNAME_COMMAND
35
+ hostname = `#{hostname_command}`.chomp
36
+
37
+ @configuration = Raven::Configuration.new
38
+ @configuration.server = @endpoint_url
39
+ @configuration.server_name = hostname
40
+ @client = Raven::Client.new(@configuration)
41
+ end
42
+
43
+ def start
44
+ super
45
+ end
46
+
47
+ def format(tag, time, record)
48
+ [tag, time, record].to_msgpack
49
+ end
50
+
51
+ def shutdown
52
+ super
53
+ end
54
+
55
+ def write(chunk)
56
+ chunk.msgpack_each do |tag, time, record|
57
+ begin
58
+ notify_sentry(tag, time, record)
59
+ rescue => e
60
+ $log.error("Sentry Error:", :error_class => e.class, :error => e.message)
61
+ end
62
+ end
63
+ end
64
+
65
+ def notify_sentry(tag, time, record)
66
+ event = Raven::Event.new(
67
+ :configuration => @configuration,
68
+ :context => Raven::Context.new,
69
+ :message => record['message']
70
+ )
71
+ event.timestamp = Time.at(time).utc.strftime('%Y-%m-%dT%H:%M:%S')
72
+ event.logger = record['logger'] || @default_logger
73
+ event.level = record['level'] || @default_level
74
+ event.tags = record['tags'] || { :tag => tag }
75
+ event.extra = record.reject{ |key| EVENT_KEYS.include?(key) }
76
+ event.modules = record['modules'] || nil
77
+ event.platform = record['platform'] if record['platform']
78
+ event.server_name = record['server_name'] if record['server_name']
79
+ @client.send(event)
80
+ end
81
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/plugin/out_sentry'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,69 @@
1
+ require 'helper'
2
+ require 'webmock/test_unit'
3
+ require 'yajl'
4
+
5
+ WebMock.disable_net_connect!
6
+
7
+ class SentryOutputTest < Test::Unit::TestCase
8
+ def setup
9
+ Fluent::Test.setup
10
+ end
11
+
12
+ CONFIG = %[
13
+ type sentry
14
+ endpoint_url https://user:password@app.getsentry.com/12345
15
+ hostname_command hostname -s
16
+ remove_tag_prefix input.
17
+ ]
18
+
19
+ def create_driver(conf=CONFIG,tag='test')
20
+ Fluent::Test::OutputTestDriver.new(Fluent::SentryOutput, tag).configure(conf)
21
+ end
22
+
23
+ def stub_endpoint(url="https://app.getsentry.com/api/12345/store/")
24
+ parser = Yajl::Parser.new
25
+ stub_request(:post, url).with do |req|
26
+ @content_type = req.headers["Content-Type"]
27
+ @body = parser.parse(req.body)
28
+ end
29
+ end
30
+
31
+ def test_configure
32
+ assert_raise(Fluent::ConfigError) {
33
+ d = create_driver('')
34
+ }
35
+ d = create_driver(CONFIG)
36
+ assert_equal 'https://user:password@app.getsentry.com/12345', d.instance.config['endpoint_url']
37
+ end
38
+
39
+ def test_emit
40
+ stub_endpoint
41
+ d1 = create_driver(CONFIG, 'input.app1_error')
42
+ emit_level = 'warning'
43
+ emit_message = 'error has occoured.'
44
+ emit_extra = {'foo' => {'array' => [1,2,3]}, 'hash' => {'nest' => 'data'}}
45
+ d1.run do
46
+ d1.emit({
47
+ 'level' => emit_level,
48
+ 'message' => emit_message,
49
+ 'something' => emit_extra
50
+ })
51
+ end
52
+ p @body
53
+ emits = d1.emits
54
+ assert_equal 0, emits.length
55
+ assert_equal 'application/json', @content_type
56
+ assert_equal emit_message, @body['message']
57
+ timestamp = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S')
58
+ assert_equal timestamp, @body['timestamp']
59
+ assert_equal emit_level, @body['level']
60
+ assert_equal '12345', @body['project']
61
+ assert_equal 'fluentd', @body['logger']
62
+ assert_equal 'ruby', @body['platform']
63
+ assert_equal 'app1_error', @body['tags'][':tag']
64
+ hostname = `#{d1.instance.config['hostname_command']}`.chomp
65
+ assert_equal hostname, @body['server_name']
66
+ extra_message = {'something' => emit_extra}
67
+ assert_equal extra_message, @body['extra']
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-sentry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kentaro Yoshida
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: webmock
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: fluentd
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: sentry-raven
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description:
95
+ email:
96
+ - y.ken.studio@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - .travis.yml
103
+ - Gemfile
104
+ - LICENSE
105
+ - README.md
106
+ - Rakefile
107
+ - fluent-plugin-sentry.gemspec
108
+ - lib/fluent/plugin/out_sentry.rb
109
+ - test/helper.rb
110
+ - test/plugin/test_out_sentry.rb
111
+ homepage: https://github.com/y-ken/fluent-plugin-sentry
112
+ licenses:
113
+ - Apache License, Version 2.0
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.23
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Fluentd output plugin to send aggregated errors/exception events to sentry
136
+ which are a realtime event logging and aggregation platform.
137
+ test_files:
138
+ - test/helper.rb
139
+ - test/plugin/test_out_sentry.rb