ConsoleSourceConsoleFilter

class Filter

A log filter which can be used to filter log messages based on severity, subject, and other criteria.

Definitions

def self.define_immutable_method(name, &block)

Define a method which can be shared between ractors.

Implementation

def self.define_immutable_method(name, &block)
	block = Ractor.make_shareable(block)
	self.define_method(name, &block)
end

def self.define_immutable_method(name, &block)

Define a method.

Implementation

def self.define_immutable_method(name, &block)
	define_method(name, &block)
end

def self.[] **levels

Create a new log filter with specific log levels.

class MyLogger < Console::Filter[debug: 0, okay: 1, bad: 2, terrible: 3]

Signature

parameter levels Hash(Symbol, Integer)

A hash of log levels.

Implementation

def self.[] **levels
	klass = Class.new(self)
	minimum_level, maximum_level = levels.values.minmax
	
	klass.instance_exec do
		const_set(:LEVELS, levels.freeze)
		const_set(:MINIMUM_LEVEL, minimum_level)
		const_set(:MAXIMUM_LEVEL, maximum_level)
		
		levels.each do |name, level|
			const_set(name.to_s.upcase, level)
			
			define_immutable_method(name) do |subject = nil, *arguments, **options, &block|
				if self.enabled?(subject, level)
					@output.call(subject, *arguments, severity: name, **@options, **options, &block)
				end
				
				return nil
			end
			
			define_immutable_method("#{name}!") do
				@level = level
			end
			
			define_immutable_method("#{name}?") do
				@level <= level
			end
		end
	end
	
	return klass
end

def initialize(output, verbose: true, level: self.class::DEFAULT_LEVEL, **options)

Create a new log filter.

Signature

parameter output Console::Output

The output destination.

parameter verbose Boolean

Enable verbose output.

parameter level Integer

The log level.

parameter options Hash

Additional options.

Implementation

def initialize(output, verbose: true, level: self.class::DEFAULT_LEVEL, **options)
	@output = output
	@verbose = verbose
	@level = level
	
	@subjects = {}
	
	@options = options
end

def with(level: @level, verbose: @verbose, **options)

Create a new log filter with the given options, from an existing log filter.

Signature

parameter level Integer

The log level.

parameter verbose Boolean

Enable verbose output.

parameter options Hash

Additional options.

returns Console::Filter

The new log filter.

Implementation

def with(level: @level, verbose: @verbose, **options)
	dup.tap do |logger|
		logger.level = level
		logger.verbose! if verbose
		logger.options = @options.merge(options)
	end
end

attr_accessor :output

Signature

attribute Console::Output

The output destination.

attr :verbose

Signature

attribute Boolean

Whether to enable verbose output.

attr :level

Signature

attribute Integer

The current log level.

attr :subjects

Signature

attribute Hash(Module, Integer)

The log levels for specific subject (classes).

attr_accessor :options

Signature

attribute Hash

Additional options.

def level= level

Set the log level.

Signature

parameter level Integer | Symbol

The log level.

Implementation

def level= level
	if level.is_a? Symbol
		@level = self.class::LEVELS[level]
	else
		@level = level
	end
end

def verbose!(value = true)

Set verbose output (enable by default with no arguments).

Signature

parameter value Boolean

Enable or disable verbose output.

Implementation

def verbose!(value = true)
	@verbose = value
	@output.verbose!(value)
end

def off!

Disable all logging.

Implementation

def off!
	@level = self.class::MAXIMUM_LEVEL + 1
end

def all!

Enable all logging.

Implementation

def all!
	@level = self.class::MINIMUM_LEVEL - 1
end

def filter(subject, level)

Filter log messages based on the subject and log level.

You must provide the subject's class, not an instance of the class.

Signature

parameter subject Module

The subject to filter.

parameter level Integer

The log level.

Implementation

def filter(subject, level)
	unless subject.is_a?(Module)
		raise ArgumentError, "Expected a class, got #{subject.inspect}"
	end
	
	@subjects[subject] = level
end

def enabled?(subject, level = self.class::MINIMUM_LEVEL)

Whether logging is enabled for the given subject and log level.

You can enable and disable logging for classes. This function checks if logging for a given subject is enabled.

Signature

parameter subject Module

The subject to check.

parameter level Integer

The log level.

returns Boolean

Whether logging is enabled.

Implementation

def enabled?(subject, level = self.class::MINIMUM_LEVEL)
	subject = subject.class unless subject.is_a?(Module)
	
	if specific_level = @subjects[subject]
		return level >= specific_level
	end
	
	if level >= @level
		return true
	end
end

def enable(subject, level = self.class::MINIMUM_LEVEL)

Enable specific log level for the given class.

Signature

parameter name Module

The class to enable.

Implementation

def enable(subject, level = self.class::MINIMUM_LEVEL)
	# Set the filter level of logging for a given subject which passes all log messages:
	filter(subject, level)
end

def disable(subject)

Disable logging for the given class.

Signature

parameter name Module

The class to disable.

Implementation

def disable(subject)
	# Set the filter level of the logging for a given subject which filters all log messages:
	filter(subject, self.class::MAXIMUM_LEVEL + 1)
end

def clear(subject)

Clear any specific filters for the given class.

Signature

parameter subject Module

The class to disable.

Implementation

def clear(subject)
	unless subject.is_a?(Module)
		raise ArgumentError, "Expected a class, got #{subject.inspect}"
	end
	
	@subjects.delete(subject)
end

def call(subject, *arguments, **options, &block)

Log a message with the given severity.

Signature

parameter subject Object

The subject of the log message.

parameter arguments Array

The arguments to log.

parameter options Hash

Additional options to pass to the output.

parameter block Proc

A block passed to the output.

returns Nil

Always returns nil.

Implementation

def call(subject, *arguments, **options, &block)
	severity = options[:severity] || UNKNOWN
	level = self.class::LEVELS[severity]
	
	if self.enabled?(subject, level)
		@output.call(subject, *arguments, **options, &block)
	end
	
	return nil
end