Class: Lumberjack::AttributeFormatter

Inherits:
Object
  • Object
show all
Defined in:
lib/lumberjack/attribute_formatter.rb

Overview

AttributeFormatter provides flexible formatting control for log entry attributes (key-value pairs). It allows you to specify different formatting rules for attribute names, object classes, or provide a default formatter for all attributes.

The formatter system works in a hierarchical manner:

  1. Attribute-specific formatters - Applied to specific attribute names (highest priority)

  2. Class-specific formatters - Applied based on the attribute value’s class

  3. Default formatter - Applied to all other attributes (lowest priority)

Formatters can be specified as:

  • Lumberjack::Formatter objects: Full formatter instances with complex logic

  • Callable objects: Any object responding to #call(value)

  • Blocks: Inline formatting logic

  • Symbols: References to predefined formatter classes (e.g., :strip, :truncate)

If the value returned by a formatter is a Lumberjack::RemapAttributes instance, then the attributes will be remapped to the new attributes.

Examples:

Basic usage with build

formatter = Lumberjack::AttributeFormatter.build do |config|
  config.add_attribute(["password", "secret", "token"]) { |value| "[REDACTED]" }
  config.add_attribute("user.email") { |email| email.downcase }
  config.add_class(Time, :date_time, "%Y-%m-%d %H:%M:%S")
end
formatter = Lumberjack::AttributeFormatter.new
formatter.add_attribute("duration_ms") { |value| Lumberjack::RemapAttributes.new(duration: value.to_f / 1000) }
formatter.format({ "duration_ms" => 1234 }) # => { "duration" => 1.234 }

See Also:

Direct Known Subclasses

TagFormatter

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeLumberjack::AttributeFormatter

Create a new attribute formatter with no default formatters configured. You’ll need to add specific formatters using #add_class, #add_attribute, or #default.



64
65
66
67
68
# File 'lib/lumberjack/attribute_formatter.rb', line 64

def initialize
  @attribute_formatter = {}
  @class_formatter = Formatter.new
  @default_formatter = nil
end

Class Method Details

.build {|formatter| ... } ⇒ Lumberjack::AttributeFormatter

Build a new attribute formatter using a configuration block. The block receives the new formatter as a parameter, allowing you to configure it with methods like add_attribute, add_class, default, etc.

Examples:

formatter = Lumberjack::AttributeFormatter.build do |config|
  config.default { |value| value.to_s.strip }
  config.add_attribute(["password", "secret"]) { |value| "[REDACTED]" }
  config.add_attribute("email") { |email| email.downcase }
  config.add_class(Time, :date_time, "%Y-%m-%d %H:%M:%S")
end

Yields:

  • (formatter)

    A block that configures the attribute formatter.

Returns:



53
54
55
56
57
# File 'lib/lumberjack/attribute_formatter.rb', line 53

def build(&block)
  formatter = new
  block&.call(formatter)
  formatter
end

Instance Method Details

#add(names_or_classes, formatter = nil, *args) {|value| ... } ⇒ Lumberjack::AttributeFormatter

Deprecated.

Use #add_class or #add_attribute instead.

Add formatters for specific attribute names or object classes. This is a convenience method that automatically delegates to #add_class or #add_attribute based on the input type.

When you pass a Module/Class, it creates a class-based formatter that applies to all attribute values of that type. When you pass a String, it creates an attribute-specific formatter for that exact attribute name.

Class formatters are applied recursively to nested hashes and arrays, making them powerful for formatting complex nested structures.

