Module: Jekyll::Minify::Instrumentation

Defined in:
lib/jekyll-minify/instrumentation.rb

Overview

OpenTelemetry instrumentation facade for jekyll-minify.

All tracing is configured centrally in TRACED_METHODS — no span code lives in business logic classes. To add a span: append one entry. To rename a method: update the one entry. When a method is removed from its class the stale entry raises NoMethodError in tests, signalling the entry to delete.

Requires opentelemetry-api at runtime; falls back to a no-op if absent. Users opt in to real tracing by adding opentelemetry-sdk and opentelemetry-exporter-otlp to their site Gemfile and exporting:

OTEL_SERVICE_NAME=jekyll-minify
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

Defined Under Namespace

Classes: NoopSpan, NoopTracer

Constant Summary collapse

TRACER_NAME =

Name reported to the OTel tracer provider for spans created by this gem.

Returns:

  • (String)
'jekyll-minify'
TRACED_METHODS =

Central instrumentation registry.

Each row: [class_name, method_type, method_name, span_name, attribute_proc]

method_type:

:instance  — public instance method
:private   — private instance method (visibility is preserved on the wrapper)
:class     — class / module method (prepended on the singleton class)

attribute_proc: ->(span, this, args, result) or nil span — OTel span (or NoopSpan); call span.set_attribute after super returns this — receiver object (instance or nil for class methods) args — positional args array as passed to the method result — return value of the original method

:nocov: — attribute procs are configuration data; coverage comes from integration tests

Returns:

  • (Array<Array>)
[
  ['Jekyll::Minify::Minifier', :class, :minify_site, 'minify.site_minify',
   lambda { |span, _this, args, result|
     span.set_attribute('minify.dest_path', args[0].dest.to_s)
     next unless result

     types = result.values_at(:html, :css, :js)
     span.set_attribute('minify.total_file_count', types.sum { |t| t[:count] })
     span.set_attribute('minify.total_original_size_bytes', types.sum { |t| t[:original_bytes] })
     span.set_attribute('minify.total_minified_size_bytes', types.sum { |t| t[:minified_bytes] })
     span.set_attribute('minify.error_count', result[:errors].length)
   }],

  ['Jekyll::Minify::Minifier', :private, :minify_each_file, 'minify.file_discovery',
   lambda { |span, _this, args, _result|
     span.set_attribute('minify.dest_path', args[0].to_s)
   }],

  ['Jekyll::Minify::Minifier', :private, :minify_with_fallback, 'minify.file_process',
   lambda { |span, _this, args, _result|
     span.set_attribute('minify.file_path', args[0].to_s)
     span.set_attribute('minify.asset_type', args[1].to_s)
   }],

  ['Jekyll::Minify::Minifier', :private, :minify_html, 'minify.html_minify',
   lambda { |span, _this, args, result|
     span.set_attribute('minify.input_size_bytes', args[0].bytesize)
     span.set_attribute('minify.output_size_bytes', result.to_s.bytesize)
   }],

  ['Jekyll::Minify::Minifier', :private, :minify_css, 'minify.css_minify',
   lambda { |span, _this, args, result|
     span.set_attribute('minify.input_size_bytes', args[0].bytesize)
     span.set_attribute('minify.output_size_bytes', result.to_s.bytesize)
   }],

  ['Jekyll::Minify::Minifier', :private, :minify_js, 'minify.js_minify',
   lambda { |span, _this, args, result|
     span.set_attribute('minify.input_size_bytes', args[0].bytesize)
     span.set_attribute('minify.output_size_bytes', result.to_s.bytesize)
   }]
].freeze

Class Method Summary collapse

Class Method Details

.enabled?Boolean

Returns true when OTel is requested via standard environment variables.

install! guards on this so the prepend wrappers are only applied when a real exporter is configured. In CI and local tests (no OTel env vars) business logic classes are untouched, keeping allow_any_instance_of stubs and other RSpec mechanics fully functional.

Returns:

  • (Boolean)


125
126
127
# File 'lib/jekyll-minify/instrumentation.rb', line 125

def self.enabled?
  ENV.key?('OTEL_EXPORTER_OTLP_ENDPOINT') || ENV.key?('OTEL_SERVICE_NAME')
end

.install!void

This method returns an undefined value.

Installs wrappers on all classes listed in TRACED_METHODS using Module#prepend.

Called once at plugin load time (end of jekyll-minify.rb, after all requires), but only when enabled? returns true. Use OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_SERVICE_NAME to activate tracing.



136
137
138
139
140
141
142
143
144
# File 'lib/jekyll-minify/instrumentation.rb', line 136

def self.install!
  return if @installed

  @installed = true
  setup_sdk!
  TRACED_METHODS.group_by { |e| e[0] }.each do |class_name, entries|
    prepend_wrappers(resolve_class(class_name), entries)
  end
end

.instrument(span_name, attributes: {}) {|span| ... } ⇒ Object

Wraps a block in an OTel span.

Parameters:

  • span_name (String)

    Dot-separated span name (e.g. 'minify.html_minify')

  • attributes (Hash) (defaults to: {})

    Initial span attributes

Yield Parameters:

  • span (OpenTelemetry::Trace::Span, NoopSpan)

    Active span

Returns:

  • (Object)

    The return value of the block



105
106
107
# File 'lib/jekyll-minify/instrumentation.rb', line 105

def self.instrument(span_name, attributes: {}, &block)
  tracer.in_span(span_name, attributes: attributes, &block)
end

.reset!void

This method returns an undefined value.

Resets the cached tracer and installation flag. Call in tests after changing OTel configuration.



112
113
114
115
# File 'lib/jekyll-minify/instrumentation.rb', line 112

def self.reset!
  @tracer    = nil
  @installed = false
end

.resolve_class(name) ⇒ Class?

Resolves a dot-separated class name to a constant; returns nil on NameError.

Parameters:

  • name (String)

    fully-qualified class name, e.g. 'Jekyll::Minify::Minifier'

Returns:

  • (Class, nil)


190
191
192
193
194
# File 'lib/jekyll-minify/instrumentation.rb', line 190

def self.resolve_class(name)
  name.split('::').reduce(Object) { |m, c| m.const_get(c) }
rescue NameError
  nil
end

.tracerOpenTelemetry::Trace::Tracer, NoopTracer

Returns the active OTel tracer, or a no-op tracer if opentelemetry-api is absent.

Returns:



88
89
90
91
92
93
94
95
96
97
# File 'lib/jekyll-minify/instrumentation.rb', line 88

def self.tracer
  @tracer ||=
    if defined?(OpenTelemetry)
      # :nocov:
      OpenTelemetry.tracer_provider.tracer(TRACER_NAME, Jekyll::Minify::VERSION)
      # :nocov:
    else
      NoopTracer.new
    end
end