├── .gitignore ├── Gemfile ├── lib ├── micrologger │ └── version.rb └── micrologger.rb ├── CHANGELOG.md ├── micrologger.gemspec ├── MIT-LICENSE.txt ├── Rakefile ├── .github └── workflows │ └── test.yml ├── README.md └── spec └── micrologger_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem "minitest" 6 | gem "rake" 7 | gem "irb" 8 | -------------------------------------------------------------------------------- /lib/micrologger/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MicroLogger 4 | VERSION = '0.1.3' 5 | end 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.3 4 | 5 | - 2022 re-release: Update Gemspec and CI 6 | 7 | ## 0.1.2 8 | 9 | * Loosen paint dep 10 | 11 | ## 0.1.0 12 | 13 | * Release 14 | 15 | -------------------------------------------------------------------------------- /micrologger.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require File.expand_path('../lib/micrologger/version', __FILE__) 4 | 5 | Gem::Specification.new do |gem| 6 | gem.name = "micrologger" 7 | gem.version = MicroLogger::VERSION 8 | gem.summary = 'A minimal logger.' 9 | gem.description = 'A minimal logger based on MicroEvent.rb' 10 | gem.license = "MIT" 11 | gem.authors = ["Jan Lelis"] 12 | gem.email = ["hi@ruby.consulting"] 13 | gem.homepage = "https://github.com/janlelis/micrologger" 14 | 15 | gem.files = Dir['{**/}{.*,*}'].select { |path| File.file?(path) } 16 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 17 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 18 | gem.require_paths = ['lib'] 19 | gem.metadata = { "rubygems_mfa_required" => "true" } 20 | 21 | gem.add_dependency 'microevent', '~> 1.0' 22 | gem.add_dependency 'paint', '>= 0.9', '< 3.0' 23 | end 24 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jan Lelis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # # # 2 | # Get gemspec info 3 | 4 | gemspec_file = Dir["*.gemspec"].first 5 | gemspec = eval File.read(gemspec_file), binding, gemspec_file 6 | info = "#{gemspec.name} | #{gemspec.version} | " \ 7 | "#{gemspec.runtime_dependencies.size} dependencies | " \ 8 | "#{gemspec.files.size} files" 9 | 10 | # # # 11 | # Gem build and install task 12 | 13 | desc info 14 | task :gem do 15 | puts info + "\n\n" 16 | print " "; sh "gem build #{gemspec_file}" 17 | FileUtils.mkdir_p "pkg" 18 | FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg" 19 | puts; sh %{gem install --no-document pkg/#{gemspec.name}-#{gemspec.version}.gem} 20 | end 21 | 22 | # # # 23 | # Start an IRB session with the gem loaded 24 | 25 | desc "#{gemspec.name} | IRB" 26 | task :irb do 27 | sh "irb -I ./lib -r #{gemspec.name.gsub '-','/'}" 28 | end 29 | 30 | # # # 31 | # Run specs 32 | 33 | desc "#{gemspec.name} | Spec" 34 | task :spec do 35 | if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ 36 | sh "for %f in (spec/\*.rb) do ruby spec/%f" 37 | else 38 | sh "for file in spec/*.rb; do ruby $file; done" 39 | end 40 | end 41 | task default: :spec 42 | -------------------------------------------------------------------------------- /lib/micrologger.rb: -------------------------------------------------------------------------------- 1 | require_relative 'micrologger/version' 2 | 3 | require 'microevent' 4 | require 'paint' 5 | 6 | class MicroLogger 7 | include MicroEvent 8 | 9 | DEFAULT_HANDLERS = { 10 | stdout: lambda{ |message, extra| 11 | STDOUT.puts formatter(message, extra) 12 | }, 13 | stderr: lambda{ |message, extra| 14 | STDERR.puts Paint[formatter(message, extra), :red] 15 | }, 16 | } 17 | 18 | def log(message, level = :info, extra = {}) 19 | trigger level, message, {level: level, time: Time.now}.merge(extra) 20 | end 21 | 22 | def register(level = :info, handler = nil, &block) 23 | bind level, &resolve_handler(handler || block) 24 | end 25 | 26 | def unregister(level = :info, handler = nil, &block) 27 | if handler || block 28 | unbind level, &resolve_handler(handler || block) 29 | else 30 | unbind level 31 | end 32 | end 33 | 34 | 35 | private 36 | 37 | def resolve_handler(handler) 38 | if handler.is_a?(Proc) 39 | handler 40 | elsif default_handler = DEFAULT_HANDLERS[handler] 41 | default_handler 42 | else 43 | raise ArgumentError, "no suitable handler found for #{handler.inspect}" 44 | end 45 | end 46 | 47 | def formatter(message, extra) 48 | "#{extra[:time].strftime('%Y-%m-%d %H:%M')} | #{extra[:level]} | #{message}" 49 | end 50 | end 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | name: Ruby ${{ matrix.ruby }} (${{ matrix.os }}) 8 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 9 | strategy: 10 | matrix: 11 | ruby: 12 | - 3.1 13 | - 3.0 14 | - 2.7 15 | - 2.6 16 | - jruby-9.3.2 17 | - truffleruby-21.3.0 18 | os: 19 | - ubuntu-latest 20 | # - macos-latest 21 | runs-on: ${{matrix.os}} 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Set up Ruby 25 | uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: ${{matrix.ruby}} 28 | bundler-cache: true 29 | - name: Run tests 30 | run: bundle exec rake 31 | 32 | test-windows: 33 | name: Ruby ${{ matrix.ruby }} (windows-latest) 34 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 35 | strategy: 36 | matrix: 37 | ruby: 38 | - 3.0 39 | - 2.7 40 | - 2.6 41 | runs-on: windows-latest 42 | steps: 43 | - uses: actions/checkout@v2 44 | - name: Set up Ruby 45 | uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: ${{matrix.ruby}} 48 | bundler-cache: true 49 | # - run: cinst ansicon 50 | - name: Run tests 51 | run: bundle exec rake 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MicroLogger [![[version]](https://badge.fury.io/rb/microevent.svg)](https://badge.fury.io/rb/microevent) [![[CI]](https://github.com/janlelis/micrologger/workflows/Test/badge.svg)](https://github.com/janlelis/micrologger/actions?query=workflow%3ATest) 2 | 3 | A minimal logger based on [MicroEvent](https://github.com/janlelis/microevent.rb). 4 | 5 | ## Setup 6 | 7 | Add to your `Gemfile` 8 | 9 | ```ruby 10 | gem 'micrologger' 11 | ``` 12 | 13 | ## How to Use It 14 | 15 | A new logger has to be configured what should be done on log events using handler procs. There are two default handlers for logging to STDOUT/STDERR included: 16 | 17 | ```ruby 18 | $logger = MicroLogger.new 19 | $logger.register :info, :stdout 20 | $logger.register :fatal, :stderr 21 | 22 | $logger.log "debug" # STDOUT: debug 23 | $logger.log "error", :fatal # STDERR: error 24 | ``` 25 | 26 | For any andvanced or customized behaviour, you will need to register your own blocks/procs: 27 | 28 | 29 | ### Example: Log to File 30 | 31 | ```ruby 32 | $logger = MicroLogger.new 33 | $logger.register :warn, :stderr 34 | $logger.register :warn do |message, meta| 35 | File.open("logfile.#{meta[:level]}.txt", "a"){ |f| f.puts "#{meta[:time]} | #{message}" } 36 | end 37 | 38 | $logger.log "hey", :warn # Will write to STDERR and logfile.warn.txt 39 | ``` 40 | 41 | Other ideas you could do: Send data to a remote endpoint, send emails, send to analytics... 42 | 43 | 44 | ## J-_-L 45 | 46 | Copyright (c) 2015 [Jan Lelis](https://janlelis.com). See MIT-LICENSE for details. 47 | -------------------------------------------------------------------------------- /spec/micrologger_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../lib/micrologger' 2 | require 'minitest/autorun' 3 | 4 | describe MicroLogger do 5 | let :logger do 6 | MicroLogger.new 7 | end 8 | 9 | describe '#log' do 10 | it 'calls registered handler for called log level' do 11 | result = [] 12 | 13 | logger.register :debug, proc{ result << 42 } 14 | logger.log "msg", :debug 15 | 16 | assert_equal [42], result 17 | end 18 | 19 | it 'it passes the message to the handler' do 20 | result = [] 21 | 22 | logger.register :debug, proc{ |message| result << message } 23 | logger.log "msg", :debug 24 | 25 | assert_equal ["msg"], result 26 | end 27 | 28 | it 'passes an "extra" meta info hash to the handler' do 29 | result = nil 30 | 31 | logger.register :debug, proc{ |message, extra| result = extra } 32 | logger.log "msg", :debug 33 | 34 | assert_equal Hash, result.class 35 | end 36 | 37 | it 'contains the current time in extra hash' do 38 | result = nil 39 | 40 | logger.register :debug, proc{ |message, extra| result = extra } 41 | logger.log "msg", :debug 42 | 43 | assert_equal Time, result[:time].class 44 | end 45 | 46 | it 'contains the log level in extra hash' do 47 | result = nil 48 | 49 | logger.register :debug, proc{ |message, extra| result = extra } 50 | logger.log "msg", :debug 51 | 52 | assert_equal :debug, result[:level] 53 | end 54 | 55 | it 'works with multiple handlers' do 56 | result = [] 57 | 58 | logger.register :debug, proc{ result << 42 } 59 | logger.register :debug, proc{ result << 23 } 60 | logger.log "msg", :debug 61 | 62 | assert_equal [42, 23], result 63 | end 64 | 65 | it 'will use the :info log level if none is given' do 66 | result = [] 67 | 68 | logger.register :info, proc{ result << 42 } 69 | logger.log "msg" 70 | 71 | assert_equal [42], result 72 | end 73 | end 74 | 75 | describe '#register' do 76 | it 'will bind a new proc handler for a log level' do 77 | result = [] 78 | fn = proc{ result << 42 } 79 | 80 | logger.register :debug, fn 81 | logger.log "msg", :debug 82 | 83 | assert_equal [42], result 84 | end 85 | 86 | it 'also takes a block as handler' do 87 | result = [] 88 | 89 | logger.register(:debug){ result << 42 } 90 | logger.log "msg", :debug 91 | 92 | assert_equal [42], result 93 | end 94 | 95 | it 'will raise an ArgumentError if no handler given' do 96 | result = nil 97 | 98 | begin 99 | logger.register :debug 100 | rescue => result 101 | end 102 | 103 | assert_equal ArgumentError, result.class 104 | end 105 | 106 | it 'will use the :info log level if is none is given' do 107 | result = [] 108 | 109 | logger.register{ result << 42 } 110 | logger.log "msg" 111 | 112 | assert_equal [42], result 113 | end 114 | end 115 | 116 | describe '#unregister' do 117 | it 'will unregister a handler for a log level' do 118 | result = [] 119 | fn = proc{ result << 42 } 120 | 121 | logger.register :debug, fn 122 | logger.unregister :debug, fn 123 | logger.log "msg", :debug 124 | 125 | assert_equal [], result 126 | end 127 | 128 | it 'will unregister all handlers if none is given' do 129 | result = [] 130 | fn = proc{ result << 42 } 131 | 132 | logger.register :debug, fn 133 | logger.unbind :debug 134 | logger.log "msg", :debug 135 | 136 | assert_equal [], result 137 | end 138 | end 139 | 140 | describe 'DEFAULT_HANDLERS' do 141 | it 'contains a :stdout handler' do 142 | # assert_output "msg", "" do 143 | # logger.register :debug, :stdout 144 | # logger.log "msg", :debug 145 | # end 146 | end 147 | 148 | it 'contains a :stderr handler' do 149 | # assert_output "", "msg" do 150 | # logger.register :debug, :stderr 151 | # logger.log "msg", :debug 152 | # end 153 | end 154 | end 155 | end 156 | --------------------------------------------------------------------------------