Parameters:

  • names_or_classes (String, Module, Array<String, Module>)

    Attribute names or object classes.

  • formatter (Lumberjack::Formatter, #call, Symbol, nil) (defaults to: nil)

    The formatter to use.

Yields:

  • (value)

    Block-based formatter that receives the attribute value.

Yield Parameters:

  • value (Object)

    The attribute value to format.

Yield Returns:

  • (Object)

    The formatted attribute value.

Returns:



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/lumberjack/attribute_formatter.rb', line 115

def add(names_or_classes, formatter = nil, *args, &block)
  Utils.deprecated("AttributeFormatter#add", "AttributeFormatter#add is deprecated and will be removed in version 2.1; use #add_class or #add_attribute instead.") do
    Array(names_or_classes).each do |obj|
      if obj.is_a?(Module)
        add_class(obj, formatter, *args, &block)
      else
        add_attribute(obj, formatter, *args, &block)
      end
    end
  end

  self
end

#add_attribute(attribute_names, formatter = nil, *args) {|value| ... } ⇒ Lumberjack::AttributeFormatter

Add formatters for specific attribute names. These formatters take precedence over class formatters and the default formatter.

Supports dot notation for nested attributes (e.g., “user.profile.email”). This allows you to format specific values deep within nested hash structures.

Examples:

Basic attribute formatting

formatter.add_attribute("password") { |pwd| "[REDACTED]" }
formatter.add_attribute("email") { |email| email.downcase }

Nested attribute formatting

formatter.add_attribute("user.profile.email") { |email| email.downcase }
formatter.add_attribute("config.database.password") { "[HIDDEN]" }

Multiple attributes

formatter.add_attribute(["secret", "token", "api_key"]) { "[REDACTED]" }

Parameters:

  • attribute_names (String, Symbol, Array<String, Symbol>)

    The attribute names to format.

  • formatter (Lumberjack::Formatter, #call, Symbol, nil) (defaults to: nil)

    The formatter to use.

Yields:

  • (value)

    Block-based formatter that receives the attribute value.

Yield Parameters:

  • value (Object)

    The attribute value to format.

Yield Returns:

  • (Object)

    The formatted attribute value.

Returns:



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/lumberjack/attribute_formatter.rb', line 187

def add_attribute(attribute_names, formatter = nil, *args, &block)
  formatter ||= block
  formatter = dereference_formatter(formatter, args)

  Array(attribute_names).collect(&:to_s).each do |attribute_name|
    if attribute_name.is_a?(Module)
      raise ArgumentError.new("attribute_name cannot be a Module/Class; use #add_class to add class-based formatters")
    end

    if formatter.nil?
      @attribute_formatter.delete(attribute_name)
    else
      @attribute_formatter[attribute_name] = formatter
    end
  end

  self
end

#add_class(classes_or_names, formatter = nil, *args) {|value| ... } ⇒ Lumberjack::AttributeFormatter

Add formatters for specific object classes. The formatter will be applied to any attribute value that is an instance of the registered class. This is particularly useful for formatting all instances of specific data types consistently across your logs.

Class formatters are recursive - they will be applied to matching objects found within nested hashes and arrays.

Examples:

Time formatting

formatter.add_class(Time, :date_time, "%Y-%m-%d %H:%M:%S")
formatter.add_class([Date, DateTime]) { |dt| dt.strftime("%Y-%m-%d") }

Parameters:

  • classes_or_names (String, Module, Array<String, Module>)

    Class names or modules.

  • formatter (Lumberjack::Formatter, #call, Symbol, Class, nil) (defaults to: nil)

    The formatter to use. If a Class is provided, it will be instantiated with the provided args.

  • args (Array)

    The arguments to pass to the constructor if formatter is a Class.

Yields:

  • (value)

    Block-based formatter that receives the attribute value.

Yield Parameters:

  • value (Object)

    The attribute value to format.

Yield Returns:

  • (Object)

    The formatted attribute value.

Returns:



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/lumberjack/attribute_formatter.rb', line 148

def add_class(classes_or_names, formatter = nil, *args, &block)
  formatter ||= block
  formatter = dereference_formatter(formatter, args)

  Array(classes_or_names).each do |class_or_name|
    class_name = class_or_name.to_s
    if formatter.nil?
      @class_formatter.remove(class_name)
    else
      @class_formatter.add(class_name, formatter)
    end
  end

  self
end

#clearLumberjack::AttributeFormatter

Remove all configured formatters, including the default formatter. This resets the formatter to a completely empty state where all attributes pass through unchanged.

Returns:



293
294
295
296
297
298
# File 'lib/lumberjack/attribute_formatter.rb', line 293

def clear
  @default_formatter = nil
  @attribute_formatter.clear
  @class_formatter.clear
  self
end

#default(formatter = nil, *args) {|value| ... } ⇒ Lumberjack::AttributeFormatter

Set a default formatter applied to all attribute values that don’t have specific formatters. This serves as the fallback formatting behavior for any attributes not covered by attribute-specific or class-specific formatters.

Parameters:

  • formatter (Lumberjack::Formatter, #call, Class, nil) (defaults to: nil)

    The formatter to use. If nil, the block will be used as the formatter. If a class is passed, it will be instantiated with the args passed in.

  • args (Array)

    The arguments to pass to the constructor if formatter is a Class.

Yields:

  • (value)

    Block-based formatter that receives the attribute value.

Yield Parameters:

  • value (Object)

    The attribute value to format.

Yield Returns:

  • (Object)

    The formatted attribute value.

Returns:



82
83
84
85
86
87
# File 'lib/lumberjack/attribute_formatter.rb', line 82

def default(formatter = nil, *args, &block)
  formatter ||= block
  formatter = dereference_formatter(formatter, args)
  @default_formatter = formatter
  self
end

#empty?Boolean

Check if the formatter has any configured formatters (attribute, class, or default).

Returns:

  • (Boolean)

    true if no formatters are configured, false otherwise.



303
304
305
# File 'lib/lumberjack/attribute_formatter.rb', line 303

def empty?
  @attribute_formatter.empty? && @class_formatter.empty? && @default_formatter.nil?
end

#format(attributes) ⇒ Hash?

Format a hash of attributes using the configured formatters. This is the main method that applies all formatting rules to transform attribute values.

The formatting process follows this precedence:

  1. Attribute-specific formatters (highest priority)

  2. Class-specific formatters

  3. Default formatter (lowest priority)

Nested hashes and arrays are processed recursively, and dot notation attribute formatters are applied to nested structures.

Parameters:

  • attributes (Hash, nil)

    The attributes hash to format.

Returns:

  • (Hash, nil)

    The formatted attributes hash, or nil if input was nil.



320
321
322
323
324
325
# File 'lib/lumberjack/attribute_formatter.rb', line 320

def format(attributes)
  return nil if attributes.nil?
  return attributes if empty?

  formated_attributes(attributes)
end

#formatter_for_attribute(name) ⇒ #call?

Get the formatter for a specific attribute.

Parameters:

  • name (String, Symbol)

    The attribute name to get the formatter for.

Returns:

  • (#call, nil)

    The formatter for the attribute, or nil if not found.



339
340
341
# File 'lib/lumberjack/attribute_formatter.rb', line 339

def formatter_for_attribute(name)
  @attribute_formatter[name.to_s]
end

#formatter_for_class(klass) ⇒ #call?

Get the formatter for a specific class or class name.

Parameters:

  • klass (String, Module)

    The class or class name to get the formatter for.

Returns:

  • (#call, nil)

    The formatter for the class, or nil if not found.



331
332
333
# File 'lib/lumberjack/attribute_formatter.rb', line 331

def formatter_for_class(klass)
  @class_formatter.formatter_for(klass)
end

#include(formatter) ⇒ self

Extend this formatter by merging the formats defined in the provided formatter into this one.

Parameters:

Returns:

  • (self)

    Returns self for method chaining.



254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/lumberjack/attribute_formatter.rb', line 254

def include(formatter)
  unless formatter.is_a?(Lumberjack::AttributeFormatter)
    raise ArgumentError.new("formatter must be a Lumberjack::AttributeFormatter")
  end

  @class_formatter.include(formatter.instance_variable_get(:@class_formatter))
  @attribute_formatter.merge!(formatter.instance_variable_get(:@attribute_formatter))

  default_formatter = formatter.instance_variable_get(:@default_formatter)
  @default_formatter = default_formatter if default_formatter

  self
end

#include_attribute?(name) ⇒ Boolean

Check if a formatter exists for a specific attribute name.

Parameters:

  • name (String, Symbol)

    The attribute name to check.

Returns:

  • (Boolean)

    true if a formatter exists, false otherwise.



355
356
357
# File 'lib/lumberjack/attribute_formatter.rb', line 355

def include_attribute?(name)
  @attribute_formatter.include?(name.to_s)
end

#include_class?(class_or_name) ⇒ Boolean

Check if a formatter exists for a specific class or class name.

Parameters:

  • class_or_name (Class, Module, String)

    The class or class name to check.

Returns:

  • (Boolean)

    true if a formatter exists, false otherwise.



347
348
349
# File 'lib/lumberjack/attribute_formatter.rb', line 347

def include_class?(class_or_name)
  @class_formatter.include?(class_or_name.to_s)
end

#prepend(formatter) ⇒ self

Extend this formatter by merging the formats defined in the provided formatter into this one. Formats defined in this formatter will take precedence and not be overridden.

Parameters:

Returns:

  • (self)

    Returns self for method chaining.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/lumberjack/attribute_formatter.rb', line 273

def prepend(formatter)
  unless formatter.is_a?(Lumberjack::AttributeFormatter)
    raise ArgumentError.new("formatter must be a Lumberjack::AttributeFormatter")
  end

  @class_formatter.prepend(formatter.instance_variable_get(:@class_formatter))

  formatter.instance_variable_get(:@attribute_formatter).each do |key, value|
    @attribute_formatter[key] = value unless @attribute_formatter.include?(key)
  end

  @default_formatter ||= formatter.instance_variable_get(:@default_formatter)

  self
end

#remove(names_or_classes) ⇒ Lumberjack::AttributeFormatter

Deprecated.

Remove formatters for specific attribute names or classes. This reverts the specified attributes or classes to use the default formatter (if configured) or no formatting.

Parameters:

  • names_or_classes (String, Module, Array<String, Module>)

    Attribute names or classes to remove formatters for.

Returns:



213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/lumberjack/attribute_formatter.rb', line 213

def remove(names_or_classes)
  Utils.deprecated("AttributeFormatter#remove", "AttributeFormatter#remove is deprecated and will be removed in version 2.1; use #remove_class or #remove_attribute instead.") do
    Array(names_or_classes).each do |key|
      if key.is_a?(Module)
        @class_formatter.remove(key)
      else
        @attribute_formatter.delete(key.to_s)
      end
    end
  end
  self
end

#remove_attribute(attribute_names) ⇒ Lumberjack::AttributeFormatter

Remove formatters for specific attribute names. This reverts the specified attributes to use the default formatter (if configured) or no formatting.

Parameters:

  • attribute_names (String, Symbol, Array<String, Symbol>)

    The attribute names to remove.

Returns:



243
244
245
246
247
248
# File 'lib/lumberjack/attribute_formatter.rb', line 243

def remove_attribute(attribute_names)
  Array(attribute_names).collect(&:to_s).each do |attribute_name|
    @attribute_formatter.delete(attribute_name)
  end
  self
end

#remove_class(classes_or_names) ⇒ Lumberjack::AttributeFormatter

Remove formatters for specific object classes. This reverts the specified classes to use the default formatter (if configured) or no formatting.

Parameters:

  • classes_or_names (String, Module, Array<String, Module>)

    The classes or names to remove.

Returns:



231
232
233
234
235
236
# File 'lib/lumberjack/attribute_formatter.rb', line 231

def remove_class(classes_or_names)
  Array(classes_or_names).each do |class_or_name|
    @class_formatter.remove(class_or_name)
  end
  self
end

#remove_defaultLumberjack::AttributeFormatter

Remove the default formatter. After calling this, attributes without specific formatters will be passed through unchanged.

Returns:



93
94
95
96
# File 'lib/lumberjack/attribute_formatter.rb', line 93

def remove_default
  @default_formatter = nil
  self
end