yell-2.2.2/0000755000004100000410000000000013622502024012506 5ustar www-datawww-datayell-2.2.2/.travis.yml0000644000004100000410000000052513622502024014621 0ustar www-datawww-datalanguage: ruby before_install: gem install bundler script: "bundle exec rspec" matrix: include: - rvm: ruby-head - rvm: 2.6 - rvm: 2.5 - rvm: 2.4 - rvm: 2.3 - rvm: jruby-9.1 - rvm: jruby-9.2 allow_failures: - rvm: ruby-head - rvm: jruby-head notifications: on_success: change on_failure: change yell-2.2.2/README.md0000644000004100000410000001572013622502024013772 0ustar www-datawww-data# Yell [![Gem Version](https://badge.fury.io/rb/yell.svg)](http://badge.fury.io/rb/yell) [![Build Status](https://travis-ci.org/rudionrails/yell.svg?branch=master)](https://travis-ci.org/rudionrails/yell) [![Code Climate](https://codeclimate.com/github/rudionrails/yell.svg)](https://codeclimate.com/github/rudionrails/yell) [![Coverage Status](https://coveralls.io/repos/rudionrails/yell/badge.svg?branch=master)](https://coveralls.io/r/rudionrails/yell) **Yell - Your Extensible Logging Library** is a comprehensive logging replacement for Ruby. Yell works and its test suite currently runs on: - ruby-head, 2.3.1, 2.2.5, 2.2.2, 2.1.0, 2.0.0 - jruby-head, jruby-9.1.0.0, jruby-9.0.0.0 If you want to conveniently use Yell with Rails, then head over to [yell-rails](https://github.com/rudionrails/yell-rails). You'll find all the documentation in this repository, though. ## Installation System wide: ```console gem install yell ``` Or in your Gemfile: ```ruby gem "yell" ``` ## Usage On the basics, you can use Yell just like any other logging library with a more sophisticated message formatter. ```ruby logger = Yell.new STDOUT logger.info "Hello World" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World" # ^ ^ ^ ^ # ISO8601 Timestamp Level Pid Message ``` The strength of Yell, however, comes when using multiple adapters. The already built-in ones are IO-based and require no further configuration. Also, there are additional ones available as separate gems. Please consult the [wiki](https://github.com/rudionrails/yell/wiki) on that - they are listed there. The standard adapters are: `:stdout` : Messages will be written to STDOUT `:stderr` : Messages will be written to STDERR `:file` : Messages will be written to a file `:datefile` : Messages will be written to a timestamped file Here are some short examples on how to combine them: ##### Example: Notice messages go into `STDOUT` and error messages into `STDERR` ```ruby logger = Yell.new do |l| l.adapter STDOUT, level: [:debug, :info, :warn] l.adapter STDERR, level: [:error, :fatal] end ``` ##### Example: Typical production Logger We setup a logger that starts passing messages at the `:info` level. Severities below `:error` go into the 'production.log', whereas anything higher is written into the 'error.log'. ```ruby logger = Yell.new do |l| l.level = 'gte.info' # will only pass :info and above to the adapters l.adapter :datefile, 'production.log', level: 'lte.warn' # anything lower or equal to :warn l.adapter :datefile, 'error.log', level: 'gte.error' # anything greater or equal to :error end ``` ##### Example: Typical production Logger for Heroku When deploying to Heroku, the "rails_log_stdout" gem gets injected to your Rails project. Yell does not need that when properly configured (see [yell-rails](https://github.com/rudionrails/yell-rails) for a more convenient integration with Rails). ```ruby logger = Yell.new do |l| l.level = 'gte.info' l.adapter :stdout, level: 'lte.warn' l.adapter :stderr, level: 'gte.error' end ``` ### But I'm used to Log4r and I don't want to move on One of the really nice features of Log4r is its repository. The following example is taken from the official Log4r [documentation](http://log4r.rubyforge.org/manual.html#outofbox). ```ruby require 'log4r' include Log4r # create a logger named 'mylog' that logs to stdout mylog = Logger.new 'mylog' mylog.outputters = Outputter.stdout # later in the code, you can get the logger back Logger['mylog'] ``` With Yell you can do the same thing with less: ```ruby require 'yell' # create a logger named 'mylog' that logs to stdout Yell.new :stdout, name: 'mylog' # later in the code, you can get the logger back Yell['mylog'] ``` There is no need to define outputters separately and you don't have to taint you global namespace with Yell's subclasses. ### Adding a logger to an existing class Yell comes with a simple module: +Yell::Loggable+. Simply include this in a class and you are good to go. ```ruby # Before you can use it, you will need to define a logger and # provide it with the `:name` of your class. Yell.new :stdout, name: 'Foo' class Foo include Yell::Loggable end # Now you can log Foo.logger.info "Hello World" Foo.new.logger.info "Hello World" ``` It even works with class inheritance: ```ruby # Given the above example, we inherit from Foo class Bar < Foo end # The logger will fallback to the Foo superclass Bar.logger.info "Hello World" Bar.new.logger.info "Hello World" ``` ### Adding a logger to all classes at once (global logger) Derived from the example above, simply do the following. ```ruby # Define a logger and pass `Object` as name. Internally, Yell adds this # logger to the repository where you can access it later on. Yell.new :stdout, name: Object # Enable logging for the class that (almost) every Ruby class inherits from Object.send :include, Yell::Loggable # now you are good to go... from wherever you are logger.info "Hello from anything" Integer.logger.info "Hello from Integer" ``` ### Suppress log messages with silencers In case you woul like to suppress certain log messages, you may define silencers with Yell. Use this to get control of a noisy log environment. For instance, you can suppress logging messages that contain secure information or more simply, to skip information about serving your Rails assets. Provide a string or a regular expression of the message patterns you would like to exclude. ```ruby logger = Yell.new do |l| l.silence /^Started GET "\/assets/ l.silence /^Served asset/ end logger.debug 'Started GET "/assets/logo.png" for 127.0.0.1 at 2013-06-20 10:18:38 +0200' logger.debug 'Served asset /logo.png - 304 Not Modified (0ms)' ``` ### Alter log messages with modifiers ## Further Readings [How To: Setting The Log Level](https://github.com/rudionrails/yell/wiki/101-setting-the-log-level) [How To: Formatting Log Messages](https://github.com/rudionrails/yell/wiki/101-formatting-log-messages) [How To: Using Adapters](https://github.com/rudionrails/yell/wiki/101-using-adapters) [How To: The Datefile Adapter](https://github.com/rudionrails/yell/wiki/101-the-datefile-adapter) [How To: Different Adapters for Different Log Levels](https://github.com/rudionrails/yell/wiki/101-different-adapters-for-different-log-levels) ### Additional Adapters [Syslog](https://github.com/rudionrails/yell/wiki/additional-adapters-syslog) [syslog-sd](https://github.com/raymond-wells/yell-adapters-syslogsd) [Graylog2 (GELF)](https://github.com/rudionrails/yell/wiki/additional-adapters-gelf) [Fluentd](https://github.com/red5studios/yell-adapters-fluentd) ### Development [How To: Writing Your Own Adapter](https://github.com/rudionrails/yell/wiki/Writing-your-own-adapter) You can find further examples and additional adapters in the [wiki](https://github.com/rudionrails/yell/wiki). or have a look into the examples folder. Copyright © 2011-current Rudolf Schmidt, released under the MIT license yell-2.2.2/.gitignore0000644000004100000410000000020113622502024014467 0ustar www-datawww-datapkg/* *.gem .bundle .idea .vscode vendor/ # bundler Gemfile.*lock # vim *.swp # coverage /coverage # rspec /spec/examples/txt yell-2.2.2/examples/0000755000004100000410000000000013622502024014324 5ustar www-datawww-datayell-2.2.2/examples/003.1-formatting-DefaultFormat.rb0000644000004100000410000000103013622502024022207 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # The default formatting string looks like: %d [%5L] %p : %m and is used when # nothing else is defined. logger = Yell.new STDOUT, format: Yell::DefaultFormat logger.info "Hello World!" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!" # ^ ^ ^ ^ # ISO8601 Timestamp Level Pid Message EOS puts "=== actual example ===" logger = Yell.new STDOUT, format: Yell::DefaultFormat logger.info "Hello World!" yell-2.2.2/examples/003.2-formatting-BasicFormat.rb0000644000004100000410000000071713622502024021660 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # The basic formating string looks like: %l, %d: %m. logger = Yell.new STDOUT, format: Yell::BasicFormat logger.info "Hello World!" #=> "I, 2012-02-29T09:30:00+01:00 : Hello World!" # ^ ^ ^ # ^ ISO8601 Timestamp Message # Level (short) EOS puts "=== actual example ===" logger = Yell.new STDOUT, format: Yell::BasicFormat logger.info "Hello World!" yell-2.2.2/examples/004.1-colorizing-the-log-output.rb0000644000004100000410000000061213622502024022362 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS You may colorize the log output on your io-based loggers loke so: logger = Yell.new STDOUT, colors: true Yell::Severities.each do |level| logger.send level.downcase, level end EOS puts "=== actual example ===" logger = Yell.new STDOUT, colors: true Yell::Severities.each do |level| logger.send level.downcase, level end yell-2.2.2/examples/003.3-formatting-ExtendedFormat.rb0000644000004100000410000000102013622502024022364 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # The extended formatting string looks like: %d [%5L] %p %h : %m. logger = Yell.new STDOUT, format: Yell::ExtendedFormat logger.info "Hello World!" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 localhost : Hello World!" # ^ ^ ^ ^ ^ # ISO8601 Timestamp Level Pid Hostname Message EOS puts "=== actual example ===" logger = Yell.new STDOUT, format: Yell::ExtendedFormat logger.info "Hello World!" yell-2.2.2/examples/005.1-repository.rb0000644000004100000410000000060413622502024017531 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # You can add a logger to the global repository. # # create a logger named 'mylog' that logs to stdout Yell.new :stdout, name: 'mylog' # Later in the code, you can get your logger back Yell['mylog'].info "Hello World!" EOS puts "=== actual example ===" Yell.new :stdout, name: 'mylog' Yell['mylog'].info "Hello World!" yell-2.2.2/examples/006.1-the-loggable-module.rb0000644000004100000410000000122713622502024021132 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # You can add logging to any class by including the Yell::Loggable module. # # When including the module, your class will get a :logger method. Before you # can use it, though, you will need to define a logger providing the :name of # your class. Yell.new :stdout, name: 'Foo' # Define the class class Foo include Yell::Loggable end foo = Foo.new foo.logger.info "Hello World!" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!" EOS puts "=== actual example ===" Yell.new :stdout, name: 'Foo' class Foo include Yell::Loggable end foo = Foo.new foo.logger.info "Hello World!" yell-2.2.2/examples/002.3-log-level-within-range.rb0000644000004100000410000000124213622502024021570 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # Additionally to writing only on specific levels, you may pass a range to # the :level option: # * %i[] is a built-in for an array of symbols logger = Yell.new STDOUT, level: (:debug..:warn) %i[debug info warn error fatal].each do |level| logger.send( level, level ) end #=> "2012-02-29T09:30:00+01:00 [DEBUG] 65784 : debug" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : info" #=> "2012-02-29T09:30:00+01:00 [ WARN] 65784 : warn" EOS puts "=== actual example ===" logger = Yell.new STDOUT, level: (:debug..:warn) %i[debug info warn error fatal].each do |level| logger.send( level, level ) end yell-2.2.2/examples/001-basic-usage.rb0000644000004100000410000000107013622502024017330 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # On the basics, Yell works just like any other logging library. # # However, it enriches your log messages to make it more readable. By default, # it will format the given message as follows: logger = Yell.new STDOUT logger.info "Hello World!" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!" # ^ ^ ^ ^ # ISO8601 Timestamp Level Pid Message EOS puts "=== actual example ===" logger = Yell.new STDOUT logger.info "Hello World!" yell-2.2.2/examples/006.2-the-loggable-module-with-inheritance.rb0000644000004100000410000000130313622502024024366 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # You can add logging to any class by including the Yell::Loggable module. # # When including the module, your class will get a :logger method. Before you # can use it, though, you will need to define a logger providing the :name of # your class. Yell.new :stdout, name: 'Foo' # Define the class class Foo include Yell::Loggable end class Bar < Foo; end bar = Bar.new bar.logger.info "Hello World!" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!" EOS puts "=== actual example ===" Yell.new :stdout, name: 'Foo' class Foo include Yell::Loggable end class Bar < Foo; end bar = Bar.new bar.logger.info "Hello World!" yell-2.2.2/examples/003.4-formatting-on-your-own.rb0000644000004100000410000000103513622502024021673 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # The extended formatting string looks like: %d [%5L] %p %h : %m. logger = Yell.new STDOUT, format: "[%f:%n in `%M'] %m", trace: true logger.info "Hello World!" #=> [003.4-formatting-on-your-own.rb:20 in `
'] Hello World! # ^ ^ ^ ^ # filename line method message EOS puts "=== actual example ===" logger = Yell.new STDOUT, format: "[%f:%n in `%M'] %m", trace: true logger.info "Hello World!" yell-2.2.2/examples/002.1-log-level-basics.rb0000644000004100000410000000104413622502024020436 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # Like many other logging libraries, Yell allows you to define from which level # onwards you want to write your log message. logger = Yell.new STDOUT, level: :info logger.debug "This is a :debug message" #=> nil logger.info "This is a :info message" #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : This is a :info message" EOS puts "=== actual example ===" logger = Yell.new STDOUT, level: :info logger.debug "This is a :debug message" logger.info "This is a :info message" yell-2.2.2/examples/002.2-log-level-on-certain-severities-only.rb0000644000004100000410000000133113622502024024370 0ustar www-datawww-data# encoding: utf-8 require_relative '../lib/yell' puts <<-EOS # The Yell::Level parser allows you to exactly specify on which levels to log, # ignoring all the others. For instance: If we want to only log at the :debug # and :warn levels we simply providing an array: # * %i[] is a built-in for an array of symbols logger = Yell.new STDOUT, level: %i[debug warn] %i[debug info warn error fatal].each do |level| logger.send( level, level ) end #=> "2012-02-29T09:30:00+01:00 [DEBUG] 65784 : debug" #=> "2012-02-29T09:30:00+01:00 [ WARN] 65784 : warn" EOS puts "=== actual example ===" logger = Yell.new STDOUT, level: %i[debug warn] %i[debug info warn error fatal].each do |level| logger.send( level, level ) end yell-2.2.2/yell.gemspec0000644000004100000410000000225213622502024015021 0ustar www-datawww-data# frozen_string_literal: true lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'yell/version' Gem::Specification.new do |spec| spec.name = 'yell' spec.version = Yell::VERSION spec.authors = ['Rudolf Schmidt'] spec.license = 'MIT' spec.summary = 'Yell - Your Extensible Logging Library' spec.description = "Yell - Your Extensible Logging Library. Define multiple adapters, various log level combinations or message formatting options like you've never done before" spec.homepage = 'https://github.com/rudionrails/yell' spec.metadata['homepage_uri'] = spec.homepage spec.metadata['source_code_uri'] = 'https://github.com/rudionrails/yell' # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } end spec.bindir = 'exe' spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] end yell-2.2.2/Rakefile0000644000004100000410000000050213622502024014150 0ustar www-datawww-datarequire 'bundler/gem_tasks' # Run stuff in the examples folder desc "Run examples" task :examples do require 'benchmark' seconds = Benchmark.realtime do Dir[ './examples/*.rb' ].each { |file| puts "\n\n=== Running #{file} ==="; require file } end puts "\n\t[ Examples took #{seconds} seconds to run ]" end yell-2.2.2/lib/0000755000004100000410000000000013622502024013254 5ustar www-datawww-datayell-2.2.2/lib/core_ext/0000755000004100000410000000000013622502024015064 5ustar www-datawww-datayell-2.2.2/lib/core_ext/logger.rb0000644000004100000410000000071513622502024016673 0ustar www-datawww-datarequire 'logger' class Logger def level_with_yell=( level ) self.level_without_yell= level.is_a?(Yell::Level) ? Integer(level) : level end alias_method :level_without_yell=, :level= alias_method :level=, :level_with_yell= def add_with_yell( severity, message = nil, progname = nil, &block ) add_without_yell(Integer(severity), message, progname, &block) end alias_method :add_without_yell, :add alias_method :add, :add_with_yell end yell-2.2.2/lib/yell.rb0000644000004100000410000001107713622502024014554 0ustar www-datawww-data# Copyright (c) 2011-2014 Rudolf Schmidt # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. module Yell #:nodoc: # Holds all Yell severities Severities = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'UNKNOWN'].freeze class << self # Creates a new logger instance. # # Refer to #Yell::Loggger for usage. # # @return [Yell::Logger] The logger instance def new( *args, &block ) Yell::Logger.new(*args, &block) end # Shortcut to Yell::Level.new # # @return [Yell::Level] The level instance def level( val = nil ) Yell::Level.new(val) end # Shortcut to Yell::Repository[] # # @return [Yell::Logger] The logger instance def []( name ) Yell::Repository[name] end # Shortcut to Yell::Repository[]= # # @return [Yell::Logger] The logger instance def []=( name, logger ) Yell::Repository[name] = logger end # Shortcut to Yell::Fomatter.new # # @return [Yell::Formatter] A Yell::Formatter instance def format( pattern = nil, date_pattern = nil, &block ) Yell::Formatter.new(pattern, date_pattern, &block) end # Loads a config from a YAML file # # @return [Yell::Logger] The logger instance def load!( file ) Yell.new Yell::Configuration.load!(file) end # Shortcut to Yell::Adapters.register def register( name, klass ) Yell::Adapters.register(name, klass) end # @private def env return ENV['YELL_ENV'] if ENV.key? 'YELL_ENV' return ENV['RACK_ENV'] if ENV.key? 'RACK_ENV' return ENV['RAILS_ENV'] if ENV.key? 'RAILS_ENV' if defined?(Rails) Rails.env else 'development' end end # @private def __deprecate__( version, message, options = {} ) #:nodoc: messages = ["Deprecation Warning (since v#{version}): #{message}" ] messages << " before: #{options[:before]}" if options[:before] messages << " after: #{options[:after]}" if options[:after] __warn__(*messages) end # @private def __warn__( *messages ) #:nodoc: $stderr.puts "[Yell] " + messages.join("\n") rescue Exception => e # do nothing end # @private def __fetch__( hash, *args ) options = args.last.is_a?(Hash) ? args.pop : {} value = args.map { |key| hash.fetch(key.to_sym, hash[key.to_s]) }.compact.first value.nil? ? options[:default] : value end end end # helpers require File.dirname(__FILE__) + '/yell/helpers/base' require File.dirname(__FILE__) + '/yell/helpers/adapter' require File.dirname(__FILE__) + '/yell/helpers/formatter' require File.dirname(__FILE__) + '/yell/helpers/level' require File.dirname(__FILE__) + '/yell/helpers/tracer' require File.dirname(__FILE__) + '/yell/helpers/silencer' # classes require File.dirname(__FILE__) + '/yell/configuration' require File.dirname(__FILE__) + '/yell/repository' require File.dirname(__FILE__) + '/yell/event' require File.dirname(__FILE__) + '/yell/level' require File.dirname(__FILE__) + '/yell/formatter' require File.dirname(__FILE__) + '/yell/silencer' require File.dirname(__FILE__) + '/yell/adapters' require File.dirname(__FILE__) + '/yell/logger' # modules require File.dirname(__FILE__) + '/yell/loggable' # core extensions require File.dirname(__FILE__) + '/core_ext/logger' # register known adapters Yell.register :null, Yell::Adapters::Base # adapter that does nothing (for convenience only) Yell.register :file, Yell::Adapters::File Yell.register :datefile, Yell::Adapters::Datefile Yell.register :stdout, Yell::Adapters::Stdout Yell.register :stderr, Yell::Adapters::Stderr yell-2.2.2/lib/yell/0000755000004100000410000000000013622502024014221 5ustar www-datawww-datayell-2.2.2/lib/yell/formatter.rb0000644000004100000410000001561613622502024016562 0ustar www-datawww-datarequire 'time' # TODO: Register custom formats # # @example The Yell default fomat # Yell::Formatter.register(:default) # # @example The Ruby standard logger format # Yell::Formatter.register(:stdlogger, "%l, [%d #%p] %5L -- : %m", "%Y-%m-%dT%H:%M:%S.%6N") # module Yell #:nodoc: # No format on the log message # # @example # logger = Yell.new STDOUT, format: false # logger.info "Hello World!" # #=> "Hello World!" NoFormat = "%m" # Default Format # # @example # logger = Yell.new STDOUT, format: Yell::DefaultFormat # logger.info "Hello World!" # #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!" # # ^ ^ ^ ^ # # ISO8601 Timestamp Level Pid Message DefaultFormat = "%d [%5L] %p : %m" # Basic Format # # @example # logger = Yell.new STDOUT, format: Yell::BasicFormat # logger.info "Hello World!" # #=> "I, 2012-02-29T09:30:00+01:00 : Hello World!" # # ^ ^ ^ # # ^ ISO8601 Timestamp Message # # Level (short) BasicFormat = "%l, %d : %m" # Extended Format # # @example # logger = Yell.new STDOUT, format: Yell::ExtendedFormat # logger.info "Hello World!" # #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 localhost : Hello World!" # # ^ ^ ^ ^ ^ # # ISO8601 Timestamp Level Pid Hostname Message ExtendedFormat = "%d [%5L] %p %h : %m" # The +Formatter+ provides a handle to configure your log message style. class Formatter Table = { "m" => "message(event.messages)", # Message "l" => "level(event.level, 1)", # Level (short), e.g.'I', 'W' "L" => "level(event.level)", # Level, e.g. 'INFO', 'WARN' "d" => "date(event.time)", # ISO8601 Timestamp "h" => "event.hostname", # Hostname "p" => "event.pid", # PID "P" => "event.progname", # Progname "t" => "event.thread_id", # Thread ID "F" => "event.file", # Path with filename where the logger was called "f" => "File.basename(event.file)", # Filename where the loger was called "M" => "event.method", # Method name where the logger was called "n" => "event.line", # Line where the logger was called "N" => "event.name" # Name of the logger } # For standard formatted backwards compatibility LegacyTable = Hash[ Table.keys.map { |k| [k, 'noop'] } ].merge( 'm' => 'message(msg)', 'l' => 'level(event, 1)', 'L' => 'level(event)', 'd' => 'date(time)', "p" => "$$", 'P' => 'progname' ) PatternMatcher = /([^%]*)(%\d*)?(#{Table.keys.join('|')})?(.*)/m attr_reader :pattern, :date_pattern # Initializes a new +Yell::Formatter+. # # Upon initialization it defines a format method. `format` takes # a {Yell::Event} instance as agument in order to apply for desired log # message formatting. # # @example Blank formatter # Formatter.new # # @example Formatter with a message pattern # Formatter.new("%d [%5L] %p : %m") # # @example Formatter with a message and date pattern # Formatter.new("%d [%5L] %p : %m", "%D %H:%M:%S.%L") # # @example Formatter with a message modifier # Formatter.new do |f| # f.modify(Hash) { |h| "Hash: #{h.inspect}" } # end def initialize( *args, &block ) builder = Builder.new(*args, &block) @pattern = builder.pattern @date_pattern = builder.date_pattern @modifier = builder.modifier define_date_method! define_call_method! end # Get a pretty string def inspect "#<#{self.class.name} pattern: #{@pattern.inspect}, date_pattern: #{@date_pattern.inspect}>" end private # Message modifier class to allow different modifiers for different requirements. class Modifier def initialize @repository = {} end def set( key, &block ) @repository.merge!(key => block) end def call( message ) case when mod = @repository[message.class] || @repository[message.class.to_s] mod.call(message) when message.is_a?(Array) message.map { |m| call(m) }.join(" ") when message.is_a?(Hash) message.map { |k, v| "#{k}: #{v}" }.join(", ") when message.is_a?(Exception) backtrace = message.backtrace ? "\n\t#{message.backtrace.join("\n\t")}" : "" sprintf("%s: %s%s", message.class, message.message, backtrace) else message end end end # Builder class to allow setters that won't be accessible once # transferred to the Formatter class Builder attr_accessor :pattern, :date_pattern attr_reader :modifier def initialize( pattern = nil, date_pattern = nil, &block ) @modifier = Modifier.new @pattern = case pattern when false then Yell::NoFormat when nil then Yell::DefaultFormat else pattern end.dup @pattern << "\n" unless @pattern[-1] == ?\n # add newline if not present @date_pattern = date_pattern || :iso8601 block.call(self) if block end def modify( key, &block ) modifier.set(key, &block) end end def define_date_method! buf = case @date_pattern when String then "t.strftime(@date_pattern)" when Symbol then respond_to?(@date_pattern, true) ? "#{@date_pattern}(t)" : "t.#{@date_pattern}" else t.iso8601 end # define the method instance_eval <<-METHOD, __FILE__, __LINE__ def date(t = Time.now) #{buf} end METHOD end # define a standard +Logger+ backwards compatible #call method for the formatter def define_call_method! instance_eval <<-METHOD, __FILE__, __LINE__ def call(event, time = nil, progname = nil, msg = nil) event.is_a?(Yell::Event) ? #{to_sprintf(Table)} : #{to_sprintf(LegacyTable)} end METHOD end def to_sprintf( table ) buff, args, _pattern = "", [], @pattern.dup while true match = PatternMatcher.match(_pattern) buff << match[1] unless match[1].empty? break if match[2].nil? buff << match[2] + 's' args << table[ match[3] ] _pattern = match[4] end %Q{sprintf("#{buff.gsub(/"/, '\"')}", #{args.join(', ')})} end def level( sev, length = nil ) severity = case sev when Integer then Yell::Severities[sev] || 'ANY' else sev end length.nil? ? severity : severity[0, length] end def message( messages ) @modifier.call(messages.is_a?(Array) && messages.size == 1 ? messages.first : messages) end # do nothing def noop '' end end end yell-2.2.2/lib/yell/version.rb0000644000004100000410000000005613622502024016234 0ustar www-datawww-datamodule Yell #:nodoc: VERSION = "2.2.2" end yell-2.2.2/lib/yell/adapters/0000755000004100000410000000000013622502024016024 5ustar www-datawww-datayell-2.2.2/lib/yell/adapters/datefile.rb0000644000004100000410000001340413622502024020130 0ustar www-datawww-datamodule Yell #:nodoc: module Adapters #:nodoc: # The +Datefile+ adapter is similar to the +File+ adapter. However, it # rotates the file at midnight (by default). class Datefile < Yell::Adapters::File # The default date pattern, e.g. "19820114" (14 Jan 1982) DefaultDatePattern = "%Y%m%d" # Metadata Header = lambda { |date, pattern| "# -*- #{date.iso8601} (#{date.to_f}) [#{pattern}] -*-" } HeaderRegexp = /^# -\*- (.+) \((\d+\.\d+)\) \[(.+)\] -\*-$/ # The pattern to be used for the files # # @example # date_pattern = "%Y%m%d" # default # date_pattern = "%Y-week-%V" attr_accessor :date_pattern # Tell the adapter to create a symlink onto the currently # active (timestamped) file. Upon rollover, the symlink is # set to the newly created file, and so on. # # @example # symlink = true attr_accessor :symlink # Set the amount of logfiles to keep when rolling over. # By default, no files will be cleaned up. # # @example Keep the last 5 logfiles # keep = 5 # keep = '10' # # @example Do not clean up any files # keep = 0 attr_accessor :keep # You can suppress the first line of the logfile that contains # the metadata. This is important upon rollover, because on *nix # systems, it is not possible to determine the creation time of a file, # on the last access time. The header compensates this. # # @example # header = false attr_accessor :header private # @overload setup!( options ) def setup!( options ) self.header = Yell.__fetch__(options, :header, default: true) self.date_pattern = Yell.__fetch__(options, :date_pattern, default: DefaultDatePattern) self.keep = Yell.__fetch__(options, :keep, default: false) self.symlink = Yell.__fetch__(options, :symlink, default: true) @original_filename = ::File.expand_path(Yell.__fetch__(options, :filename, default: default_filename)) options[:filename] = @original_filename @date = Time.now @date_strftime = @date.strftime(date_pattern) super end # @overload write!( event ) def write!( event ) # do nothing when not closing return super unless close? close # exit when file ready present return super if ::File.exist?(@filename) header! if header? symlink! if symlink? cleanup! if cleanup? super end # @overload close! def close! @filename = filename_for(@date) super end # Determine whether to close the file handle or not. # # It is based on the `:date_pattern` (can be passed as option upon initialize). # If the current time hits the pattern, it closes the file stream. # # @return [Boolean] true or false def close? _date = Time.now _date_strftime = _date.strftime(date_pattern) if @stream.nil? or _date_strftime != @date_strftime @date, @date_strftime = _date, _date_strftime return true end false end # Removes old logfiles of the same date pattern. # # By reading the header of the files that match the date pattern, the # adapter determines whether to remove them or not. If no header is present, # it makes the best guess by checking the last access time (which may result # in false cleanups). def cleanup! files = Dir[ @original_filename.sub(/(\.\w+)?$/, ".*\\1") ].sort.select do |file| _, pattern = header_from(file) # Select if the date pattern is nil (no header info available within the file) or # when the pattern matches. pattern.nil? || pattern == self.date_pattern end ::File.unlink( *files[0..-keep-1] ) end # Cleanup old logfiles? # # @return [Boolean] true or false def cleanup? !!keep && keep.to_i > 0 end # Symlink the current filename to the original one. def symlink! # do nothing, because symlink is already correct return if ::File.symlink?(@original_filename) && ::File.readlink(@original_filename) == @filename ::File.unlink(@original_filename) if ::File.exist?(@original_filename) || ::File.symlink?(@original_filename) ::File.symlink(@filename, @original_filename) end # Symlink the original filename? # # @return [Boolean] true or false def symlink? !!symlink end # Write the header information into the file def header! stream.puts( Header.call(@date, date_pattern) ) end # Write header into the file? # # @return [Boolean] true or false def header? !!header end # Sets the filename with the `:date_pattern` appended to it. def filename_for( date ) @original_filename.sub(/(\.\w+)?$/, ".#{date.strftime(date_pattern)}\\1") end # Fetch the header form the file def header_from( file ) if m = ::File.open(file, &:readline).match(HeaderRegexp) # in case there is a Header present, we can just read from it [ Time.at(m[2].to_f), m[3] ] else # In case there is no header: we need to take a good guess # # Since the pattern can not be determined, we will just return the Posix ctime. # That is NOT the creatint time, so the value will potentially be wrong! [::File.ctime(file), nil] end end # @overload inspectables def inspectables super.concat %i[date_pattern header keep symlink] end end end end yell-2.2.2/lib/yell/adapters/base.rb0000644000004100000410000001404213622502024017264 0ustar www-datawww-datarequire 'monitor' module Yell #:nodoc: module Adapters #:nodoc: # This class provides the basic interface for all allowed operations on any # adapter implementation. Other adapters should inherit from it for the methods # used by the {Yell::Logger}. # # Writing your own adapter is really simple. Inherit from the base class and use # the `setup`, `write` and `close` methods. Yell requires the `write` method to be # specified (`setup` and `close` are optional). # # # The following example shows how to define a basic Adapter to format and print # log events to STDOUT: # # class PutsAdapter < Yell::Adapters::Base # include Yell::Formatter::Helpers # # setup do |options| # self.format = options[:format] # end # # write do |event| # message = format.call(event) # # STDOUT.puts message # end # end # # # After the Adapter has been written, we need to register it to Yell: # # Yell::Adapters.register :puts, PutsAdapter # # Now, we can use it like so: # # logger = Yell.new :puts # logger.info "Hello World!" class Base < Monitor include Yell::Helpers::Base include Yell::Helpers::Level class << self # Setup your adapter with this helper method. # # @example # setup do |options| # @file_handle = File.new( '/dev/null', 'w' ) # end def setup( &block ) compile!(:setup!, &block) end # Define your write method with this helper. # # @example Printing messages to file # write do |event| # @file_handle.puts event.message # end def write( &block ) compile!(:write!, &block) end # Define your open method with this helper. # # @example Open a file handle # open do # @stream = ::File.open( 'test.log', ::File::WRONLY|::File::APPEND|::File::CREAT ) # end def open( &block ) compile!(:open!, &block) end # Define your close method with this helper. # # @example Closing a file handle # close do # @stream.close # end def close( &block ) compile!(:close!, &block) end private # Pretty funky code block, I know but here is what it basically does: # # @example # compile! :write! do |event| # puts event.message # end # # # Is actually defining the `:write!` instance method with a call to super: # # def write!( event ) # puts event.method # super # end def compile!( name, &block ) # Get the already defined method m = instance_method( name ) # Create a new method with leading underscore define_method("_#{name}", &block) _m = instance_method("_#{name}") remove_method("_#{name}") # Define instance method define!(name, _m, m, &block) end # Define instance method by given name and call the unbound # methods in order with provided block. def define!( name, _m, m, &block ) if block.arity == 0 define_method(name) do _m.bind(self).call m.bind(self).call end else define_method(name) do |*args| _m.bind(self).call(*args) m.bind(self).call(*args) end end end end # Initializes a new Adapter. # # You should not overload the constructor, use #setup instead. def initialize( options = {}, &block ) super() # init the monitor superclass reset! setup!(options) # eval the given block block.arity > 0 ? block.call(self) : instance_eval(&block) if block_given? end # The main method for calling the adapter. # # The method receives the log `event` and determines whether to # actually write or not. def write( event ) synchronize { write!(event) } if write?(event) rescue Exception => e # make sure the adapter is closed and re-raise the exception synchronize { close } raise(e) end # Close the adapter (stream, connection, etc). # # Adapter classes should provide their own implementation # of this method. def close close! end # Get a pretty string representation of the adapter, including def inspect inspection = inspectables.map { |m| "#{m}: #{send(m).inspect}" } "#<#{self.class.name} #{inspection * ', '}>" end private # Setup the adapter instance. # # Adapter classes should provide their own implementation # of this method (if applicable). def setup!( options ) self.level = Yell.__fetch__(options, :level) end # Perform the actual write. # # Adapter classes must provide their own implementation # of this method. def write!( event ) # Not implemented end # Perform the actual open. # # Adapter classes should provide their own implementation # of this method. def open! # Not implemented end # Perform the actual close. # # Adapter classes should provide their own implementation # of this method. def close! # Not implemented end # Determine whether to write at the given severity. # # @example # write? Yell::Event.new( 'INFO', 'Hello Wold!' ) # # @param [Yell::Event] event The log event # # @return [Boolean] true or false def write?( event ) level.nil? || level.at?(event.level) end # Get an array of inspected attributes for the adapter. def inspectables [:level] end end end end yell-2.2.2/lib/yell/adapters/file.rb0000644000004100000410000000137613622502024017277 0ustar www-datawww-datamodule Yell #:nodoc: module Adapters #:nodoc: # The +File+ adapter is the most basic. As one would expect, it's used # for logging into files. class File < Yell::Adapters::Io private # @overload setup!( options ) def setup!( options ) @filename = ::File.expand_path(Yell.__fetch__(options, :filename, default: default_filename)) super end # @overload open! def open! @stream = ::File.open(@filename, ::File::WRONLY|::File::APPEND|::File::CREAT) super end def default_filename #:nodoc: logdir = ::File.expand_path("log") ::File.expand_path(::File.directory?(logdir) ? "#{logdir}/#{Yell.env}.log" : "#{Yell.env}.log") end end end end yell-2.2.2/lib/yell/adapters/streams.rb0000644000004100000410000000057413622502024020035 0ustar www-datawww-datamodule Yell #:nodoc: module Adapters #:nodoc: class Stdout < Yell::Adapters::Io private # @overload open! def open! @stream = $stdout.clone super end end class Stderr < Yell::Adapters::Io private # @overload open! def open! @stream = $stderr.clone super end end end end yell-2.2.2/lib/yell/adapters/io.rb0000644000004100000410000000442213622502024016762 0ustar www-datawww-datamodule Yell #:nodoc: module Adapters #:nodoc: class Io < Yell::Adapters::Base include Yell::Helpers::Formatter # The possible unix log colors TTYColors = { 0 => "\033[1;32m", # green 1 => "\033[0m", # normal 2 => "\033[1;33m", # yellow 3 => "\033[1;31m", # red 4 => "\033[1;35m", # magenta 5 => "\033[1;36m", # cyan -1 => "\033[0m" # normal } # Sets the “sync mode” to true or false. # # When true (default), every log event is immediately written to the file. # When false, the log event is buffered internally. attr_accessor :sync # Sets colored output on or off (default off) # # @example Enable colors # colors = true # # @example Disable colors # colors = false attr_accessor :colors # Shortcut to enable colors. # # @example # colorize! def colorize!; @colors = true; end private # @overload setup!( options ) def setup!( options ) @stream = nil self.colors = Yell.__fetch__(options, :colors, default: false) self.formatter = Yell.__fetch__(options, :format, :formatter) self.sync = Yell.__fetch__(options, :sync, default: true) super end # @overload write!( event ) def write!( event ) message = formatter.call(event) # colorize if applicable if colors and color = TTYColors[event.level] message = color + message + TTYColors[-1] end stream.syswrite(message) super end # @overload open! def open! @stream.sync = self.sync if @stream.respond_to?(:sync) @stream.flush if @stream.respond_to?(:flush) super end # @overload close! def close! @stream.close if @stream.respond_to?(:close) @stream = nil super end # The IO stream # # Adapter classes should provide their own implementation # of this method. def stream synchronize { open! if @stream.nil?; @stream } end # @overload inspectables def inspectables super.concat [:formatter, :colors, :sync] end end end end yell-2.2.2/lib/yell/loggable.rb0000644000004100000410000000123113622502024016317 0ustar www-datawww-datamodule Yell #:nodoc: # Include this module to add a logger to any class. # # When including this module, your class will have a :logger instance method # available. Before you can use it, you will need to define a Yell logger and # provide it with the name of your class. # # @example # Yell.new :stdout, name: 'Foo' # # class Foo # include Yell::Loggable # end # # Foo.new.logger.info "Hello World" module Loggable def self.included(base) base.extend(ClassMethods) end module ClassMethods def logger Yell[self] end end def logger self.class.logger end end end yell-2.2.2/lib/yell/helpers/0000755000004100000410000000000013622502024015663 5ustar www-datawww-datayell-2.2.2/lib/yell/helpers/formatter.rb0000644000004100000410000000103213622502024020207 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Formatter #:nodoc: # Set the format for your message. def formatter=( pattern ) @__formatter__ = case pattern when Yell::Formatter then pattern else Yell::Formatter.new(*pattern) end end alias :format= :formatter= def formatter @__formatter__ end alias :format :formatter private def reset! @__formatter__ = Yell::Formatter.new super end end end end yell-2.2.2/lib/yell/helpers/adapter.rb0000644000004100000410000000225113622502024017630 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Adapter #:nodoc: # Define an adapter to be used for logging. # # @example Standard adapter # adapter :file # # @example Standard adapter with filename # adapter :file, 'development.log' # # # Alternative notation for filename in options # adapter :file, filename: 'developent.log' # # @example Standard adapter with filename and additional options # adapter :file, 'development.log', level: :warn # # @example Set the adapter directly from an adapter instance # adapter Yell::Adapter::File.new # # @param [Symbol] type The type of the adapter, may be `:file` or `:datefile` (default `:file`) # @return [Yell::Adapter] The instance # @raise [Yell::NoSuchAdapter] Will be thrown when the adapter is not defined def adapter( type = :file, *args, &block ) adapters.add(type, *args, &block) end def adapters @__adapters__ end private def reset! @__adapters__ = Yell::Adapters::Collection.new(@options) super end end end end yell-2.2.2/lib/yell/helpers/base.rb0000644000004100000410000000030113622502024017114 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Base #:nodoc: private # stub def reset! end def inspectables [] end end end end yell-2.2.2/lib/yell/helpers/silencer.rb0000644000004100000410000000070513622502024020016 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Silencer # Set the silence pattern def silence( *patterns ) silencer.add(*patterns) end def silencer @__silencer__ end private def reset! @__silencer__ = Yell::Silencer.new super end def silence!( *messages ) @__silencer__.silence!(*messages) if silencer.silence? end end end end yell-2.2.2/lib/yell/helpers/level.rb0000644000004100000410000000121613622502024017317 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Level # Set the minimum log level. # # @example Set the level to :warn # level = :warn # # @param [String, Symbol, Integer] severity The minimum log level def level=( severity ) @__level__ = case severity when Yell::Level then severity else Yell::Level.new(severity) end end # @private def level @__level__ end private def reset! @__level__ = Yell::Level.new super end def inspectables [:level] | super end end end end yell-2.2.2/lib/yell/helpers/tracer.rb0000644000004100000410000000176013622502024017474 0ustar www-datawww-datamodule Yell #:nodoc: module Helpers #:nodoc: module Tracer #:nodoc: # Set whether the logger should allow tracing or not. The trace option # will tell the logger when to provider caller information. # # @example No tracing at all # trace = false # # @example Trace every time # race = true # # @example Trace from the error level onwards # trace = :error # trace = 'gte.error' # # @return [Yell::Level] a level representation of the tracer def trace=( severity ) @__trace__ = case severity when Yell::Level then severity when false then Yell::Level.new("gt.#{Yell::Severities.last}") else Yell::Level.new(severity) end end def trace @__trace__ end private def reset! @__trace__ = Yell::Level.new('gte.error') super end def inspectables [:trace] | super end end end end yell-2.2.2/lib/yell/configuration.rb0000644000004100000410000000072413622502024017420 0ustar www-datawww-datarequire 'erb' require 'yaml' module Yell #:nodoc: # The Configuration can be used to setup Yell before # initializing an instance. class Configuration def self.load!( file ) yaml = YAML.load( ERB.new(File.read(file)).result ) # in case we have ActiveSupport if defined?(ActiveSupport::HashWithIndifferentAccess) yaml = ActiveSupport::HashWithIndifferentAccess.new(yaml) end yaml[Yell.env] || {} end end end yell-2.2.2/lib/yell/event.rb0000644000004100000410000000506313622502024015673 0ustar www-datawww-datarequire 'time' require 'socket' module Yell #:nodoc: # Yell::Event.new( :info, 'Hello World', { :scope => 'Application' } ) # #=> Hello World scope: Application class Event # regex to fetch caller attributes CallerRegexp = /^(.+?):(\d+)(?::in `(.+)')?/ # jruby and rubinius seem to have a different caller CallerIndex = defined?(RUBY_ENGINE) && ["rbx", "jruby"].include?(RUBY_ENGINE) ? 1 : 2 class Options include Comparable attr_reader :severity attr_reader :caller_offset def initialize( severity, caller_offset ) @severity = severity @caller_offset = caller_offset end def <=>( other ) @severity <=> other end alias :to_i :severity alias :to_int :severity end # Prefetch those values (no need to do that on every new instance) @@hostname = Socket.gethostname rescue nil @@progname = $0 # Accessor to the log level attr_reader :level # Accessor to the log message attr_reader :messages # Accessor to the time the log event occured attr_reader :time # Accessor to the logger's name attr_reader :name def initialize( logger, options, *messages) @time = Time.now @name = logger.name extract!(options) @messages = messages @caller = logger.trace.at?(level) ? caller[caller_index].to_s : '' @file = nil @line = nil @method = nil @pid = nil end # Accessor to the hostname def hostname @@hostname end # Accessor to the progname def progname @@progname end # Accessor to the PID def pid Process.pid end # Accessor to the thread's id def thread_id Thread.current.object_id end # Accessor to filename the log event occured def file @file || (backtrace!; @file) end # Accessor to the line the log event occured def line @line || (backtrace!; @line) end # Accessor to the method the log event occured def method @method || (backtrace!; @method) end private def extract!( options ) if options.is_a?(Yell::Event::Options) @level = options.severity @caller_offset = options.caller_offset else @level = options @caller_offset = 0 end end def caller_index CallerIndex + @caller_offset end def backtrace! if m = CallerRegexp.match(@caller) @file, @line, @method = m[1..-1] else @file, @line, @method = ['', '', ''] end end end end yell-2.2.2/lib/yell/repository.rb0000644000004100000410000000314413622502024016767 0ustar www-datawww-datarequire 'monitor' require "singleton" module Yell #:nodoc: class LoggerNotFound < StandardError def message; "Could not find a Yell::Logger instance with the name '#{super}'"; end end class Repository extend MonitorMixin include Singleton def initialize @loggers = {} end # Set loggers in the repository # # @example Set a logger # Yell::Repository[ 'development' ] = Yell::Logger.new :stdout # # @return [Yell::Logger] The logger instance def self.[]=( name, logger ) synchronize { instance.loggers[name] = logger } end # Get loggers from the repository # # @example Get the logger # Yell::Repository[ 'development' ] # # @raise [Yell::LoggerNotFound] Raised when repository does not have that key # @return [Yell::Logger] The logger instance def self.[]( name ) synchronize { instance.__fetch__(name) or raise Yell::LoggerNotFound.new(name) } end # Get the list of all loggers in the repository # # @return [Hash] The map of loggers def self.loggers synchronize { instance.loggers } end # @private def loggers @loggers end # @private # # Fetch the logger by the given name. # # If the logger could not be found and has a superclass, it # will attempt to look there. This is important for the # Yell::Loggable module. def __fetch__( name ) logger = loggers[name] || loggers[name.to_s] if logger.nil? && name.respond_to?(:superclass) return __fetch__(name.superclass) end logger end end end yell-2.2.2/lib/yell/silencer.rb0000644000004100000410000000346413622502024016361 0ustar www-datawww-datamodule Yell #:nodoc: # The +Yell::Silencer+ is your handly helper for stiping out unwanted log messages. class Silencer class PresetNotFound < StandardError def message; "Could not find a preset for #{super.inspect}"; end end Presets = { :assets => [/\AStarted GET "\/assets/, /\AServed asset/, /\A\s*\z/] # for Rails } def initialize( *patterns ) @patterns = patterns.dup end # Add one or more patterns to the silencer # # @example # add( 'password' ) # add( 'username', 'password' ) # # @example Add regular expressions # add( /password/ ) # # @return [self] The silencer instance def add( *patterns ) patterns.each { |pattern| add!(pattern) } self end # Clears out all the messages that would match any defined pattern # # @example # call(['username', 'password']) # #=> ['username] # # @return [Array] The remaining messages def call( *messages ) return messages if @patterns.empty? messages.reject { |m| matches?(m) } end # Get a pretty string def inspect "#<#{self.class.name} patterns: #{@patterns.inspect}>" end # @private def patterns @patterns end private def add!( pattern ) @patterns = @patterns | fetch(pattern) end def fetch( pattern ) case pattern when Symbol then Presets[pattern] or raise PresetNotFound.new(pattern) else [pattern] end end # Check if the provided message matches any of the defined patterns. # # @example # matches?('password') # #=> true # # @return [Boolean] true or false def matches?( message ) @patterns.any? { |pattern| message.respond_to?(:match) && message.match(pattern) } end end end yell-2.2.2/lib/yell/level.rb0000644000004100000410000001257113622502024015663 0ustar www-datawww-datamodule Yell #:nodoc: # The +Level+ class handles the severities for you in order to determine # if an adapter should log or not. # # In order to setup your level, you have certain modifiers available: # at :warn # will be set to :warn level only # gt :warn # Will set from :error level onwards # gte :warn # Will set from :warn level onwards # lt :warn # Will set from :info level an below # lte :warn # Will set from :warn level and below # # You are able to combine those modifiers to your convenience. # # @example Set from :info to :error (including) # Yell::Level.new(:info).lte(:error) # # @example Set from :info to :error (excluding) # Yell::Level.new(:info).lt(:error) # # @example Set at :info only # Yell::Level.new.at(:info) class Level include Comparable InterpretRegexp = /(at|gt|gte|lt|lte)?\.?(#{Yell::Severities.join('|')})/i # Create a new level instance. # # @example Enable all severities # Yell::Level.new # # @example Pass the minimum possible severity # Yell::Level.new :warn # # @example Pass an array to exactly set the level at the given severities # Yell::Level.new [:info, :error] # # @example Pass a range to set the level within the severities # Yell::Level.new (:info..:error) # # @param [Integer,String,Symbol,Array,Range,nil] severity The severity for the level. def initialize( *severities ) @tainted = false set(*severities) end # Set the severity to the given format def set( *severities ) @severities = Yell::Severities.map { true } severity = severities.length > 1 ? severities : severities.first case severity when Array then at(*severity) when Range then gte(severity.first).lte(severity.last) when String then interpret(severity) when Integer, Symbol then gte(severity) when Yell::Level then @severities = severity.severities end end # Returns whether the level is allowed at the given severity # # @example # at? :warn # at? 0 # debug # # @return [Boolean] tru or false def at?( severity ) index = index_from(severity) index.nil? ? false : @severities[index] end # Set the level at specific severities # # @example Set at :debug and :error only # at :debug, :error # # @return [Yell::Level] the instance def at( *severities ) severities.each { |severity| calculate! :==, severity } self end # Set the level to greater than the given severity # # @example Set to :error and above # gt :warn # # @return [Yell::Level] the instance def gt( severity ) calculate! :>, severity self end # Set the level greater or equal to the given severity # # @example Set to :warn and above # gte :warn # # @return [Yell::Level] the instance def gte( severity ) calculate! :>=, severity self end # Set the level lower than given severity # # @example Set to lower than :warn # lt :warn # # @return [Yell::Level] the instance def lt( severity ) calculate! :<, severity self end # Set the level lower or equal than given severity # # @example Set to lower or equal than :warn # lte :warn # # @return [Yell::Level] the instance def lte( severity ) calculate! :<=, severity self end # to_i implements backwards compatibility def to_i @severities.each_with_index { |s,i| return i if s == true } end alias :to_int :to_i # Get a pretty string representation of the level, including the severities. def inspect inspectables = Yell::Severities.select.with_index { |l, i| !!@severities[i] } "#<#{self.class.name} severities: #{inspectables * ', '}>" end # @private def severities @severities end # @private def ==(other) other.respond_to?(:severities) ? severities == other.severities : super end # @private def <=>( other ) other.is_a?(Numeric) ? to_i <=> other : super end private def interpret( severities ) severities.split( ' ' ).each do |severity| if m = InterpretRegexp.match(severity) m[1].nil? ? __send__( :gte, m[2] ) : __send__( m[1], m[2] ) end end end def calculate!( modifier, severity ) index = index_from(severity) return if index.nil? case modifier when :> then ascending!( index+1 ) when :>= then ascending!( index ) when :< then descending!( index-1 ) when :<= then descending!( index ) else set!( index ) # :== end @tainted = true unless @tainted end def index_from( severity ) case severity when String, Symbol then Yell::Severities.index(severity.to_s.upcase) else Integer(severity) end end def ascending!( index ) each { |s, i| @severities[i] = i < index ? false : true } end def descending!( index ) each { |s, i| @severities[i] = index < i ? false : true } end def each @severities.each_with_index do |s, i| next if s == false # skip yield(s, i) end end def set!( index, val = true ) @severities.map! { false } unless @tainted @severities[index] = val end end end yell-2.2.2/lib/yell/logger.rb0000644000004100000410000001116313622502024016027 0ustar www-datawww-datarequire 'pathname' module Yell #:nodoc: # The +Yell::Logger+ is your entrypoint. Anything onwards is derived from here. # # A +Yell::Logger+ instance holds all your adapters and sends the log events # to them if applicable. There are multiple ways of how to create a new logger. class Logger include Yell::Helpers::Base include Yell::Helpers::Level include Yell::Helpers::Formatter include Yell::Helpers::Adapter include Yell::Helpers::Tracer include Yell::Helpers::Silencer # The name of the logger instance attr_reader :name # Initialize a new Logger # # @example A standard file logger # Yell::Logger.new 'development.log' # # @example A standard datefile logger # Yell::Logger.new :datefile # Yell::Logger.new :datefile, 'development.log' # # @example Setting the log level # Yell::Logger.new level: :warn # # Yell::Logger.new do |l| # l.level = :warn # end # # @example Combined settings # Yell::Logger.new 'development.log', level: :warn # # Yell::Logger.new :datefile, 'development.log' do |l| # l.level = :info # end def initialize( *args, &block ) # extract options @options = args.last.is_a?(Hash) ? args.pop : {} # check if filename was given as argument and put it into the @options if [String, Pathname].include?(args.last.class) @options[:filename] = args.pop unless @options[:filename] end reset! # FIXME: :format is deprecated in future versions --R self.formatter = Yell.__fetch__(@options, :format, :formatter) self.level = Yell.__fetch__(@options, :level, :default => 0) self.name = Yell.__fetch__(@options, :name) self.trace = Yell.__fetch__(@options, :trace, default: :error) # silencer self.silence(*Yell.__fetch__(@options, :silence, default: [])) # adapters may be passed in the options extract!(*Yell.__fetch__(@options, :adapters, default: [])) # extract adapter self.adapter(args.pop) if args.any? # eval the given block block.arity > 0 ? block.call(self) : instance_eval(&block) if block_given? # default adapter when none defined self.adapter(:file) if adapters.empty? end # Set the name of a logger. When providing a name, the logger will # automatically be added to the Yell::Repository. # # @return [String] The logger's name def name=( val ) Yell::Repository[val] = self if val @name = val.nil? ? "<#{self.class.name}##{object_id}>": val @name end # Somewhat backwards compatible method (not fully though) def add( options, *messages, &block ) return false unless level.at?(options) messages = messages messages << block.call unless block.nil? messages = silencer.call(*messages) return false if messages.empty? event = Yell::Event.new(self, options, *messages) write(event) end # Creates instance methods for every log level: # `debug` and `debug?` # `info` and `info?` # `warn` and `warn?` # `error` and `error?` # `unknown` and `unknown?` Yell::Severities.each_with_index do |s, index| name = s.downcase class_eval <<-EOS, __FILE__, __LINE__ + index def #{name}?; level.at?(#{index}); end # def info?; level.at?(1); end # def #{name}( *m, &b ) # def info( *m, &b ) options = Yell::Event::Options.new(#{index}, 1) add(options, *m, &b) # add(Yell::Event::Options.new(1, 1), *m, &b) end # end EOS end # Get a pretty string representation of the logger. def inspect inspection = inspectables.map { |m| "#{m}: #{send(m).inspect}" } "#<#{self.class.name} #{inspection * ', '}>" end # @private def close adapters.close end # @private def write( event ) adapters.write(event) end private # The :adapters key may be passed to the options hash. It may appear in # multiple variations: # # @example # extract!(:stdout, :stderr) # # @example # extract!(stdout: {level: :info}, stderr: {level: :error}) def extract!( *list ) list.each do |a| if a.is_a?(Hash) a.each { |t, o| adapter(t, o) } else adapter(a) end end end # Get an array of inspected attributes for the adapter. def inspectables [:name] | super end end end yell-2.2.2/lib/yell/adapters.rb0000644000004100000410000000427213622502024016356 0ustar www-datawww-datamodule Yell #:nodoc: # AdapterNotFound is raised whenever you want to instantiate an # adapter that does not exist. class AdapterNotFound < StandardError; end # This module provides the interface to attaching adapters to # the logger. You should not have to call the corresponding classes # directly. module Adapters class Collection def initialize( options = {} ) @options = options @collection = [] end def add( type = :file, *args, &block ) options = [@options, *args].inject(Hash.new) do |h, c| h.merge( [String, Pathname].include?(c.class) ? {:filename => c} : c ) end # remove possible :null adapters @collection.shift if @collection.first.instance_of?(Yell::Adapters::Base) new_adapter = Yell::Adapters.new(type, options, &block) @collection.push(new_adapter) new_adapter end def empty? @collection.empty? end # @private def write( event ) @collection.each { |c| c.write(event) } true end # @private def close @collection.each { |c| c.close } end end # holds the list of known adapters @adapters = {} # Register your own adapter here # # @example # Yell::Adapters.register( :myadapter, MyAdapter ) def self.register( name, klass ) @adapters[name.to_sym] = klass end # Returns an instance of the given processor type. # # @example A simple file adapter # Yell::Adapters.new( :file ) def self.new( type, options = {}, &block ) return type if type.is_a?(Yell::Adapters::Base) adapter = case type when STDOUT then @adapters[:stdout] when STDERR then @adapters[:stderr] else @adapters[type.to_sym] end raise AdapterNotFound.new(type) if adapter.nil? adapter.new(options, &block) end end end # Base for all adapters require File.dirname(__FILE__) + '/adapters/base' # IO based adapters require File.dirname(__FILE__) + '/adapters/io' require File.dirname(__FILE__) + '/adapters/streams' require File.dirname(__FILE__) + '/adapters/file' require File.dirname(__FILE__) + '/adapters/datefile' yell-2.2.2/Gemfile0000644000004100000410000000066713622502024014012 0ustar www-datawww-data# frozen_string_literal: true source 'http://rubygems.org' # Specify your gem's dependencies in yell.gemspec gemspec group :development, :test do gem 'rake' gem 'rspec-core', '~> 3' gem 'rspec-expectations' gem 'rspec-its' gem 'rspec-mocks' gem 'byebug', platform: :mri gem 'timecop' gem 'activesupport', '~> 5' gem 'coveralls', require: false gem 'rubocop', require: false gem 'simplecov', require: false end yell-2.2.2/.ruby-version0000644000004100000410000000000613622502024015147 0ustar www-datawww-data2.3.1 yell-2.2.2/LICENSE.txt0000644000004100000410000000205313622502024014331 0ustar www-datawww-dataCopyright (c) 2011-current Rudolf Schmidt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.