sapience 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +2 -0
  5. data/.ruby-version +1 -0
  6. data/.simplecov +15 -0
  7. data/.travis.yml +27 -0
  8. data/CODE_OF_CONDUCT.md +49 -0
  9. data/Gemfile +12 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +43 -0
  12. data/Rakefile +13 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/lib/sapience/ansi_colors.rb +27 -0
  16. data/lib/sapience/appender/file.rb +138 -0
  17. data/lib/sapience/appender/sentry.rb +72 -0
  18. data/lib/sapience/appender/statsd.rb +68 -0
  19. data/lib/sapience/appender/wrapper.rb +74 -0
  20. data/lib/sapience/base.rb +381 -0
  21. data/lib/sapience/concerns/compatibility.rb +53 -0
  22. data/lib/sapience/configuration.rb +86 -0
  23. data/lib/sapience/core_ext/thread.rb +14 -0
  24. data/lib/sapience/formatters/base.rb +36 -0
  25. data/lib/sapience/formatters/color.rb +68 -0
  26. data/lib/sapience/formatters/default.rb +41 -0
  27. data/lib/sapience/formatters/json.rb +22 -0
  28. data/lib/sapience/formatters/raw.rb +12 -0
  29. data/lib/sapience/log.rb +221 -0
  30. data/lib/sapience/loggable.rb +29 -0
  31. data/lib/sapience/logger.rb +236 -0
  32. data/lib/sapience/rails.rb +15 -0
  33. data/lib/sapience/sapience.rb +357 -0
  34. data/lib/sapience/subscriber.rb +127 -0
  35. data/lib/sapience/version.rb +3 -0
  36. data/lib/sapience.rb +35 -0
  37. data/sapience.gemspec +39 -0
  38. data/test_app/.gitignore +42 -0
  39. data/test_app/.rspec +2 -0
  40. data/test_app/.ruby-version +1 -0
  41. data/test_app/Gemfile +36 -0
  42. data/test_app/README.md +24 -0
  43. data/test_app/Rakefile +6 -0
  44. data/test_app/app/assets/config/manifest.js +2 -0
  45. data/test_app/app/assets/images/.keep +0 -0
  46. data/test_app/app/assets/javascripts/posts.js +2 -0
  47. data/test_app/app/assets/stylesheets/application.css +15 -0
  48. data/test_app/app/assets/stylesheets/posts.css +4 -0
  49. data/test_app/app/assets/stylesheets/scaffold.css +84 -0
  50. data/test_app/app/channels/application_cable/channel.rb +4 -0
  51. data/test_app/app/channels/application_cable/connection.rb +4 -0
  52. data/test_app/app/controllers/application_controller.rb +3 -0
  53. data/test_app/app/controllers/concerns/.keep +0 -0
  54. data/test_app/app/controllers/posts_controller.rb +58 -0
  55. data/test_app/app/helpers/application_helper.rb +2 -0
  56. data/test_app/app/helpers/posts_helper.rb +2 -0
  57. data/test_app/app/jobs/application_job.rb +2 -0
  58. data/test_app/app/mailers/application_mailer.rb +4 -0
  59. data/test_app/app/models/application_record.rb +3 -0
  60. data/test_app/app/models/concerns/.keep +0 -0
  61. data/test_app/app/models/post.rb +3 -0
  62. data/test_app/app/models/user.rb +2 -0
  63. data/test_app/app/views/layouts/application.html.erb +13 -0
  64. data/test_app/app/views/layouts/mailer.html.erb +13 -0
  65. data/test_app/app/views/layouts/mailer.text.erb +1 -0
  66. data/test_app/app/views/posts/_form.html.erb +32 -0
  67. data/test_app/app/views/posts/create.html.erb +2 -0
  68. data/test_app/app/views/posts/destroy.html.erb +2 -0
  69. data/test_app/app/views/posts/edit.html.erb +6 -0
  70. data/test_app/app/views/posts/index.html.erb +31 -0
  71. data/test_app/app/views/posts/new.html.erb +5 -0
  72. data/test_app/app/views/posts/show.html.erb +19 -0
  73. data/test_app/app/views/posts/update.html.erb +2 -0
  74. data/test_app/bin/bundle +3 -0
  75. data/test_app/bin/rails +4 -0
  76. data/test_app/bin/rake +4 -0
  77. data/test_app/bin/setup +34 -0
  78. data/test_app/bin/update +29 -0
  79. data/test_app/config/application.rb +26 -0
  80. data/test_app/config/boot.rb +3 -0
  81. data/test_app/config/cable.yml +9 -0
  82. data/test_app/config/database.yml +25 -0
  83. data/test_app/config/environment.rb +5 -0
  84. data/test_app/config/environments/development.rb +49 -0
  85. data/test_app/config/environments/production.rb +78 -0
  86. data/test_app/config/environments/test.rb +42 -0
  87. data/test_app/config/initializers/application_controller_renderer.rb +6 -0
  88. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  89. data/test_app/config/initializers/cookies_serializer.rb +5 -0
  90. data/test_app/config/initializers/filter_parameter_logging.rb +4 -0
  91. data/test_app/config/initializers/inflections.rb +16 -0
  92. data/test_app/config/initializers/mime_types.rb +4 -0
  93. data/test_app/config/initializers/new_framework_defaults.rb +24 -0
  94. data/test_app/config/initializers/session_store.rb +3 -0
  95. data/test_app/config/initializers/wrap_parameters.rb +14 -0
  96. data/test_app/config/locales/en.yml +23 -0
  97. data/test_app/config/puma.rb +45 -0
  98. data/test_app/config/routes.rb +3 -0
  99. data/test_app/config/secrets.yml +22 -0
  100. data/test_app/config.ru +5 -0
  101. data/test_app/db/migrate/20160812092236_create_users.rb +13 -0
  102. data/test_app/db/migrate/20160812093621_create_posts.rb +11 -0
  103. data/test_app/db/schema.rb +33 -0
  104. data/test_app/db/seeds.rb +7 -0
  105. data/test_app/lib/assets/.keep +0 -0
  106. data/test_app/lib/tasks/.keep +0 -0
  107. data/test_app/log/.keep +0 -0
  108. data/test_app/public/404.html +67 -0
  109. data/test_app/public/422.html +67 -0
  110. data/test_app/public/500.html +66 -0
  111. data/test_app/public/apple-touch-icon-precomposed.png +0 -0
  112. data/test_app/public/apple-touch-icon.png +0 -0
  113. data/test_app/public/favicon.ico +0 -0
  114. data/test_app/public/robots.txt +5 -0
  115. data/test_app/spec/controllers/posts_controller_spec.rb +7 -0
  116. data/test_app/spec/helpers/posts_helper_spec.rb +15 -0
  117. data/test_app/spec/models/post_spec.rb +5 -0
  118. data/test_app/spec/models/user_spec.rb +5 -0
  119. data/test_app/spec/rails_helper.rb +23 -0
  120. data/test_app/spec/requests/posts_spec.rb +10 -0
  121. data/test_app/spec/routing/posts_routing_spec.rb +39 -0
  122. data/test_app/spec/spec_helper.rb +60 -0
  123. data/test_app/tmp/.keep +0 -0
  124. data/test_app/vendor/assets/stylesheets/.keep +0 -0
  125. metadata +298 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2b51a1bdbf72bc1ea60b09d75b32a6f78f0ed143
