yell-2.0.5/0000755000175000017500000000000012577437450012415 5ustar mcrusoemcrusoeyell-2.0.5/metadata.yml0000644000175000017500000000702412577437450014723 0ustar mcrusoemcrusoe--- !ruby/object:Gem::Specification name: yell version: !ruby/object:Gem::Version version: 2.0.5 platform: ruby authors: - Rudolf Schmidt autorequire: bindir: bin cert_chain: [] date: 2014-10-14 00:00:00.000000000 Z dependencies: [] description: Yell - Your Extensible Logging Library. Define multiple adapters, various log level combinations or message formatting options like you've never done before email: executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - Gemfile - LICENSE.txt - README.md - Rakefile - examples/001-basic-usage.rb - examples/002.1-log-level-basics.rb - examples/002.2-log-level-on-certain-severities-only.rb - examples/002.3-log-level-within-range.rb - examples/003.1-formatting-DefaultFormat.rb - examples/003.2-formatting-BasicFormat.rb - examples/003.3-formatting-ExtendedFormat.rb - examples/003.4-formatting-on-your-own.rb - examples/004.1-colorizing-the-log-output.rb - examples/005.1-repository.rb - examples/006.1-the-loggable-module.rb - examples/006.2-the-loggable-module-with-inheritance.rb - lib/core_ext/logger.rb - lib/yell.rb - lib/yell/adapters.rb - lib/yell/adapters/base.rb - lib/yell/adapters/datefile.rb - lib/yell/adapters/file.rb - lib/yell/adapters/io.rb - lib/yell/adapters/streams.rb - lib/yell/configuration.rb - lib/yell/event.rb - lib/yell/formatter.rb - lib/yell/helpers/adapter.rb - lib/yell/helpers/base.rb - lib/yell/helpers/formatter.rb - lib/yell/helpers/level.rb - lib/yell/helpers/silencer.rb - lib/yell/helpers/tracer.rb - lib/yell/level.rb - lib/yell/loggable.rb - lib/yell/logger.rb - lib/yell/repository.rb - lib/yell/silencer.rb - lib/yell/version.rb - spec/compatibility/activesupport_logger_spec.rb - spec/compatibility/formatter_spec.rb - spec/compatibility/level_spec.rb - spec/fixtures/yell.yml - spec/spec_helper.rb - spec/threaded/yell_spec.rb - spec/yell/adapters/base_spec.rb - spec/yell/adapters/datefile_spec.rb - spec/yell/adapters/file_spec.rb - spec/yell/adapters/io_spec.rb - spec/yell/adapters/streams_spec.rb - spec/yell/adapters_spec.rb - spec/yell/configuration_spec.rb - spec/yell/dsl_spec.rb - spec/yell/event_spec.rb - spec/yell/formatter_spec.rb - spec/yell/level_spec.rb - spec/yell/loggable_spec.rb - spec/yell/logger_spec.rb - spec/yell/repository_spec.rb - spec/yell/silencer_spec.rb - spec/yell_spec.rb - yell.gemspec homepage: http://rudionrailspec.github.com/yell licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: yell rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: Yell - Your Extensible Logging Library test_files: - spec/compatibility/activesupport_logger_spec.rb - spec/compatibility/formatter_spec.rb - spec/compatibility/level_spec.rb - spec/fixtures/yell.yml - spec/spec_helper.rb - spec/threaded/yell_spec.rb - spec/yell/adapters/base_spec.rb - spec/yell/adapters/datefile_spec.rb - spec/yell/adapters/file_spec.rb - spec/yell/adapters/io_spec.rb - spec/yell/adapters/streams_spec.rb - spec/yell/adapters_spec.rb - spec/yell/configuration_spec.rb - spec/yell/dsl_spec.rb - spec/yell/event_spec.rb - spec/yell/formatter_spec.rb - spec/yell/level_spec.rb - spec/yell/loggable_spec.rb - spec/yell/logger_spec.rb - spec/yell/repository_spec.rb - spec/yell/silencer_spec.rb - spec/yell_spec.rb yell-2.0.5/yell.gemspec0000644000175000017500000000155612577437450014736 0ustar mcrusoemcrusoe# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $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.homepage = "http://rudionrailspec.github.com/yell" spec.summary = %q{Yell - Your Extensible Logging Library} spec.description = %q{Yell - Your Extensible Logging Library. Define multiple adapters, various log level combinations or message formatting options like you've never done before} spec.rubyforge_project = "yell" spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] end yell-2.0.5/spec/0000755000175000017500000000000012577437450013347 5ustar mcrusoemcrusoeyell-2.0.5/spec/yell_spec.rb0000644000175000017500000000373112577437450015657 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell do let( :logger ) { Yell.new } subject { logger } it { should be_kind_of Yell::Logger } it "should raise AdapterNotFound when adapter cant be loaded" do expect { Yell.new :unknownadapter }.to raise_error(Yell::AdapterNotFound) end context ".level" do subject { Yell.level } it { should be_kind_of Yell::Level } end context ".format" do subject { Yell.format( "%m" ) } it { should be_kind_of Yell::Formatter } end context ".load!" do subject { Yell.load!('yell.yml') } before do mock(Yell::Configuration).load!('yell.yml') { {} } end it { should be_kind_of Yell::Logger } end context ".[]" do let(:name) { 'test' } it "should delegate to the repository" do mock(Yell::Repository)[name] Yell[name] end end context ".[]=" do let(:name) { 'test' } it "should delegate to the repository" do mock.proxy(Yell::Repository)[name] = logger Yell[name] = logger end end context ".env" do subject { Yell.env } it "should default to YELL_ENV" do subject.should == 'test' end context "fallback to RACK_ENV" do before do stub(ENV).key?('YELL_ENV') { false } mock(ENV).key?('RACK_ENV') { true } ENV['RACK_ENV'] = 'rack' end after { ENV.delete 'RACK_ENV' } it { should == 'rack' } end context "fallback to RAILS_ENV" do before do stub(ENV).key?('YELL_ENV') { false } stub(ENV).key?('RACK_ENV') { false } mock(ENV).key?('RAILS_ENV') { true } ENV['RAILS_ENV'] = 'rails' end after { ENV.delete 'RAILS_ENV' } it { should == 'rails' } end context "fallback to development" do before do stub(ENV).key?('YELL_ENV') { false } stub(ENV).key?('RACK_ENV') { false } stub(ENV).key?('RAILS_ENV') { false } end it { should == 'development' } end end end yell-2.0.5/spec/yell/0000755000175000017500000000000012577437450014314 5ustar mcrusoemcrusoeyell-2.0.5/spec/yell/silencer_spec.rb0000644000175000017500000000152012577437450017455 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Silencer do context "initialize with #patterns" do subject { Yell::Silencer.new(/this/) } its(:patterns) { should eq([/this/]) } end context "#add" do let(:silencer) { Yell::Silencer.new } it "should add patterns" do silencer.add /this/, /that/ expect(silencer.patterns).to eq([/this/, /that/]) end it "should ignore duplicate patterns" do silencer.add /this/, /that/, /this/ expect(silencer.patterns).to eq([/this/, /that/]) end end context "#call" do let(:silencer) { Yell::Silencer.new(/this/) } it "should reject messages that match any pattern" do expect(silencer.call("this")).to eq([]) expect(silencer.call("that")).to eq(["that"]) expect(silencer.call("this", "that")).to eq(["that"]) end end end yell-2.0.5/spec/yell/repository_spec.rb0000644000175000017500000000343212577437450020074 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Repository do let(:name) { 'test' } let(:logger) { Yell.new(:stdout) } subject { Yell::Repository[name] } context ".[]" do it "should raise when not set" do expect { subject }.to raise_error(Yell::LoggerNotFound) end context "when logger with :name exists" do let!(:logger) { Yell.new(:stdout, :name => name) } it { should eq(logger) } end context "given a Class" do let!(:logger) { Yell.new(:stdout, :name => "Numeric") } it "should raise with the correct :name when logger not found" do mock.proxy(Yell::LoggerNotFound).new(String) lambda { Yell::Repository[String] }.should raise_error(Yell::LoggerNotFound) end it "should return the logger" do Yell::Repository[Numeric].should eq(logger) end it "should return the logger when superclass has it defined" do Yell::Repository[Integer].should eq(logger) end end end context ".[]=" do before { Yell::Repository[name] = logger } it { should eq(logger) } end context ".[]= with a named logger" do let!(:logger) { Yell.new(:stdout, :name => name) } before { Yell::Repository[name] = logger } it { should eq(logger) } end context ".[]= with a named logger of a different name" do let(:other) { 'other' } let(:logger) { Yell.new(:stdout, :name => other) } before { Yell::Repository[name] = logger } it "should add logger to both repositories" do Yell::Repository[name].should eq(logger) Yell::Repository[other].should eq(logger) end end context "loggers" do let(:loggers) { { name => logger } } subject { Yell::Repository.loggers } before { Yell::Repository[name] = logger } it { should eq(loggers) } end end yell-2.0.5/spec/yell/logger_spec.rb0000644000175000017500000001563112577437450017140 0ustar mcrusoemcrusoerequire 'spec_helper' class LoggerFactory attr_accessor :logger def info logger.info :foo end def add logger.add 1, :bar end end describe Yell::Logger do let(:filename) { fixture_path + '/logger.log' } describe "a Logger instance" do let(:logger) { Yell::Logger.new } subject { logger } context "log methods" do it { should respond_to(:debug) } it { should respond_to(:debug?) } it { should respond_to(:info) } it { should respond_to(:info?) } it { should respond_to(:warn) } it { should respond_to(:warn?) } it { should respond_to(:error) } it { should respond_to(:error?) } it { should respond_to(:fatal) } it { should respond_to(:fatal?) } it { should respond_to(:unknown) } it { should respond_to(:unknown?) } end context "default #name" do its(:name) { should eq("") } it "should not be added to the repository" do expect { Yell::Repository[logger.name] }.to raise_error(Yell::LoggerNotFound) end end context "default #adapter" do subject { logger.adapters.instance_variable_get(:@collection) } its(:size) { should == 1 } its(:first) { should be_kind_of(Yell::Adapters::File) } end context "default #level" do subject { logger.level } it { should be_instance_of(Yell::Level) } its(:severities) { should eq([true, true, true, true, true, true]) } end context "default #trace" do subject { logger.trace } it { should be_instance_of(Yell::Level) } its(:severities) { should eq([false, false, false, true, true, true]) } # from error onwards end end describe "initialize with #name" do let(:name) { 'test' } let!(:logger) { Yell.new(:name => name) } it "should set the name correctly" do expect(logger.name).to eq(name) end it "should be added to the repository" do expect(Yell::Repository[name]).to eq(logger) end end context "initialize with #level" do let(:level) { :error } let(:logger) { Yell.new(:level => level) } subject { logger.level } it { should be_instance_of(Yell::Level) } its(:severities) { should eq([false, false, false, true, true, true]) } end context "initialize with #trace" do let(:trace) { :info } let(:logger) { Yell.new(:trace => trace) } subject { logger.trace } it { should be_instance_of(Yell::Level) } its(:severities) { should eq([false, true, true, true, true, true]) } end context "initialize with #silence" do let(:silence) { "test" } let(:logger) { Yell.new(:silence => silence) } subject { logger.silencer } it { should be_instance_of(Yell::Silencer) } its(:patterns) { should eq([silence]) } end context "initialize with a #filename" do it "should call adapter with :file" do mock.proxy(Yell::Adapters::File).new(:filename => filename) Yell::Logger.new(filename) end end context "initialize with a #filename of Pathname type" do let(:pathname) { Pathname.new(filename) } it "should call adapter with :file" do mock.proxy(Yell::Adapters::File).new(:filename => pathname) Yell::Logger.new(pathname) end end context "initialize with a :stdout adapter" do before { mock.proxy(Yell::Adapters::Stdout).new(anything) } it "should call adapter with STDOUT" do Yell::Logger.new(STDOUT) end it "should call adapter with :stdout" do Yell::Logger.new(:stdout) end end context "initialize with a :stderr adapter" do before { mock.proxy(Yell::Adapters::Stderr).new(anything) } it "should call adapter with STDERR" do Yell::Logger.new(STDERR) end it "should call adapter with :stderr" do Yell::Logger.new(:stderr) end end context "initialize with a block" do let(:level) { Yell::Level.new :error } let(:adapters) { logger.adapters.instance_variable_get(:@collection) } context "with arity" do let(:logger) do Yell::Logger.new(:level => level) { |l| l.adapter(:stdout) } end it "should pass the level correctly" do expect(logger.level).to eq(level) end it "should pass the adapter correctly" do expect(adapters.first).to be_instance_of(Yell::Adapters::Stdout) end end context "without arity" do let(:logger) do Yell::Logger.new(:level => level) { adapter(:stdout) } end it "should pass the level correctly" do expect(logger.level).to eq(level) end it "should pass the adapter correctly" do expect(adapters.first).to be_instance_of(Yell::Adapters::Stdout) end end end context "initialize with #adapters option" do it "should set adapters in logger correctly" do any_instance_of(Yell::Logger) do |logger| mock.proxy(logger).adapter(:stdout) mock.proxy(logger).adapter(:stderr, :level => :error) end Yell::Logger.new(:adapters => [:stdout, {:stderr => {:level => :error}}]) end end context "caller's :file, :line and :method" do let(:stdout) { Yell::Adapters::Stdout.new(:format => "%F, %n: %M") } let(:logger) { Yell::Logger.new(:trace => true) { |l| l.adapter(stdout) } } it "should write correctly" do factory = LoggerFactory.new factory.logger = logger mock(stdout.send(:stream)).syswrite("#{__FILE__}, 7: info\n") mock(stdout.send(:stream)).syswrite("#{__FILE__}, 11: add\n") factory.info factory.add end end context "logging in general" do let(:logger) { Yell::Logger.new(filename, :format => "%m") } let(:line) { File.open(filename, &:readline) } it "should output a single message" do logger.info "Hello World" expect(line).to eq("Hello World\n") end it "should output multiple messages" do logger.info ["Hello", "W", "o", "r", "l", "d"] expect(line).to eq("Hello W o r l d\n") end it "should output a hash and message" do logger.info ["Hello World", {:test => :message}] expect(line).to eq("Hello World test: message\n") end it "should output a hash and message" do logger.info [{:test => :message}, "Hello World"] expect(line).to eq("test: message Hello World\n") end it "should output a hash and block" do logger.info(:test => :message) { "Hello World" } expect(line).to eq("test: message Hello World\n") end end context "logging with a silencer" do let(:silence) { "this" } let(:stdout) { Yell::Adapters::Stdout.new } let(:logger) { Yell::Logger.new(stdout, :silence => silence) } it "should not pass a matching message to any adapter" do dont_allow(stdout).write logger.info "this should not be logged" end it "should pass a non-matching message to any adapter" do mock(stdout).write(is_a(Yell::Event)) logger.info "that should be logged" end end end yell-2.0.5/spec/yell/loggable_spec.rb0000644000175000017500000000051512577437450017430 0ustar mcrusoemcrusoerequire 'spec_helper' class LoggableFactory include Yell::Loggable end describe Yell::Loggable do let(:factory) { LoggableFactory.new } subject { factory } it { should respond_to(:logger) } it "should make a lookup in the Yell::Repository" do mock(Yell::Repository)[LoggableFactory] factory.logger end end yell-2.0.5/spec/yell/level_spec.rb0000644000175000017500000001310412577437450016761 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Level do context "default" do let(:level) { Yell::Level.new } it "should should return correctly" do expect(level.at?(:debug)).to be_true expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context "given a Symbol" do let(:level) { Yell::Level.new(severity) } context ":debug" do let(:severity) { :debug } it "should should return correctly" do expect(level.at?(:debug)).to be_true expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context ":info" do let(:severity) { :info } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context ":warn" do let(:severity) { :warn } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context ":error" do let(:severity) { :error } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_false expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context ":fatal" do let(:severity) { :fatal } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_false expect(level.at?(:error)).to be_false expect(level.at?(:fatal)).to be_true end end end context "given a String" do let(:level) { Yell::Level.new(severity) } context "basic string" do let(:severity) { 'error' } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_false expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context "complex string with outer boundaries" do let(:severity) { 'gte.info lte.error' } it "should should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_false end end context "complex string with inner boundaries" do let(:severity) { 'gt.info lt.error' } it "should be valid" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_false expect(level.at?(:fatal)).to be_false end end context "complex string with precise boundaries" do let(:severity) { 'at.info at.error' } it "should be valid" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_false expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_false end end context "complex string with combined boundaries" do let(:severity) { 'gte.error at.debug' } it "should be valid" do expect(level.at?(:debug)).to be_true expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_false expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end end context "given an Array" do let(:level) { Yell::Level.new( [:debug, :warn, :fatal] ) } it "should return correctly" do expect(level.at?(:debug)).to be_true expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_false expect(level.at?(:fatal)).to be_true end end context "given a Range" do let(:level) { Yell::Level.new( (1..3) ) } it "should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_true expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_false end end context "given a Yell::Level instance" do let(:level) { Yell::Level.new(:warn) } it "should return correctly" do expect(level.at?(:debug)).to be_false expect(level.at?(:info)).to be_false expect(level.at?(:warn)).to be_true expect(level.at?(:error)).to be_true expect(level.at?(:fatal)).to be_true end end context "backwards compatibility" do let(:level) { Yell::Level.new :warn } it "should return correctly to :to_i" do expect(level.to_i).to eq(2) end it "should typecast with Integer correctly" do expect(Integer(level)).to eq(2) end it "should be compatible when passing to array (https://github.com/rudionrails/yell/issues/1)" do severities = %w(FINE INFO WARNING SEVERE SEVERE INFO) expect(severities[level]).to eq("WARNING") end end end yell-2.0.5/spec/yell/formatter_spec.rb0000644000175000017500000000636712577437450017672 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Formatter do let(:logger) { Yell::Logger.new(:stdout, :name => 'Yell') } let(:message) { "Hello World!" } let(:event) { Yell::Event.new(logger, 1, message) } let(:pattern) { "%m" } let(:formatter) { Yell::Formatter.new(pattern) } let(:time) { Time.now } subject { formatter.call(event) } before do Timecop.freeze(time) end describe "patterns" do context "%m" do let(:pattern) { "%m" } it { should eq("#{event.messages.join(' ')}\n") } end context "%l" do let(:pattern) { "%l" } it { should eq("#{Yell::Severities[event.level][0,1]}\n") } end context "%L" do let(:pattern) { "%L" } it { should eq("#{Yell::Severities[event.level]}\n") } end context "%d" do let(:pattern) { "%d" } it { should eq("#{event.time.iso8601}\n") } end context "%p" do let(:pattern) { "%p" } it { should eq("#{event.pid}\n") } end context "%P" do let(:pattern) { "%P" } it { should eq("#{event.progname}\n") } end context "%t" do let(:pattern) { "%t" } it { should eq("#{event.thread_id}\n") } end context "%h" do let(:pattern) { "%h" } it { should eq("#{event.hostname}\n") } end context ":caller" do let(:_caller) { [nil, nil, "/path/to/file.rb:123:in `test_method'"] } before do any_instance_of(Yell::Event) do |e| stub(e).file { "/path/to/file.rb" } stub(e).line { "123" } stub(e).method { "test_method" } end end context "%F" do let(:pattern) { "%F" } it { should eq("/path/to/file.rb\n") } end context "%f" do let(:pattern) { "%f" } it { should eq("file.rb\n") } end context "%M" do let(:pattern) { "%M" } it { should eq("test_method\n") } end context "%n" do let(:pattern) { "%n" } it { should eq("123\n") } end end context "%N" do let(:pattern) { "%N" } it { should eq("Yell\n") } end end describe "presets" do context "NoFormat" do let(:pattern) { Yell::NoFormat } it { should eq("Hello World!\n") } end context "DefaultFormat" do let(:pattern) { Yell::DefaultFormat } it { should eq("#{time.iso8601} [ INFO] #{$$} : Hello World!\n") } end context "BasicFormat" do let(:pattern) { Yell::BasicFormat } it { should eq("I, #{time.iso8601} : Hello World!\n") } end context "ExtendedFormat" do let(:pattern) { Yell::ExtendedFormat } it { should eq("#{time.iso8601} [ INFO] #{$$} #{Socket.gethostname} : Hello World!\n") } end end describe "Exception" do let(:message) { StandardError.new("This is an Exception") } before do stub(message).backtrace { ["backtrace"] } end it { should eq("StandardError: This is an Exception\n\tbacktrace\n") } end describe "Hash" do let(:message) { {:test => 'message'} } it { should eq("test: message\n") } end describe "custom message modifiers" do let(:formatter) do Yell::Formatter.new(pattern) { |f| f.modify(String) { |m| "Modified! #{m}" } } end it { should eq("Modified! #{message}\n") } end end yell-2.0.5/spec/yell/event_spec.rb0000644000175000017500000000400112577437450016767 0ustar mcrusoemcrusoerequire 'spec_helper' # Since Yell::Event.new is not called directly, but through # the logger methods, we need to divert here in order to get # the correct caller. class EventFactory def self.event(logger, level, message) self._event(logger, level, message) end private def self._event(logger, level, message) Yell::Event.new(logger, level, message) end end describe Yell::Event do let(:logger) { Yell::Logger.new(:trace => true) } let(:event) { Yell::Event.new(logger, 1, 'Hello World!') } context "#level" do subject { event.level } it { should eq(1) } end context "#messages" do subject { event.messages } it { should eq(['Hello World!']) } end context "#time" do let(:time) { Time.now } subject { event.time.to_s } before { Timecop.freeze(time) } it { should eq(time.to_s) } end context "#hostname" do subject { event.hostname } it { should eq(Socket.gethostname) } end context "#pid" do subject { event.pid } it { should eq(Process.pid) } end context "#id when forked", :pending => RUBY_PLATFORM == 'java' ? "No forking with jruby" : false do subject { @pid } before do read, write = IO.pipe @pid = Process.fork do event = Yell::Event.new(logger, 1, 'Hello World!') write.puts event.pid end Process.wait write.close @child_pid = read.read.to_i read.close end it { should_not eq(Process.pid) } it { should eq(@child_pid) } end context "#progname" do subject { event.progname } it { should eq($0) } end context ":caller" do subject { EventFactory.event(logger, 1, "Hello World") } context "with trace" do its(:file) { should eq(__FILE__) } its(:line) { should eq("8") } its(:method) { should eq("event") } end context "without trace" do before { logger.trace = false } its(:file) { should eq("") } its(:line) { should eq("") } its(:method) { should eq("") } end end end yell-2.0.5/spec/yell/dsl_spec.rb0000644000175000017500000000161512577437450016440 0ustar mcrusoemcrusoerequire 'spec_helper' describe "Yell Adapter DSL spec" do class DSLAdapter < Yell::Adapters::Base setup do |options| @test_setup = true end write do |event| @test_write = true end close do @test_close = true end def test_setup?; !!@test_setup; end def test_write?; !!@test_write; end def test_close?; !!@test_close; end end it "should perform #setup" do adapter = DSLAdapter.new expect(adapter.test_setup?).to be_true end it "should perform #write" do event = 'event' stub(event).level { 0 } adapter = DSLAdapter.new expect(adapter.test_write?).to be_false adapter.write(event) expect(adapter.test_write?).to be_true end it "should perform #close" do adapter = DSLAdapter.new expect(adapter.test_close?).to be_false adapter.close expect(adapter.test_close?).to be_true end end yell-2.0.5/spec/yell/configuration_spec.rb0000644000175000017500000000135012577437450020521 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Configuration do describe ".load!" do let(:file) { fixture_path + '/yell.yml' } let(:config) { Yell::Configuration.load!(file) } subject { config } it { should be_kind_of(Hash) } it { should have_key(:level) } it { should have_key(:adapters) } context ":level" do subject { config[:level] } it { should eq("info") } end context ":adapters" do subject { config[:adapters] } it { should be_kind_of(Array) } # stdout it { expect(subject.first).to eq(:stdout) } # stderr it { expect(subject.last).to be_kind_of(Hash) } it { expect(subject.last).to eq(:stderr => {:level => 'gte.error'}) } end end end yell-2.0.5/spec/yell/adapters_spec.rb0000644000175000017500000000164612577437450017465 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters do context ".new" do it "should accept an adapter instance" do stdout = Yell::Adapters::Stdout.new adapter = Yell::Adapters.new(stdout) expect(adapter).to eq(stdout) end it "should accept STDOUT" do mock.proxy(Yell::Adapters::Stdout).new(anything) Yell::Adapters.new(STDOUT) end it "should accept STDERR" do mock.proxy(Yell::Adapters::Stderr).new(anything) Yell::Adapters.new(STDERR) end it "should raise an unregistered adapter" do expect { Yell::Adapters.new :unknown }.to raise_error(Yell::AdapterNotFound) end end context ".register" do let(:name) { :test } let(:klass) { mock } before { Yell::Adapters.register(name, klass) } it "should allow to being called from :new" do mock(klass).new(anything) Yell::Adapters.new(name) end end end yell-2.0.5/spec/yell/adapters/0000755000175000017500000000000012577437450016117 5ustar mcrusoemcrusoeyell-2.0.5/spec/yell/adapters/streams_spec.rb0000644000175000017500000000067212577437450021141 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters::Stdout do it { should be_kind_of(Yell::Adapters::Io) } context "#stream" do subject { Yell::Adapters::Stdout.new.send :stream } it { should be_kind_of(IO) } end end describe Yell::Adapters::Stderr do it { should be_kind_of(Yell::Adapters::Io) } context "#stream" do subject { Yell::Adapters::Stderr.new.send(:stream) } it { should be_kind_of(IO) } end end yell-2.0.5/spec/yell/adapters/io_spec.rb0000644000175000017500000000322412577437450020066 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters::Io do it { should be_kind_of Yell::Adapters::Base } context "initialize" do it "should set default :format" do adapter = Yell::Adapters::Io.new expect(adapter.format).to be_kind_of(Yell::Formatter) end context ":level" do let(:level) { Yell::Level.new(:warn) } it "should set the level" do adapter = Yell::Adapters::Io.new(:level => level) expect(adapter.level).to eq(level) end it "should set the level when block was given" do adapter = Yell::Adapters::Io.new { |a| a.level = level } expect(adapter.level).to eq(level) end end context ":format" do let(:format) { Yell::Formatter.new } it "should set the level" do adapter = Yell::Adapters::Io.new(:format => format) expect(adapter.format).to eq(format) end it "should set the level when block was given" do adapter = Yell::Adapters::Io.new { |a| a.format = format } expect(adapter.format).to eq(format) end end end context "#write" do let(:logger) { Yell::Logger.new } let(:event) { Yell::Event.new(logger, 1, "Hello World") } let(:adapter) { Yell::Adapters::Io.new } let(:stream) { File.new('/dev/null', 'w') } before do stub(adapter).stream { stream } end it "should format the message" do mock.proxy(adapter.format).call( event ) adapter.write(event) end it "should print formatted message to stream" do formatted = Yell::Formatter.new.call(event) mock(stream).syswrite(formatted) adapter.write(event) end end end yell-2.0.5/spec/yell/adapters/file_spec.rb0000644000175000017500000000345612577437450020405 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters::File do let(:devnull) { File.new('/dev/null', 'w') } before do stub(File).open(anything, anything) { devnull } end it { should be_kind_of(Yell::Adapters::Io) } context "#stream" do subject { Yell::Adapters::File.new.send(:stream) } it { should be_kind_of(File) } end context "#write" do let(:logger) { Yell::Logger.new } let(:event) { Yell::Event.new(logger, 1, "Hello World") } context "default filename" do let(:filename) { File.expand_path "#{Yell.env}.log" } let(:adapter) { Yell::Adapters::File.new } it "should print to file" do mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull } adapter.write(event) end end context "with given :filename" do let(:filename) { fixture_path + '/filename.log' } let(:adapter) { Yell::Adapters::File.new(:filename => filename) } it "should print to file" do mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull } adapter.write(event) end end context "with given :pathname" do let(:pathname) { Pathname.new(fixture_path).join('filename.log') } let(:adapter) { Yell::Adapters::File.new( :filename => pathname ) } it "should accept pathanme as filename" do mock(File).open(pathname.to_s, File::WRONLY|File::APPEND|File::CREAT) { devnull } adapter.write(event) end end context "#sync" do let(:adapter) { Yell::Adapters::File.new } it "should sync by default" do mock(devnull).sync=(true) adapter.write(event) end it "pass the option to File" do adapter.sync = false mock(devnull).sync=(false) adapter.write(event) end end end end yell-2.0.5/spec/yell/adapters/datefile_spec.rb0000644000175000017500000001037412577437450021240 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters::Datefile do let(:logger) { Yell::Logger.new } let(:message) { "Hello World" } let(:event) { Yell::Event.new(logger, 1, message) } let(:today) { Time.now } let(:tomorrow) { Time.now + 86400 } let(:filename) { fixture_path + '/test.log' } let(:today_filename) { fixture_path + "/test.#{today.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" } let(:tomorrow_filename) { fixture_path + "/test.#{tomorrow.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" } let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename, :format => "%m") } before do Timecop.freeze(today) end it { should be_kind_of Yell::Adapters::File } describe "#write" do let(:today_lines) { File.readlines(today_filename) } before do adapter.write(event) end it "should be output to filename with date pattern" do expect(File.exist?(today_filename)).to be_true expect(today_lines.size).to eq(2) # includes header line expect(today_lines.last).to match(message) end it "should output to the same file" do adapter.write(event) expect(File.exist?(today_filename)).to be_true expect(today_lines.size).to eq(3) # includes header line end it "should not open file handle again" do dont_allow(File).open(anything, anything) adapter.write(event) end context "on rollover" do let(:tomorrow_lines) { File.readlines(tomorrow_filename) } before do Timecop.freeze(tomorrow) { adapter.write(event) } end it "should rotate file" do expect(File.exist?(tomorrow_filename)).to be_true expect(tomorrow_lines.size).to eq(2) # includes header line expect(tomorrow_lines.last).to match(message) end end end describe "#keep" do before do adapter.symlink = false # to not taint the Dir adapter.keep = 2 adapter.write(event) end it "should keep the specified number or files upon rollover" do expect(Dir[fixture_path + '/*.log'].size).to eq(1) Timecop.freeze(tomorrow) { adapter.write(event) } expect(Dir[fixture_path + '/*.log'].size).to eq(2) Timecop.freeze(tomorrow + 86400 ) { adapter.write(event) } expect(Dir[fixture_path + '/*.log'].size).to eq(2) end end describe "#symlink" do context "when true (default)" do before do adapter.write(event) end it "should be created on the original filename" do expect(File.symlink?(filename)).to be_true expect(File.readlink(filename)).to eq(today_filename) end it "should be recreated upon rollover" do Timecop.freeze(tomorrow) { adapter.write(event) } expect(File.symlink?(filename)).to be_true expect(File.readlink(filename)).to eq(tomorrow_filename) end end context "when false" do before do adapter.symlink = false end it "should not create the sylink the original filename" do adapter.write( event ) expect(File.symlink?(filename)).to be_false end end end describe "#header" do let(:header) { File.open(today_filename, &:readline) } context "when true (default)" do before do adapter.write(event) end it "should be written" do expect(header).to match(Yell::Adapters::Datefile::HeaderRegexp) end it "should be rewritten upon rollover" do Timecop.freeze(tomorrow) { adapter.write(event) } expect(File.symlink?(filename)).to be_true expect(File.readlink(filename)).to eq(tomorrow_filename) end end context "when false" do before do adapter.header = false end it "should not be written" do adapter.write(event) expect(header).to eq("Hello World\n") end end end context "another adapter with the same :filename" do let(:another_adapter) { Yell::Adapters::Datefile.new(:filename => filename) } before do adapter.write(event) end it "should not write the header again" do another_adapter.write(event) # 1: header # 2: adapter write # 3: another_adapter: write expect(File.readlines(today_filename).size).to eq(3) end end end yell-2.0.5/spec/yell/adapters/base_spec.rb0000644000175000017500000000174712577437450020401 0ustar mcrusoemcrusoerequire 'spec_helper' describe Yell::Adapters::Base do context "initialize" do context ":level" do let(:level) { Yell::Level.new(:warn) } it "should set the level" do adapter = Yell::Adapters::Base.new(:level => level) expect(adapter.level).to eq(level) end it "should set the level when block was given" do adapter = Yell::Adapters::Base.new { |a| a.level = level } expect(adapter.level).to eq(level) end end end context "#write" do let(:logger) { Yell::Logger.new } subject { Yell::Adapters::Base.new(:level => 1) } it "should delegate :event to :write!" do event = Yell::Event.new(logger, 1, "Hello World!") mock(subject).write!(event) subject.write(event) end it "should not write when event does not have the right level" do event = Yell::Event.new(logger, 0, "Hello World!") dont_allow(subject).write!(event) subject.write(event) end end end yell-2.0.5/spec/threaded/0000755000175000017500000000000012577437450015127 5ustar mcrusoemcrusoeyell-2.0.5/spec/threaded/yell_spec.rb0000644000175000017500000000425412577437450017440 0ustar mcrusoemcrusoerequire 'spec_helper' describe "running Yell multi-threaded" do let( :threads ) { 100 } let( :range ) { (1..threads) } let( :filename ) { fixture_path + '/threaded.log' } let( :lines ) { `wc -l #{filename}`.to_i } context "one instance" do before do logger = Yell.new filename range.map do |count| Thread.new { 10.times { logger.info count } } end.each(&:join) sleep 0.5 end it "should write all messages" do lines.should == 10*threads end end # context "one instance per thread" do # before do # range.map do |count| # Thread.new do # logger = Yell.new( filename ) # 10.times { logger.info count } # end # end.each(&:join) # sleep 0.5 # end # it "should write all messages" do # lines.should == 10*threads # end # end context "one instance in the repository" do before do Yell[ 'threaded' ] = Yell.new( filename ) end it "should write all messages" do range.map do |count| Thread.new { 10.times { Yell['threaded'].info count } } end.each(&:join) lines.should == 10*threads end end context "multiple datefile instances" do let( :threadlist ) { [] } let( :date ) { Time.now } before do Timecop.freeze( date - 86400 ) range.each do |count| threadlist << Thread.new do logger = Yell.new :datefile, :filename => filename, :keep => 2 loop { logger.info :info; sleep 0.1 } end end sleep 0.3 # sleep to get some messages into the file end after do threadlist.each(&:kill) end it "should safely rollover" do # now cycle the days 7.times do |count| Timecop.freeze( date + 86400*count ) sleep 0.3 files = Dir[ fixture_path + '/*.*.log' ] files.size.should == 2 # files.last.should match( datefile_pattern_for(Time.now) ) # today # files.first.should match( datefile_pattern_for(Time.now-86400) ) # yesterday end end end private def datefile_pattern_for( time ) time.strftime(Yell::Adapters::Datefile::DefaultDatePattern) end end yell-2.0.5/spec/spec_helper.rb0000644000175000017500000000167112577437450016172 0ustar mcrusoemcrusoe$:.unshift File.expand_path('..', __FILE__) $:.unshift File.expand_path('../../lib', __FILE__) ENV['YELL_ENV'] = 'test' require 'rspec/core' require 'rspec/expectations' require 'rr' require 'timecop' begin require 'pry' rescue LoadError end begin require 'coveralls' require 'simplecov' STDERR.puts "Running coverage..." SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter ] SimpleCov.start do add_filter 'spec' end rescue LoadError # do nothing end require 'yell' RSpec.configure do |config| config.mock_framework = :rr config.before :each do Yell::Repository.loggers.clear Dir[ fixture_path + "/*.log" ].each { |f| File.delete f } end config.after :each do Timecop.return # release time after each test end private def fixture_path File.expand_path( "fixtures", File.dirname(__FILE__) ) end end yell-2.0.5/spec/fixtures/0000755000175000017500000000000012577437450015220 5ustar mcrusoemcrusoeyell-2.0.5/spec/fixtures/yell.yml0000644000175000017500000000013412577437450016706 0ustar mcrusoemcrusoetest: :level: info :adapters: - :stdout - :stderr: :level: "gte.error" yell-2.0.5/spec/compatibility/0000755000175000017500000000000012577437450016220 5ustar mcrusoemcrusoeyell-2.0.5/spec/compatibility/level_spec.rb0000644000175000017500000000046712577437450020675 0ustar mcrusoemcrusoerequire 'spec_helper' require 'logger' describe "backwards compatible level" do let(:level) { Yell::Level.new(:error) } let(:logger) { Logger.new($stdout) } before do logger.level = level end it "should format out the level correctly" do expect(logger.level).to eq(level.to_i) end end yell-2.0.5/spec/compatibility/formatter_spec.rb0000644000175000017500000000071512577437450021565 0ustar mcrusoemcrusoerequire 'spec_helper' require 'logger' describe "backwards compatible formatter" do let(:time) { Time.now } let(:formatter) { Yell::Formatter.new(Yell::DefaultFormat) } let(:logger) { Logger.new($stdout) } before do Timecop.freeze(time) logger.formatter = formatter end it "should format out the message correctly" do mock($stdout).write("#{time.iso8601} [ INFO] #{$$} : Hello World!\n") logger.info "Hello World!" end end yell-2.0.5/spec/compatibility/activesupport_logger_spec.rb0000644000175000017500000000146112577437450024030 0ustar mcrusoemcrusoe# encoding: utf-8 require 'spec_helper' begin require 'active_support' rescue LoadError end # make a setup just like in railties ~> 4.0.0 # # We simulate the case when Rails 4 starts up its server # and wants to append the log output. describe "Compatibility to ActiveSupport::Logger", :pending => (!defined?(ActiveSupport) || ActiveSupport::VERSION::MAJOR < 4) do let!(:yell) { Yell.new($stdout, :format => "%m") } let!(:logger) do console = ActiveSupport::Logger.new($stdout) console.formatter = yell.formatter console.level = yell.level yell.extend(ActiveSupport::Logger.broadcast(console)) console end it "should behave correctly" do mock($stdout).syswrite("Hello World\n") # yell mock($stdout).write("Hello World\n") # logger yell.info "Hello World" end end yell-2.0.5/lib/0000755000175000017500000000000012577437450013163 5ustar mcrusoemcrusoeyell-2.0.5/lib/yell/0000755000175000017500000000000012577437450014130 5ustar mcrusoemcrusoeyell-2.0.5/lib/yell/version.rb0000644000175000017500000000010212577437450016133 0ustar mcrusoemcrusoe# encoding: utf-8 module Yell #:nodoc: VERSION = "2.0.5" end yell-2.0.5/lib/yell/silencer.rb0000644000175000017500000000350612577437450016265 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/repository.rb0000644000175000017500000000316712577437450016703 0ustar mcrusoemcrusoe# encoding: utf-8 require '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.0.5/lib/yell/logger.rb0000644000175000017500000001124412577437450015736 0ustar mcrusoemcrusoe# encoding: utf-8 require '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!( *adapters ) adapters.each do |a| case a when Hash then 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.0.5/lib/yell/loggable.rb0000644000175000017500000000126312577437450016233 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/level.rb0000644000175000017500000001255312577437450015572 0ustar mcrusoemcrusoe# encoding: utf-8 module 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 ) 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 taint 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.0.5/lib/yell/helpers/0000755000175000017500000000000012577437450015572 5ustar mcrusoemcrusoeyell-2.0.5/lib/yell/helpers/tracer.rb0000644000175000017500000000200212577437450017371 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/helpers/silencer.rb0000644000175000017500000000072712577437450017731 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/helpers/level.rb0000644000175000017500000000124012577437450017223 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/helpers/formatter.rb0000644000175000017500000000105412577437450020122 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/helpers/base.rb0000644000175000017500000000032312577437450017027 0ustar mcrusoemcrusoe# encoding: utf-8 module Yell #:nodoc: module Helpers #:nodoc: module Base #:nodoc: private # stub def reset! end def inspectables [] end end end end yell-2.0.5/lib/yell/helpers/adapter.rb0000644000175000017500000000230512577437450017537 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/formatter.rb0000644000175000017500000001565012577437450016467 0ustar mcrusoemcrusoe# encoding: utf-8 require '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 @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.0.5/lib/yell/event.rb0000644000175000017500000000505412577437450015602 0ustar mcrusoemcrusoe# encoding: utf-8 require '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 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.0.5/lib/yell/configuration.rb0000644000175000017500000000074712577437450017334 0ustar mcrusoemcrusoe# encoding: utf-8 require '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.0.5/lib/yell/adapters/0000755000175000017500000000000012577437450015733 5ustar mcrusoemcrusoeyell-2.0.5/lib/yell/adapters/streams.rb0000644000175000017500000000061712577437450017742 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/adapters/io.rb0000644000175000017500000000445612577437450016700 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/adapters/file.rb0000644000175000017500000000142412577437450017200 0ustar mcrusoemcrusoe# encoding: utf-8 module 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.0.5/lib/yell/adapters/datefile.rb0000644000175000017500000001345412577437450020044 0ustar mcrusoemcrusoe# encoding: utf-8 module 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 [:date_pattern, :header, :keep, :symlink ] end end end end yell-2.0.5/lib/yell/adapters/base.rb0000644000175000017500000001406512577437450017200 0ustar mcrusoemcrusoe# encoding: utf-8 require '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', 'Hwllo 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.0.5/lib/yell/adapters.rb0000644000175000017500000000431712577437450016265 0ustar mcrusoemcrusoe# encoding: utf-8 module 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( name, options = {}, &block ) return name if name.is_a?(Yell::Adapters::Base) adapter = case name when STDOUT then @adapters[:stdout] when STDERR then @adapters[:stderr] else @adapters[name.to_sym] end raise AdapterNotFound.new(name) 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.0.5/lib/yell.rb0000644000175000017500000001112712577437450014457 0ustar mcrusoemcrusoe# encoding: utf-8 # 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.0.5/lib/core_ext/0000755000175000017500000000000012577437450014773 5ustar mcrusoemcrusoeyell-2.0.5/lib/core_ext/logger.rb0000644000175000017500000000065312577437450016603 0ustar mcrusoemcrusoerequire 'logger' class Logger def level_with_yell=( level ) self.level_without_yell= Integer(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.0.5/examples/0000755000175000017500000000000012577437450014233 5ustar mcrusoemcrusoeyell-2.0.5/examples/006.2-the-loggable-module-with-inheritance.rb0000644000175000017500000000131112577437450024274 0ustar mcrusoemcrusoe# 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.0.5/examples/006.1-the-loggable-module.rb0000644000175000017500000000123512577437450021040 0ustar mcrusoemcrusoe# 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.0.5/examples/005.1-repository.rb0000644000175000017500000000061312577437450017440 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" Yell.new :stdout, :name => 'mylog' Yell['mylog'].info "Hello World!" yell-2.0.5/examples/004.1-colorizing-the-log-output.rb0000644000175000017500000000062112577437450022271 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" logger = Yell.new STDOUT, :colors => true Yell::Severities.each do |level| logger.send level.downcase, level end yell-2.0.5/examples/003.4-formatting-on-your-own.rb0000644000175000017500000000105212577437450021601 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" logger = Yell.new STDOUT, :format => "[%f:%n in `%M'] %m", :trace => true logger.info "Hello World!" yell-2.0.5/examples/003.3-formatting-ExtendedFormat.rb0000644000175000017500000000102712577437450022302 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" logger = Yell.new STDOUT, :format => Yell::ExtendedFormat logger.info "Hello World!" yell-2.0.5/examples/003.2-formatting-BasicFormat.rb0000644000175000017500000000072612577437450021567 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" logger = Yell.new STDOUT, :format => Yell::BasicFormat logger.info "Hello World!" yell-2.0.5/examples/003.1-formatting-DefaultFormat.rb0000644000175000017500000000103712577437450022125 0ustar mcrusoemcrusoe# 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 "=== actuale example ===" logger = Yell.new STDOUT, :format => Yell::DefaultFormat logger.info "Hello World!" yell-2.0.5/examples/002.3-log-level-within-range.rb0000644000175000017500000000120712577437450021500 0ustar mcrusoemcrusoe# 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: logger = Yell.new STDOUT, :level => (:debug..:warn) [: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 "=== actuale example ===" logger = Yell.new STDOUT, :level => (:debug..:warn) [:debug, :info, :warn, :error, :fatal].each do |level| logger.send( level, level ) end yell-2.0.5/examples/002.2-log-level-on-certain-severities-only.rb0000644000175000017500000000130012577437450024273 0ustar mcrusoemcrusoe# 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: logger = Yell.new STDOUT, :level => [:debug, :warn] [: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 => [:debug, :warn] [:debug, :info, :warn, :error, :fatal].each do |level| logger.send( level, level ) end yell-2.0.5/examples/002.1-log-level-basics.rb0000644000175000017500000000105212577437450020344 0ustar mcrusoemcrusoe# 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.0.5/examples/001-basic-usage.rb0000644000175000017500000000107012577437450017237 0ustar mcrusoemcrusoe# 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.0.5/Rakefile0000644000175000017500000000050212577437450014057 0ustar mcrusoemcrusoerequire '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.0.5/README.md0000644000175000017500000001555612577437450013710 0ustar mcrusoemcrusoe# Yell [![Gem Version](https://badge.fury.io/rb/yell.png)](http://badge.fury.io/rb/yell) [![Build Status](https://travis-ci.org/rudionrails/yell.png?branch=master)](https://travis-ci.org/rudionrails/yell) [![Code Climate](https://codeclimate.com/github/rudionrails/yell.png)](https://codeclimate.com/github/rudionrails/yell) [![Coverage Status](https://coveralls.io/repos/rudionrails/yell/badge.png?branch=master)](https://coveralls.io/r/rudionrails/yell) **Yell - Your Extensible Logging Library** is a comprehensive logging replacement for Ruby. Yell works and is tested with ruby 1.8.7, 1.9.x, 2.0.0, jruby 1.8 and 1.9 mode, rubinius 1.8 and 1.9 as well as ree. 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) [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-2014 Rudolf Schmidt, released under the MIT license yell-2.0.5/LICENSE.txt0000644000175000017500000000205012577437450014235 0ustar mcrusoemcrusoeCopyright (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. yell-2.0.5/Gemfile0000644000175000017500000000074712577437450013720 0ustar mcrusoemcrusoesource "http://rubygems.org" # Specify your gem's dependencies in yell.gemspec gemspec group :development, :test do gem "rake" gem 'rspec-core', '~> 2' gem 'rspec-expectations', '~> 2' gem "rr" if RUBY_VERSION < "1.9" gem 'timecop', '0.6.0' gem 'activesupport', '~> 3' else gem 'timecop' gem 'activesupport' gem 'pry' end gem 'simplecov', :require => false, :platform => :ruby_20 gem 'coveralls', :require => false, :platform => :ruby_20 end yell-2.0.5/.travis.yml0000644000175000017500000000026512577437450014531 0ustar mcrusoemcrusoelanguage: ruby script: "rspec" rvm: - 1.8.7 - 1.9.3 - 2.0.0 - 2.1.1 - jruby-18mode - jruby-19mode - rbx-2 - ree notifications: email: - me@rudionrails.com yell-2.0.5/.gitignore0000644000175000017500000000012512577437450014403 0ustar mcrusoemcrusoepkg/* *.gem .bundle .idea # bundler Gemfile.lock # vim *.swp # coverage /coverage