vidazing_logger 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9106df6123f10567ee61da20d022d23c5f43b97a05b2fa9a78291424b6c7b4ad
4
- data.tar.gz: e7aaa6373349e1b2b1ac628a28daf169c314a8e3e452ae12a7b021f119427d86
3
+ metadata.gz: 205ded9bdff5c8cf0b5c2c5b0818b31581e6b151b85ffd9315f34bb23d765236
4
+ data.tar.gz: f5dc4ccfbdd8edd057e08e6c3fad722466c131b2dec341c406e7f74f2292a1d2
5
5
  SHA512:
6
- metadata.gz: 5c22b59b28fe9258a8453564f8c4db707ae4a3a84c2b120f8d994ecac31285306420365428f647adc478e281ef4c262b3c942182df3b5532ddc5172944e493c3
7
- data.tar.gz: 3bfaf20cd8eead8be172c9839b9c202107510e580ab5ff7510485e04bdc38951785240a60a98400ba1590acceb669c8544840d32c6c05935664beef950f4dddd
6
+ metadata.gz: 1e21a3d6630b82047c0ea877a77d9f34a3b05b4a61fe2458935aec1044359ee3d8850fe6b5b127f943e33501bf1f8875e110564dd028581ed14553f4414c1860
7
+ data.tar.gz: 6394c6456b3cedf5f9a3ed0021bf810a8298ac24bf236711b18da822c585821c8697094defdb397b9fb1b8645fd2b138aae0b0f786ccfb394ca529ca973c7807
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -1,3 +1,7 @@
1
+ # Application
2
+ logs/
3
+
4
+ # General
1
5
  *.gem
2
6
  *.rbc
3
7
  /.config
@@ -36,6 +40,7 @@ build-iPhoneSimulator/
36
40
  /rdoc/
37
41
 
38
42
  ## Environment normalization:
43
+ bundle/
39
44
  /.bundle/
40
45
  /vendor/bundle
41
46
  /lib/bundler/man/