4
+ data.tar.gz: 87a7710812da15bc3cdb80eb2cdedd1681658cd8
5
+ SHA512:
6
+ metadata.gz: 25c9ac8836d07d4ec09623176e2b12b603be340073b7061f42d28e9378dfc853a8ea4fa667f31d2a544b3d7afe02508459f47759867f6a1dc32277862d18fb6b
7
+ data.tar.gz: a52fbcd6f66d607db46b44b074ff943b066a5fd88c5f03916745f395f9032334acd4839a9d612948fdd21e416e987beb424981ac6076f7e0d45935b7e02554d0
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ repo_token: 2pF5ERW8NKVYqrkGeGTvzGP7oYLidlQ41
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ Gemfile.lock
2
+ spec/examples.txt
3
+ coverage/
4
+ .DS_Store
5
+ .idea
6
+ log/
7
+
8
+ /.bundle/
9
+
10
+ **/*.sqlite3
11
+
12
+ **/examples.txt
13
+ **/*.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format Fuubar
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/.simplecov ADDED
@@ -0,0 +1,15 @@
1
+ require "simplecov-json"
2
+ require "coveralls"
3
+ Coveralls.wear!
4
+
5
+ SimpleCov.refuse_coverage_drop
6
+
7
+ SimpleCov.formatters = [
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ SimpleCov::Formatter::JSONFormatter,
10
+ ]
11
+ SimpleCov.start do
12
+ add_filter "/spec/"
13
+ add_filter "/bin/"
14
+ add_filter "/gemfiles/"
15
+ end
data/.travis.yml ADDED
@@ -0,0 +1,27 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ before_install:
5
+ - rvm get head
6
+ - gem update --system
7
+ - gem install bundler
8
+ install:
9
+ - bundle install -j8 -r3
10
+ script:
11
+ - if [[ "${STYLE}" = "true" ]]; then bundle exec rake reevoocop; fi;
12
+ - bundle exec rspec spec
13
+ rvm:
14
+ - jruby-9.0.5.0
15
+ - rbx-3.9
16
+ - 2.2.4
17
+ env: STYLE=false
18
+
19
+ matrix:
20
+ fast_finish: true
21
+ include:
22
+ - rvm: 2.3.1
23
+ env: STYLE=true
24
+
25
+ addons:
26
+ code_climate:
27
+ repo_token:
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at mikael@zoolutions.se. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sapience.gemspec
4
+ gemspec
5
+
6
+ gem "pry-nav"
7
+ gem "sentry-raven"
8
+ gem "statsd-ruby"
9
+ gem "minitest_to_rspec"
10
+ gem "transpec"
11
+ gem "codeclimate", require: false
12
+ gem 'coveralls', require: false
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Mikael Henriksson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Sapience
2
+
3
+ [![Code Climate](https://codeclimate.com/github/reevoo/sapience-rb/badges/gpa.svg)](https://codeclimate.com/github/reevoo/sapience-rb)[![Test Coverage](https://codeclimate.com/github/reevoo/sapience-rb/badges/coverage.svg)](https://codeclimate.com/github/reevoo/sapience-rb/coverage)[![Issue Count](https://codeclimate.com/github/reevoo/sapience-rb/badges/issue_count.svg)](https://codeclimate.com/github/reevoo/sapience-rb)
4
+
5
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sapience`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+
7
+ TODO: Delete this and the text above, and describe your gem
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'sapience'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install sapience
24
+
25
+ ## Usage
26
+
27
+ TODO: Write usage instructions here
28
+
29
+ ## Development
30
+
31
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
32
+
33
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/reevoo/sapience. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
38
+
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
43
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ begin
7
+ require "reevoocop/rake_task"
8
+ ReevooCop::RakeTask.new(:reevoocop) do |task|
9
+ task.options = ["-D"]
10
+ end
11
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
12
+ end
13
+ task default: [:reevocop, :spec]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sapience"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ module Sapience
2
+ # Formatting & colors used by optional color formatter
3
+ module AnsiColors
4
+ CLEAR = "\e[0m"
5
+ BOLD = "\e[1m"
6
+ BLACK = "\e[30m"
7
+ RED = "\e[31m"
8
+ GREEN = "\e[32m"
9
+ YELLOW = "\e[33m"
10
+ BLUE = "\e[34m"
11
+ MAGENTA = "\e[35m"
12
+ CYAN = "\e[36m"
13
+ WHITE = "\e[37m"
14
+
15
+ # Maps the log level to a color for colorized formatters
16
+ # Since this map is not frozen, it can be modified as needed
17
+ LEVEL_MAP = {
18
+ trace: MAGENTA,
19
+ debug: GREEN,
20
+ info: CYAN,
21
+ warn: BOLD,
22
+ error: RED,
23
+ fatal: RED,
24
+ }
25
+ end
26
+
27
+ end
@@ -0,0 +1,138 @@
1
+ # File appender
2
+ #
3
+ # Writes log messages to a file or open iostream
4
+ #
5
+ module Sapience
6
+ module Appender
7
+ class File < Sapience::Subscriber
8
+
9
+ # Create a File Logger appender instance.
10
+ #
11
+ # Parameters
12
+ # :file_name [String|IO]
13
+ # Name of file to write to.
14
+ # Or, an IO stream to which to write the log message to.
15
+ #
16
+ # :level [:trace | :debug | :info | :warn | :error | :fatal]
17
+ # Override the log level for this appender.
18
+ # Default: Sapience.config.default_level
19
+ #
20
+ # :formatter: [Object|Proc]
21
+ # An instance of a class that implements #call, or a Proc to be used to format
22
+ # the output from this appender
23
+ # Default: Use the built-in formatter (See: #call)
24
+ #
25
+ # :filter [Regexp|Proc]
26
+ # RegExp: Only include log messages where the class name matches the supplied
27
+ # regular expression. All other messages will be ignored.
28
+ # Proc: Only include log messages where the supplied Proc returns true
29
+ # The Proc must return true or false.
30
+ #
31
+ # Example
32
+ # require 'sapience'
33
+ #
34
+ # # Enable trace level logging
35
+ # Sapience.config.default_level = :info
36
+ #
37
+ # # Log to screen
38
+ # Sapience.add_appender(:file, io: STDOUT, formatter: :color)
39
+ #
40
+ # # And log to a file at the same time
41
+ # Sapience::Logger.add_appender(:file, file_name: 'application.log', formatter: :color)
42
+ #
43
+ # logger = Sapience['test']
44
+ # logger.info 'Hello World'
45
+ #
46
+ # Example 2. To log all levels to file and only :info and above to screen:
47
+ #
48
+ # require 'sapience'
49
+ #
50
+ # # Enable trace level logging
51
+ # Sapience.config.default_level = :trace
52
+ #
53
+ # # Log to screen but only display :info and above
54
+ # Sapience.add_appender(:file, io: STDOUT, level: :info)
55
+ #
56
+ # # And log to a file at the same time, including all :trace level data
57
+ # Sapience.add_appender(:file, file_name: 'application.log')
58
+ #
59
+ # logger = Sapience['test']
60
+ # logger.info 'Hello World'
61
+ def initialize(options = {}, deprecated_level = nil, deprecated_filter = nil, &block)
62
+ # Old style arguments: (file_name, level=nil, filter=nil, &block)
63
+ options =
64
+ if options.is_a?(Hash)
65
+ options.dup
66
+ else
67
+ file_name = options
68
+ opts = {}
69
+ if file_name.respond_to?(:write) && file_name.respond_to?(:close)
70
+ opts[:io] = file_name
71
+ else
72
+ opts[:file_name] = file_name
73
+ end
74
+ opts[:level] = deprecated_level if deprecated_level
75
+ opts[:filter] = deprecated_filter if deprecated_filter
76
+ opts
77
+ end
78
+
79
+ if io = options.delete(:io)
80
+ @log = io
81
+ else
82
+ @file_name = options.delete(:file_name)
83
+ fail "Sapience::Appender::File missing mandatory parameter :file_name or :io" unless @file_name
84
+ reopen
85
+ end
86
+
87
+ # Set the log level and formatter if supplied
88
+ super(options, &block)
89
+ end
90
+
91
+ # After forking an active process call #reopen to re-open
92
+ # open the file handles etc to resources
93
+ #
94
+ # Note: This method will only work if :file_name was supplied
95
+ # on the initializer.
96
+ # If :io was supplied, it will need to be re-opened manually.
97
+ def reopen
98
+ return unless @file_name
99
+ ensure_folder_exist
100
+
101
+ @log = open(@file_name, (::File::WRONLY | ::File::APPEND | ::File::CREAT))
102
+ # Force all log entries to write immediately without buffering
103
+ # Allows multiple processes to write to the same log file simultaneously
104
+ @log.sync = true
105
+ @log.set_encoding(Encoding::BINARY) if @log.respond_to?(:set_encoding)
106
+ @log
107
+ end
108
+
109
+ def ensure_folder_exist
110
+ return if ::File.exist?(@file_name)
111
+
112
+ dir_name = ::File.dirname(@file_name)
113
+
114
+ FileUtils.mkdir_p(dir_name)
115
+ end
116
+
117
+ # Pass log calls to the underlying Rails, log4j or Ruby logger
118
+ # trace entries are mapped to debug since :trace is not supported by the
119
+ # Ruby or Rails Loggers
120
+ def log(log)
121
+ return false unless should_log?(log)
122
+
123
+ # Since only one appender thread will be writing to the file at a time
124
+ # it is not necessary to protect access to the file with a semaphore
125
+ # Allow this logger to filter out log levels lower than it's own
126
+ @log.write(formatter.call(log, self) << "\n")
127
+ true
128
+ end
129
+
130
+ # Flush all pending logs to disk.
131
+ # Waits for all sent documents to be writted to disk
132
+ def flush
133
+ @log.flush if @log.respond_to?(:flush)
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,72 @@
1
+ begin
2
+ require "sentry-raven"
3
+ rescue LoadError
4
+ raise 'Gem sentry-raven is required for logging purposes. Please add the gem "sentry-raven" to your Gemfile.'
5
+ end
6
+
7
+ # Send log messages to sentry
8
+ #
9
+ # Example:
10
+ # Sapience.add_appender(:sentry, {})
11
+ #
12
+ class Sapience::Appender::Sentry < Sapience::Subscriber
13
+ # Create Appender
14
+ #
15
+ # Parameters
16
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
17
+ # Override the log level for this appender.
18
+ # Default: :error
19
+ #
20
+ # formatter: [Object|Proc|Symbol|Hash]
21
+ # An instance of a class that implements #call, or a Proc to be used to format
22
+ # the output from this appender
23
+ # Default: Use the built-in formatter (See: #call)
24
+ #
25
+ # filter: [Regexp|Proc]
26
+ # RegExp: Only include log messages where the class name matches the supplied.
27
+ # regular expression. All other messages will be ignored.
28
+ # Proc: Only include log messages where the supplied Proc returns true
29
+ # The Proc must return true or false.
30
+ #
31
+ # host: [String]
32
+ # Name of this host to appear in log messages.
33
+ # Default: Sapience.config.host
34
+ #
35
+ # application: [String]
36
+ # Name of this application to appear in log messages.
37
+ # Default: Sapience.config.application
38
+ def initialize(options = {}, &block)
39
+ options = options.is_a?(Hash) ? options.dup : { level: options }
40
+ options[:level] ||= :error
41
+
42
+ super(options, &block)
43
+ end
44
+
45
+ # Send an error notification to sentry
46
+ def log(log)
47
+ return false unless should_log?(log)
48
+
49
+ context = formatter.call(log, self)
50
+ if log.exception
51
+ context.delete(:exception)
52
+ Raven.capture_exception(log.exception, context)
53
+ else
54
+ message = {
55
+ error_class: context.delete(:name),
56
+ error_message: context.delete(:message),
57
+ context: context,
58
+ }
59
+ message[:backtrace] = log.backtrace if log.backtrace
60
+ Raven.capture_message(message[:error_message], message)
61
+ end
62
+ true
63
+ end
64
+
65
+ private
66
+
67
+ # Use Raw Formatter by default
68
+ def default_formatter
69
+ Sapience::Formatters::Raw.new
70
+ end
71
+
72
+ end
@@ -0,0 +1,68 @@
1
+ require "uri"
2
+ begin
3
+ require "statsd-ruby"
4
+ rescue LoadError
5
+ raise 'Gem statsd-ruby is required for logging metrics. Please add the gem "statsd-ruby" to your Gemfile.'
6
+ end
7
+
8
+ # Example:
9
+ # Sapience.add_appender(:statsd, {url: "udp://localhost:2222"})
10
+ #
11
+ class Sapience::Appender::Statsd < Sapience::Subscriber
12
+ # Create Appender
13
+ #
14
+ # Parameters:
15
+ # url: [String]
16
+ # Valid URL to post to.
17
+ # Example:
18
+ # udp://localhost:8125
19
+ # Example, send all metrics to a particular namespace:
20
+ # udp://localhost:8125/namespace
21
+ # Default: udp://localhost:8125
22
+ def initialize(options = {}, &block)
23
+ options = options.is_a?(Hash) ? options.dup : { level: options }
24
+ url = options.delete(:url) || "udp://localhost:8125"
25
+ uri = URI.parse(url)
26
+ fail('Statsd only supports udp. Example: "udp://localhost:8125"') if uri.scheme != "udp"
27
+
28
+ @statsd = ::Statsd.new(uri.host, uri.port)
29
+ path = uri.path.chomp("/")
30
+ @statsd.namespace = path.sub("/", "") if path != ""
31
+
32
+ super(options, &block)
33
+ end
34
+
35
+ # Send an error notification to sentry
36
+ def log(log)
37
+ metric = log.metric
38
+ return false unless metric
39
+
40
+ if log.duration
41
+ timing(metric, log.duration)
42
+ else
43
+ amount = (log.metric_amount || 1).round
44
+ if amount < 0
45
+ decrement(metric, amount)
46
+ else
47
+ increment(metric, amount)
48
+ end
49
+ end
50
+ true
51
+ end
52
+
53
+ def timing(metric, duration)
54
+ @statsd.timing(metric, duration)
55
+ end
56
+
57
+ def increment(metric, amount)
58
+ @statsd.batch do
59
+ amount.times { @statsd.increment(metric) }
60
+ end
61
+ end
62
+
63
+ def decrement(metric, amount)
64
+ @statsd.batch do
65
+ amount.abs.times { @statsd.decrement(metric) }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,74 @@
1
+ # Send log messages to any standard Ruby logging class.
2
+ #
3
+ # Forwards logging call to loggers such as Logger, log4r, etc.
4
+ #
5
+ module Sapience
6
+ module Appender
7
+ class Wrapper < Sapience::Subscriber
8
+ attr_reader :logger
9
+
10
+ # Forward all logging calls to the supplied logging instance.
11
+ #
12
+ # Parameters
13
+ # logger: [Object]
14
+ # Instance of an existing logger conforming to the Ruby Logger methods.
15
+ #
16
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
17
+ # Override the log level for this appender.
18
+ # Default: Sapience.config.default_level
19
+ #
20
+ # formatter: [Object|Proc]
21
+ # An instance of a class that implements #call, or a Proc to be used to format
22
+ # the output from this appender
23
+ # Default: Use the built-in formatter (See: #call)
24
+ #
25
+ # filter: [Regexp|Proc]
26
+ # RegExp: Only include log messages where the class name matches the supplied.
27
+ # regular expression. All other messages will be ignored.
28
+ # Proc: Only include log messages where the supplied Proc returns true
29
+ # The Proc must return true or false.
30
+ #
31
+ # Ruby Logger
32
+ # require 'logger'
33
+ # require 'sapience'
34
+ #
35
+ # ruby_logger = Logger.new(STDOUT)
36
+ # Sapience.add_appender(:wrapper, logger: ruby_logger)
37
+ #
38
+ # logger = Sapience['test']
39
+ # logger.info('Hello World', some: :payload)
40
+ #
41
+ def initialize(options, &block)
42
+ # Backward compatibility
43
+ options = { logger: options } unless options.is_a?(Hash)
44
+ options = options.dup
45
+ @logger = options.delete(:logger)
46
+
47
+ # Check if the custom appender responds to all the log levels. For example Ruby ::Logger
48
+ if does_not_implement = LEVELS[1..-1].find { |i| !@logger.respond_to?(i) }
49
+ fail(ArgumentError, "Supplied logger does not implement:#{does_not_implement}. It must implement all of #{LEVELS[1..-1].inspect}")
50
+ end
51
+
52
+ fail "Sapience::Appender::Wrapper missing mandatory parameter :logger" unless @logger
53
+ super(options, &block)
54
+ end
55
+
56
+ # Pass log calls to the underlying Rails, log4j or Ruby logger
57
+ # trace entries are mapped to debug since :trace is not supported by the
58
+ # Ruby or Rails Loggers
59
+ def log(log)
60
+ return false unless should_log?(log)
61
+
62
+ @logger.send(log.level == :trace ? :debug : log.level, formatter.call(log, self))
63
+ true
64
+ end
65
+
66
+ # Flush all pending logs to disk.
67
+ # Waits for all sent documents to be writted to disk
68
+ def flush
69
+ @logger.flush if @logger.respond_to?(:flush)
70
+ end
71
+
72
+ end
73
+ end
74
+ end