Module: Braintrust::Contrib::Integration::ClassMethods

Defined in:
lib/braintrust/contrib/integration.rb

Instance Method Summary collapse

Instance Method Details

#available?Boolean

Is the target library available for loading?

Returns:

  • (Boolean)


35
36
37
# File 'lib/braintrust/contrib/integration.rb', line 35

def available?
  gem_names.any? { |name| Gem.loaded_specs.key?(name) }
end

#compatible?Boolean

Is the library version compatible?

Returns:

  • (Boolean)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/braintrust/contrib/integration.rb', line 59

def compatible?
  return false unless available?

  gem_names.each do |name|
    spec = Gem.loaded_specs[name]
    next unless spec

    version = spec.version
    return false if minimum_version && version < Gem::Version.new(minimum_version)
    return false if maximum_version && version > Gem::Version.new(maximum_version)
    return true
  end
  false
end

#gem_namesArray<String>

Array of gem names this integration supports.

Returns:

  • (Array<String>)

Raises:

  • (NotImplementedError)


22
23
24
# File 'lib/braintrust/contrib/integration.rb', line 22

def gem_names
  raise NotImplementedError, "#{self} must implement gem_names"
end

#instrument!(**options) ⇒ Boolean

Instrument this integration with optional configuration. If a target is provided, configures the target instance specifically. Otherwise, applies class-level instrumentation to all instances.

Examples:

Class-level instrumentation (all clients)

integration.instrument!(tracer_provider: my_provider)

Instance-level instrumentation (specific client)

integration.instrument!(target: client, tracer_provider: my_provider)

Parameters:

  • options (Hash)

    Configuration options

Options Hash (**options):

  • :target (Object)

    Optional target instance to instrument

  • :tracer_provider (OpenTelemetry::SDK::Trace::TracerProvider)

    Optional tracer provider

Returns:

  • (Boolean)

    true if patching succeeded or was already done



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/braintrust/contrib/integration.rb', line 102

def instrument!(**options)
  if options.empty?
    Braintrust::Log.debug("#{integration_name}.instrument! called")
  else
    Braintrust::Log.debug("#{integration_name}.instrument! called (#{options.keys.join(", ")})")
  end

  if options[:target]
    # Configure the target with provided options (exclude :target from context)
    context_options = options.except(:target)
    Contrib::Context.set!(options[:target], **context_options) unless context_options.empty?
  end

  patch!(**options)
end

#integration_nameSymbol

Unique symbol name for this integration (e.g., :openai, :anthropic).

Returns:

  • (Symbol)

Raises:

  • (NotImplementedError)


16
17
18
# File 'lib/braintrust/contrib/integration.rb', line 16

def integration_name
  raise NotImplementedError, "#{self} must implement integration_name"
end

#loaded?Boolean

Is the target library loaded?

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


41
42
43
# File 'lib/braintrust/contrib/integration.rb', line 41

def loaded?
  raise NotImplementedError, "#{self} must implement loaded?"
end

#maximum_versionString?

Maximum compatible version (optional, inclusive).

Returns:

  • (String, nil)


53
54
55
# File 'lib/braintrust/contrib/integration.rb', line 53

def maximum_version
  nil
end

#minimum_versionString?

Minimum compatible version (optional, inclusive).

Returns:

  • (String, nil)


47
48
49
# File 'lib/braintrust/contrib/integration.rb', line 47

def minimum_version
  nil
end

#patch!(**options) ⇒ Boolean

Apply instrumentation (idempotent). Tries all applicable patchers. This method is typically called by instrument! after configuration.

Parameters:

  • options (Hash)

    Configuration options

Options Hash (**options):

  • :target (Object)

    Optional target instance to patch

  • :tracer_provider (OpenTelemetry::SDK::Trace::TracerProvider)

    Optional tracer provider

Returns:

  • (Boolean)

    true if any patching succeeded or was already done



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/braintrust/contrib/integration.rb', line 125

def patch!(**options)
  unless available?
    Braintrust::Log.debug("#{integration_name}.patch! skipped: gem not available")
    return false
  end
  unless loaded?
    Braintrust::Log.debug("#{integration_name}.patch! skipped: library not loaded")
    return false
  end
  unless compatible?
    Braintrust::Log.debug("#{integration_name}.patch! skipped: version not compatible")
    return false
  end

  # Try all applicable patchers
  success = false
  patchers.each do |patch|
    # Check if this patcher is applicable
    next unless patch.applicable?

    # Attempt to patch (patcher checks applicable? again under lock)
    success = true if patch.patch!(**options)
  end

  Braintrust::Log.debug("#{integration_name}.patch! skipped: no applicable patcher") unless success
  success
end

#patcherClass

Convenience method for single patcher (existing pattern). Override this OR patchers (not both).

Returns:

  • (Class)

    The patcher class

Raises:

  • (NotImplementedError)


84
85
86
# File 'lib/braintrust/contrib/integration.rb', line 84

def patcher
  raise NotImplementedError, "#{self} must implement patcher or patchers"
end

#patchersArray<Class>

Array of patcher classes for this integration. Override to return multiple patchers for version-specific logic.

Returns:

  • (Array<Class>)

    Array of patcher classes



77
78
79
# File 'lib/braintrust/contrib/integration.rb', line 77

def patchers
  [patcher] # Default: single patcher
end

#register!Object

Register this integration with the global registry.



154
155
156
# File 'lib/braintrust/contrib/integration.rb', line 154

def register!
  Registry.instance.register(self)
end

#require_pathsArray<String>

Require paths for auto-instrument detection. Default implementation returns gem_names.

Returns:

  • (Array<String>)


29
30
31
# File 'lib/braintrust/contrib/integration.rb', line 29

def require_paths
  gem_names
end