data/.rubocop.yml ADDED
@@ -0,0 +1,9 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5.1
3
+ Exclude:
4
+ - 'bundle/**/*'
5
+
6
+ Metrics/BlockLength:
7
+ Exclude:
8
+ - '**/*.rake'
9
+ - 'test/**/*.rb'
data/.simplecov ADDED
@@ -0,0 +1,3 @@
1
+ SimpleCov.start do
2
+ add_filter 'bundle/'
3
+ end
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.5.1
5
+ before_install:
6
+ - gem install bundler -v 1.16.4
7
+
8
+ script:
9
+ - bundle exec rake build
10
+ - bundle exec rake doc:build
11
+ - bundle exec rake test
12
+
13
+ after_script:
14
+ - bundle exec rake coveralls:push
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  gemspec
data/README.md CHANGED
@@ -1,10 +1,15 @@
1
- # logger-gem
1
+ # logger-gem [![Gem Version](https://badge.fury.io/rb/vidazing_logger.svg)](https://badge.fury.io/rb/vidazing_logger)
2
+
3
+ [![Build Status](https://travis-ci.org/VidaZing/logger_gem.svg?branch=master)](https://travis-ci.org/VidaZing/logger_gem)
4
+ [![Inline docs](http://inch-ci.org/github/VidaZing/logger_gem.svg?branch=master)](http://inch-ci.org/github/VidaZing/logger_gem)
5
+ [![Coverage Status](https://coveralls.io/repos/github/VidaZing/logger_gem/badge.svg?branch=master)](https://coveralls.io/github/VidaZing/logger_gem?branch=master)
6
+
2
7
  VidaZing logging strategy using [TwP/logging](https://github.com/TwP/logging).
3
8
 
4
9
  Writes to rolling log files and the corresponding IO pipe.
5
10
 
6
- * <span style="color:red">Red</span> timestamps: `logs/error.log` + stderr.
7
- * <span style="color:blue">Blue</span> timestamps: `logs/build.log` + stdout.
11
+ * <img src="http://medyk.org/colors/ff8787.png" style="border: 1px solid black" width="20" height="20" /> timestamps for: `logs/error.log` + stderr.
12
+ * <img src="http://medyk.org/colors/87d7ff.png" style="border: 1px solid black" width="20" height="20" /> timestamps for: `logs/build.log` + stdout.
8
13
 
9
14
  1. [**Installation**](#installation)
10
15
  2. [**Usage**](#usage)
@@ -14,7 +19,7 @@ Writes to rolling log files and the corresponding IO pipe.
14
19
  1. In your `Gemfile`, add the `vidazing_logger` gem:
15
20
 
16
21
  ```ruby
17
- gem 'vidazing_logger', '~> 0.1'
22
+ gem 'vidazing_logger', '~> 0.2'
18
23
  ```
19
24
 
20
25
  2. In your `shell`, run:
@@ -39,7 +44,20 @@ See `rake -T`
39
44
  ```ruby
40
45
  require 'vidazing_logger'
41
46
 
42
- logger = VidazingLogger.logger("OPTIONAL_LOGGER_NAME")
47
+ # Easy
48
+ optional_name = "DearDiary"
49
+ optional_log_dir = 'logs'
50
+ logger = VidazingLogger.logger(optional_name, optional_log_dir)
51
+
52
+ # Customized. See VidazingLogger::Logger#build
53
+ LoggerBuilder.build(name: @name) do |builder|
54
+ builder
55
+ .add_stdout
56
+ .add_build_log(log_dir: @log_dir)
57
+ .add_stderr
58
+ .add_error_log(log_dir: @log_dir)
59
+ end
60
+
43
61
  ```
44
62
 
45
63
  ### Binary
data/Rakefile CHANGED
@@ -1,63 +1,82 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rainbow/refinement'
2
4
  using Rainbow
3
5
  require 'rake/testtask'
6
+ require 'coveralls/rake/task'
4
7
 
5
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
6
- require "vidazing_logger/version"
8
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
9
+ require 'vidazing_logger/version'
7
10
  VERSION = VidazingLogger::VERSION
8
11
 
9
- GEM_NAME = "vidazing_logger"
12
+ GEM_NAME = 'vidazing_logger'
10
13
 
11
14
  # IMPORTANT: Color can't be used for `system` commands.
12
15
  GEM_NAME_VERSION = "#{GEM_NAME}-#{VERSION}"
13
16
  GEM_ARTIFACT = "#{GEM_NAME_VERSION}.gem"
14
17
 
15
- desc "Remove #{GEM_ARTIFACT} && Gemfile.lock"
18
+ desc "Remove #{GEM_ARTIFACT} && Gemfile.lock".blue
16
19
  task :clean do
17
20
  puts "Removing #{GEM_ARTIFACT} && Gemfile.lock".blue
18
- system "rm -f *.gem Gemfile.lock"
21
+ system 'rm -f *.gem Gemfile.lock'
19
22
  end
20
23
 
21
- desc "Build #{GEM_NAME_VERSION}"
22
- task :build => :clean do
24
+ desc "Build #{GEM_NAME_VERSION}".blue
25
+ task build: :clean do
23
26
  puts "Building #{GEM_NAME_VERSION}".blue
24
27
  system "gem build #{GEM_NAME}.gemspec"
25
28
  end
26
29
 
27
- desc "Publish #{GEM_ARTIFACT}"
30
+ task default: ['build']
31
+
32
+ desc "Publish #{GEM_ARTIFACT}".blue
28
33
  task :publish do
29
34
  puts "Publishing #{GEM_NAME_VERSION}".blue
30
35
  system "gem push #{GEM_NAME_VERSION}.gem"
31
36
  end
32
37
 
33
- desc "Installs #{GEM_ARTIFACT}"
34
- task :install => :build do
38
+ desc "Installs #{GEM_ARTIFACT}".blue
39
+ task install: :build do
35
40
  puts "Installing #{GEM_ARTIFACT}".blue
36
41
  system "gem install #{GEM_NAME}"
37
42
  end
38
43
 
39
- desc "Uninstalls #{GEM_ARTIFACT}"
44
+ desc "Uninstalls #{GEM_ARTIFACT}".blue
40
45
  task :uninstall do
41
46
  puts "UNINSTALLING #{GEM_ARTIFACT}".inverse.blue
42
47
  system "gem uninstall -xq #{GEM_NAME}"
43
48
  end
44
49
 
50
+ namespace :dev do
51
+ desc 'Analyze code quality (rubocop, flog, flay)'
52
+ task :quality do
53
+ puts 'Analyzing format with rubocop'.blue
54
+ system 'bundle exec rubocop'
55
+
56
+ puts 'Checking code quality. Lower is better'.blue
57
+ system 'bundle exec flog lib/'
58
+
59
+ puts 'Checking code duplication. Prime to refactor'.blue
60
+ system 'bundle exec flay lib/'
61
+ end
62
+ end
63
+
45
64
  namespace :doc do
46
65
  desc "Build documentation into 'doc/'"
47
66
  task :build do
48
67
  puts "Building documentation into 'doc/':".blue
49
- system "yard"
68
+ system 'yard'
50
69
  end
51
70
 
52
- desc "Find undocumented code"
71
+ desc 'Find undocumented code'
53
72
  task :coverage do
54
- puts "Documentation coverage:".blue
55
- system "yard stats --list-undoc"
73
+ puts 'Documentation coverage:'.blue
74
+ system 'yard stats --list-undoc'
56
75
  end
57
76
 
58
- desc "See local documentation at http://localhost:8808"
77
+ desc 'See local documentation at http://localhost:8808'
59
78
  task :serve do
60
- system "yard server --reload"
79
+ system 'yard server --reload'
61
80
  end
62
81
  end
63
82
 
@@ -67,44 +86,59 @@ Rake::TestTask.new do |t|
67
86
  t.verbose = true
68
87
  end
69
88
 
70
- namespace :loop do
89
+ namespace :loop do # rubocop:disable Metrics/BlockLength
71
90
  def looper?
72
91
  puts "Checking for 'fswatch' to monitor files".blue
73
92
 
74
- has_fswatch = ! `which fswatch`.empty?
93
+ has_fswatch = !`which fswatch`.empty?
94
+
95
+ unless has_fswatch
96
+ abort('fswatch is NOT installed. Visit https://github.com/emcrisostomo/fswatch'.bright.red)
97
+ end
75
98
 
76
- abort('fswatch is NOT installed. Visit https://github.com/emcrisostomo/fswatch'.bright.red) unless has_fswatch
77
99
  puts('fswatch is installed.'.bright.green) if has_fswatch
78
100
  end
79
101
 
80
102
  def looping(cmd)
81
- fswatch_cmd = "fswatch -0 -e .git/ -e *.gem -e logs -e .yardoc -l 1 ."
103
+ exclude = '-e Gemfile.lock -e .git/ -e *.gem -e logs -e .yardoc -e bundle/'
104
+ fswatch_cmd = "fswatch -0 #{exclude} -l 1 ."
105
+
82
106
  xargs_cmd = "xargs -0 -I {} sh -c \"echo 'File: {}' && %s\""
107
+
83
108
  looping_cmd = "#{fswatch_cmd} | #{xargs_cmd}"
109
+ system format(looping_cmd.to_s, cmd)
110
+ end
111
+
112
+ IGNORED_MESSAGE = 'Ignores .git/, Gemfile.lock, logs/, .yardoc/, bundle/, '\
113
+ 'and gems created. Watches every 1 seconds'
84
114
 
85
- system "#{looping_cmd}" % cmd
115
+ desc 'Repeatedly see dev:quality on file changes'
116
+ task :"dev:quality" do
117
+ looper?
118
+ puts "Analyzing dev:quality on file changes. #{IGNORED_MESSAGE}".blue
119
+ looping('rake dev:quality')
86
120
  end
87
121
 
88
- IGNORED_MESSAGE = "Ignores .git/, logs/, .yardoc/, and gems created. Watches every 1 seconds"
122
+ desc 'Repeatedly show documentation coverage on file changes'
123
+ task :"doc:coverage" do
124
+ looper?
125
+ puts "Showing undocumented code on file changes. #{IGNORED_MESSAGE}".blue
126
+ looping('rake doc:coverage')
127
+ end
89
128
 
90
- desc "Repeatedly installs the gem on file changes"
129
+ desc 'Repeatedly installs the gem on file changes'
91
130
  task :install do
92
131
  looper?
93
132
  puts "Rebuilding on file changes. #{IGNORED_MESSAGE}".blue
94
- looping("rake uninstall install")
133
+ looping('rake uninstall install')
95
134
  end
96
135
 
97
- desc "Repeatedly runs tests on file changes"
136
+ desc 'Repeatedly runs tests on file changes'
98
137
  task :test do
99
138
  looper?
100
139
  puts "Running tests on file changes. #{IGNORED_MESSAGE}".blue
101
- looping("rake test")
102
- end
103
-
104
- desc "Repeatedly show documentation coverage on file changes"
105
- task :"doc:coverage" do
106
- looper?
107
- puts "Showing undocumented code on file changes. #{IGNORED_MESSAGE}".blue
108
- looping("rake doc:coverage")
140
+ looping('rake test')
109
141
  end
110
142
  end
143
+
144
+ Coveralls::RakeTask.new
data/bin/vidazing_logger CHANGED
@@ -1,44 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'vidazing_logger'
4
5
 
5
6
  require 'optparse'
6
7
  require 'ostruct'
7
8
 
9
+ # Handles command line options for the vidazing_logger binary.
10
+ # See `vidazing_logger --help`
11
+ #
12
+ # @since 0.1.0
8
13
  class VidazingOptions
9
- LEVEL_ALIASES = { 'd' => 'debug', 'i' => 'info', 'w' => 'warn', 'e' => 'error', 'f' => 'fatal' }
14
+ attr_reader :level, :clean
10
15
 
11
- def self.parse(args)
12
- options = OpenStruct.new
13
- options.level = 'info'
14
- options.clean = false
16
+ def initialize
17
+ @level = 'info'
18
+ @clean = false
19
+ @options_parser = create_options_parser
20
+ end
21
+
22
+ def create_options_parser # rubocop:disable Metrics/MethodLength
23
+ OptionParser.new do |opts|
24
+ opts.banner = 'Usage: vidazing_logger [options] "Message"'
15
25
 
16
- options_parser = OptionParser.new do |opts|
17
- opts.banner = "Usage: vidazing_logger [options] \"Message\""
26
+ opts.separator ''
27
+ opts.separator 'Specific options:'
18
28
 
19
- opts.separator ""
20
- opts.separator "Specific options:"
29
+ level_aliases = { 'd' => 'debug', 'i' => 'info', 'w' => 'warn',
30
+ 'e' => 'error', 'f' => 'fatal' }.freeze
31
+ level_list = level_aliases.flatten.join(',')
21
32
 
22
- level_list = LEVEL_ALIASES.flatten.join(',')
23
- opts.on("-l", "--level LEVEL", LEVEL_ALIASES.values, LEVEL_ALIASES, "Select log level",
24
- " (#{level_list})") do |level|
25
- options.level = level
33
+ opts.on('-l', '--level LEVEL', level_aliases.values, level_aliases,
34
+ 'Select log level', " (#{level_list})") do |level|
35
+
36
+ @level = level
26
37
  end
27
38
 
28
- opts.on_tail("-c", "--clean", "Remove the logs/ directory") do
29
- options.clean = true
39
+ opts.on_tail('-c', '--clean', 'Remove the logs/ directory') do
40
+ @clean = true
30
41
  end
31
42
  end
43
+ end
32
44
 
33
- options_parser.parse!(args)
34
- options
45
+ def parse(args)
46
+ @options_parser.parse!(args)
35
47
  end
36
48
  end
37
49
 
38
- options = VidazingOptions.parse(ARGV)
50
+ vidazing_options = VidazingOptions.new
51
+ vidazing_options.parse(ARGV)
39
52
 
40
- if options.clean
41
- puts "Cleaning the logs/ directory"
53
+ if vidazing_options.clean
54
+ puts 'Cleaning the logs/ directory'
42
55
  VidazingLogger.clean
43
56
  end
44
57
 
@@ -46,5 +59,5 @@ unless ARGV.empty?
46
59
  message = ARGV.join(' ')
47
60
 
48
61
  log = VidazingLogger.logger
49
- log.public_send(options.level, message)
62
+ log.public_send(vidazing_options.level, message)
50
63
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logging'
4
+
5
+ module VidazingLogger
6
+ # An +Appender+ appenders log events to a logging destination.
7
+ # All appenders use the same layout. So we store the +color_scheme+
8
+ # instead.
9
+ #
10
+ # @api private
11
+ # @since 0.2.0
12
+ class Appender
13
+ attr_reader :filter_levels, :name, :color_scheme
14
+
15
+ def initialize(name:, filter_levels:, color_scheme:)
16
+ @filter_levels = filter_levels
17
+ @color_scheme = color_scheme
18
+ @name = name
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vidazing_logger/appenders/log'
4
+ require 'vidazing_logger/color_scheme'
5
+ require 'vidazing_logger/filters/levels'
6
+
7
+ module VidazingLogger
8
+ module Appenders
9
+ # Appender writing to 'logs/build.log'
10
+ #
11
+ # @api private
12
+ # @since 0.2.0
13
+ class BuildLog < Log
14
+ def initialize(log_dir:)
15
+ super \
16
+ name: 'build',
17
+ log_dir: log_dir,
18
+ color_scheme: ColorScheme.normal,
19
+ filter_levels: Filters::Levels.normal
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vidazing_logger/appenders/log'
4
+ require 'vidazing_logger/color_scheme'
5
+ require 'vidazing_logger/filters/levels'
6
+
7
+ module VidazingLogger
8
+ module Appenders
9
+ # Appender writing to 'logs/error.log'
10
+ #
11
+ # @api private
12
+ # @since 0.2.0
13
+ class ErrorLog < Log
14
+ def initialize(log_dir:)
15
+ super \
16
+ name: 'error',
17
+ log_dir: log_dir,
18
+ color_scheme: ColorScheme.error,
19
+ filter_levels: Filters::Levels.error
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vidazing_logger/appender'
4
+
5
+ module VidazingLogger
6
+ module Appenders
7
+ # Appender writing to log files
8
+ #
9
+ # @api private
10
+ # @since 0.2.0
11
+ class Log < Appender
12
+ attr_reader :log_dir, :name
13
+
14
+ def log_path
15
+ "#{@log_dir}/#{@name}"
16
+ end
17
+
18
+ def initialize(log_dir:, name:, color_scheme:, filter_levels:)
19
+ @log_dir = log_dir
20
+ @name = "#{name}.log"
21
+
22
+ super \
23
+ name: log_path,
24
+ color_scheme: color_scheme,
25
+ filter_levels: filter_levels
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vidazing_logger/layout_pattern'
4
+
5
+ require 'logging'
6
+
7
+ module VidazingLogger
8
+ module Appenders
9
+ # Uses an +appender+
10
+ #
11
+ # @api private
12
+ # @since 0.2.0
13
+ class LoggingGemAdapter
14
+ attr_reader :vidazing_appender, :logging_appender
15
+
16
+ def initialize(type:, vidazing_appender:)
17
+ @vidazing_appender = vidazing_appender
18
+
19
+ logging_filter = create_logging_filter
20
+ logging_layout = create_logging_layout
21
+
22
+ logging_appender_options = create_logging_appender_options \
23
+ filter: logging_filter,
24
+ layout: logging_layout
25
+
26
+ @logging_appender = create_logging_appender \
27
+ type: type,
28
+ name: vidazing_appender.name,
29
+ options: logging_appender_options
30
+ end
31
+
32
+ private
33
+
34
+ def create_logging_appender_options(filter:, layout:)
35
+ [
36
+ filters: filter,
37
+ layout: layout,
38
+ # These are specific to Appenders::Type.rolling_file
39
+ # But the underlying logging library uses opts.fetch
40
+ # So these will be ignored for other appenders types
41
+ age: 'daily',
42
+ keep: 7
43
+ ]
44
+ end
45
+
46
+ def create_logging_appender(type:, name:, options:)
47
+ abort('options are empty!') if options.empty?
48
+ abort("Invalid Type '#{type}'") unless Type.valid_type?(type: type)
49
+
50
+ options.unshift(name)
51
+
52
+ Logging.appenders.public_send(type, *options)
53
+ Logging.appenders[name]
54
+ end
55
+
56
+ def create_logging_filter # rubocop:disable Metrics/MethodLength
57
+ # Logging::Filters::Level takes *levels as its argument.
58
+ # This means we can't store the method arguments ahead of time
59
+ # in an array and directly pass those.
60
+ #
61
+ # Instead, to isolate the Logging gem reference, we hack
62
+ level0, level1, level2, level3, level4 =
63
+ *@vidazing_appender.filter_levels
64
+
65
+ if level1.nil?
66
+ Logging::Filters::Level.new(level0)
67
+ elsif level2.nil?
68
+ Logging::Filters::Level.new(level0, level1)
69
+ elsif level3.nil?
70
+ Logging::Filters::Level.new(level0, level1, level2)
71
+ elsif level4.nil?
72
+ Logging::Filters::Level.new(level0, level1, level2, level3)
73
+ else
74
+ Logging::Filters::Level.new(:all)
75
+ end
76
+ end
77
+
78
+ def create_logging_color_scheme
79
+ color_scheme = @vidazing_appender.color_scheme
80
+ name = color_scheme.name
81
+
82
+ # Logging holds the color scheme reference
83
+ Logging.color_scheme(name, color_scheme.scheme)
84
+
85
+ name
86
+ end
87
+
88
+ def create_logging_layout
89
+ color_scheme_name = create_logging_color_scheme
90
+ layout = LayoutPattern.colored(color_scheme_name).layout
91
+
92
+ Logging.layouts.pattern layout
93
+ end
94
+
95
+ class << self
96
+ def stdout(vidazing_appender:)
97
+ LoggingGemAdapter.new(type: Type::ID_STDOUT,
98
+ vidazing_appender: vidazing_appender)
99
+ end
100
+
101
+ def stderr(vidazing_appender:)
102
+ LoggingGemAdapter.new(type: Type::ID_STDERR,
103
+ vidazing_appender: vidazing_appender)
104
+ end
105
+
106
+ def rolling_file(vidazing_appender:)
107
+ LoggingGemAdapter.new(type: Type::ID_ROLLING_FILE,
108
+ vidazing_appender: vidazing_appender)
109
+ end
110
+ end
111
+ end
112
+
113
+ # Determines what kind of logging will occur
114
+ #
115
+ # @see Type::ID_ROLLING_FILE, Type::ID_STDOUT, Type::ID_STDERR
116
+ # @api private
117
+ module Type
118
+ ID_ROLLING_FILE = 'rolling_file'
119
+ ID_STDOUT = 'stdout'
120
+ ID_STDERR = 'stderr'
121
+
122
+ TYPES = [ID_ROLLING_FILE, ID_STDERR, ID_STDOUT].freeze
123
+
124
+ class << self
125
+ def valid_type?(type:)
126
+ is_valid = false
127
+
128
+ begin
129
+ is_valid = Logging.appenders.respond_to?(type)
130
+ rescue StandardError
131
+ abort("Logging.appenders.#{type} is not a public_method." \
132
+ 'See https://github.com/TwP/logging/')
133
+ end
134
+
135
+ is_valid && TYPES.include?(type)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end