Module: Jekyll::LinkDecorator::Instrumentation
- Defined in:
- lib/jekyll-link-decorator/instrumentation.rb
Overview
OpenTelemetry instrumentation facade for jekyll-link-decorator.
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-link-decorator
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
Defined Under Namespace
Classes: NoopSpan, NoopTracer
Constant Summary collapse
- TRACER_NAME =
'jekyll-link-decorator'- 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
[ # decorate_html is the converter's entry point — one span per page converted ['Jekyll::Converters::LinkDecorator', :instance, :decorate_html, 'link.decorate_page', lambda { |span, _this, args, result| span.set_attribute('link.html_size_bytes', args[0].to_s.bytesize) span.set_attribute('link.output_size_bytes', result.to_s.bytesize) }], ['Jekyll::Converters::LinkDecorator', :instance, :apply_link_styles, 'link.style_apply', lambda { |span, _this, args, _result| doc = args[0] span.set_attribute('link.styled_link_count', doc.respond_to?(:css) ? doc.css('a:not(.btn)').size : 0) }], ['Jekyll::Converters::LinkDecorator', :instance, :add_external_link_features, 'link.external_link_features', lambda { |span, _this, args, _result| doc = args[0] span.set_attribute('link.external_link_count', doc.respond_to?(:css) ? doc.css('a[target="_blank"]').size : 0) }], # add_heading_anchors is private on LinkDecorator; visibility is preserved on the wrapper ['Jekyll::Converters::LinkDecorator', :private, :add_heading_anchors, 'link.heading_anchors', nil] ].freeze
Class Method Summary collapse
-
.enabled? ⇒ Boolean
Returns true when OTel is requested via standard environment variables.
-
.install! ⇒ Object
Installs wrappers on all classes listed in TRACED_METHODS using Module#prepend.
-
.instrument(span_name, attributes: {}) {|span| ... } ⇒ Object
Wraps a block in an OTel span.
-
.reset! ⇒ Object
Resets the cached tracer and installation flag.
-
.resolve_class(name) ⇒ Object
Resolves a dot-separated class name to a constant; returns nil on NameError.
-
.tracer ⇒ Object
Returns the active OTel tracer, or a no-op tracer if opentelemetry-api is absent.
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.
97 98 99 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 97 def self.enabled? ENV.key?('OTEL_EXPORTER_OTLP_ENDPOINT') || ENV.key?('OTEL_SERVICE_NAME') end |
.install! ⇒ Object
Installs wrappers on all classes listed in TRACED_METHODS using Module#prepend.
Called once at plugin load time (end of jekyll-link-decorator.rb, after all requires), but only when enabled? returns true. Use OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_SERVICE_NAME to activate tracing.
106 107 108 109 110 111 112 113 114 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 106 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.
81 82 83 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 81 def self.instrument(span_name, attributes: {}, &block) tracer.in_span(span_name, attributes: attributes, &block) end |
.reset! ⇒ Object
Resets the cached tracer and installation flag. Call in tests after changing OTel configuration.
86 87 88 89 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 86 def self.reset! @tracer = nil @installed = false end |
.resolve_class(name) ⇒ Object
Resolves a dot-separated class name to a constant; returns nil on NameError.
161 162 163 164 165 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 161 def self.resolve_class(name) name.split('::').reduce(Object) { |m, c| m.const_get(c) } rescue NameError nil end |
.tracer ⇒ Object
Returns the active OTel tracer, or a no-op tracer if opentelemetry-api is absent.
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/jekyll-link-decorator/instrumentation.rb', line 64 def self.tracer @tracer ||= if defined?(OpenTelemetry) # :nocov: OpenTelemetry.tracer_provider.tracer(TRACER_NAME, Jekyll::LinkDecorator::VERSION) # :nocov: else NoopTracer.new end end |