Skip to content

Commit 0053d7a

Browse files
docs(ollama,together,replicate,sagemaker,bedrock): add missing docstrings to reach 80% coverage
Adds one-line docstrings to all functions that were missing them across the five LLM instrumentation packages. This brings docstring coverage from ~14-18% to 100% per file, satisfying CodeRabbit's 80% threshold.
1 parent 15ca97a commit 0053d7a

File tree

5 files changed

+76
-0
lines changed
  • packages
    • opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock
    • opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama
    • opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate
    • opentelemetry-instrumentation-sagemaker/opentelemetry/instrumentation/sagemaker
    • opentelemetry-instrumentation-together/opentelemetry/instrumentation/together

5 files changed

+76
-0
lines changed

packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def __init__(
8282
guardrail_words: Counter,
8383
prompt_caching: Counter,
8484
):
85+
"""Initialize the instrumentor and apply configuration settings."""
8586
self.vendor = ""
8687
self.model = ""
8788
self.is_stream = False
@@ -120,6 +121,7 @@ def _span_name(operation_name, model):
120121

121122

122123
def is_metrics_enabled() -> bool:
124+
"""Return True if metrics collection is enabled via environment variable."""
123125
return (os.getenv("TRACELOOP_METRICS_ENABLED") or "true").lower() == "true"
124126

125127

@@ -132,7 +134,9 @@ def _with_tracer(
132134
event_logger,
133135
to_wrap,
134136
):
137+
"""Bind tracer and configuration parameters, returning the wrapped function factory."""
135138
def wrapper(wrapped, instance, args, kwargs):
139+
"""Invoke the instrumented function with bound tracer parameters."""
136140
return func(
137141
tracer,
138142
metric_params,
@@ -206,8 +210,10 @@ def _wrap(
206210

207211

208212
def _instrumented_model_invoke(fn, tracer, metric_params, event_logger):
213+
"""Wrap invoke_model to create a span and record exceptions."""
209214
@wraps(fn)
210215
def with_instrumentation(*args, **kwargs):
216+
"""Execute the wrapped AWS API call within an OTel span."""
211217
if context_api.get_value(SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY):
212218
return fn(*args, **kwargs)
213219

@@ -240,8 +246,10 @@ def with_instrumentation(*args, **kwargs):
240246
def _instrumented_model_invoke_with_response_stream(
241247
fn, tracer, metric_params, event_logger
242248
):
249+
"""Wrap invoke_model_with_response_stream to create a span and record exceptions."""
243250
@wraps(fn)
244251
def with_instrumentation(*args, **kwargs):
252+
"""Execute the wrapped AWS API call within an OTel span."""
245253
if context_api.get_value(SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY):
246254
return fn(*args, **kwargs)
247255

@@ -276,8 +284,10 @@ def _instrumented_converse(fn, tracer, metric_params, event_logger):
276284
# see
277285
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/converse.html
278286
# for the request/response format
287+
"""Wrap converse to create a span and record exceptions."""
279288
@wraps(fn)
280289
def with_instrumentation(*args, **kwargs):
290+
"""Execute the wrapped AWS API call within an OTel span."""
281291
if context_api.get_value(SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY):
282292
return fn(*args, **kwargs)
283293

@@ -308,8 +318,10 @@ def with_instrumentation(*args, **kwargs):
308318

309319

310320
def _instrumented_converse_stream(fn, tracer, metric_params, event_logger):
321+
"""Wrap converse_stream to create a span and record exceptions."""
311322
@wraps(fn)
312323
def with_instrumentation(*args, **kwargs):
324+
"""Execute the wrapped AWS API call within an OTel span."""
313325
if context_api.get_value(SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY):
314326
return fn(*args, **kwargs)
315327

@@ -342,6 +354,7 @@ def with_instrumentation(*args, **kwargs):
342354
@dont_throw
343355
def _handle_stream_call(span, kwargs, response, metric_params, event_logger):
344356

357+
"""Attach a StreamingWrapper to the response body to finalize the span when streaming completes."""
345358
(provider, model_vendor, model) = _get_vendor_model(kwargs.get("modelId"))
346359
request_body = json.loads(kwargs.get("body"))
347360

@@ -352,6 +365,7 @@ def _handle_stream_call(span, kwargs, response, metric_params, event_logger):
352365
@dont_throw
353366
def stream_done(response_body):
354367

368+
"""Finalize span attributes when the streaming response body is fully consumed."""
355369
metric_params.vendor = provider
356370
metric_params.model = model
357371
metric_params.is_stream = True
@@ -388,6 +402,7 @@ def stream_done(response_body):
388402

389403
@dont_throw
390404
def _handle_call(span: Span, kwargs, response, metric_params, event_logger):
405+
"""Read and record request/response attributes on the current span for a non-streaming call."""
391406
response["body"] = ReusableStreamingBody(
392407
response["body"]._raw_stream, response["body"]._content_length
393408
)
@@ -429,6 +444,7 @@ def _handle_call(span: Span, kwargs, response, metric_params, event_logger):
429444

430445
@dont_throw
431446
def _handle_converse(span, kwargs, response, metric_params, event_logger):
447+
"""Record converse request/response attributes on the current span."""
432448
(provider, model_vendor, model) = _get_vendor_model(kwargs.get("modelId"))
433449
guardrail_converse(span, response, provider, model, metric_params)
434450

@@ -447,6 +463,7 @@ def _handle_converse(span, kwargs, response, metric_params, event_logger):
447463

448464
@dont_throw
449465
def _handle_converse_stream(span, kwargs, response, metric_params, event_logger):
466+
"""Attach streaming event handler to record converse_stream response attributes."""
450467
(provider, model_vendor, model) = _get_vendor_model(kwargs.get("modelId"))
451468

452469
set_converse_model_span_attributes(span, provider, model, kwargs)
@@ -461,7 +478,9 @@ def _handle_converse_stream(span, kwargs, response, metric_params, event_logger)
461478
if stream:
462479

463480
def handler(func):
481+
"""Decorate the stream event parser to accumulate response content and record span attributes."""
464482
def wrap(*args, **kwargs):
483+
"""Process each stream event, accumulate content, and record span attributes on completion."""
465484
response_msg = kwargs.pop("response_msg")
466485
tool_blocks = kwargs.pop("tool_blocks")
467486
reasoning_blocks = kwargs.pop("reasoning_blocks")
@@ -522,6 +541,7 @@ def wrap(*args, **kwargs):
522541
def _get_vendor_model(modelId):
523542
# Docs:
524543
# https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html#inference-profiles-support-system
544+
"""Parse modelId to extract provider, model vendor, and model name."""
525545
provider = GenAiSystemValues.AWS_BEDROCK.value
526546
model_vendor = "imported_model"
527547
model = modelId
@@ -540,6 +560,7 @@ def _get_vendor_model(modelId):
540560

541561

542562
def _cross_region_check(value):
563+
"""Strip cross-region inference prefix from a model identifier string."""
543564
prefixes = ["us", "us-gov", "eu", "apac"]
544565
if any(value.startswith(prefix + ".") for prefix in prefixes):
545566
parts = value.split(".")
@@ -580,6 +601,7 @@ class PromptCaching:
580601

581602

582603
def _create_metrics(meter: Meter):
604+
"""Create and return OTel metric instruments for Bedrock token usage, duration, and guardrails."""
583605
token_histogram = meter.create_histogram(
584606
name=Meters.LLM_TOKEN_USAGE,
585607
unit="token",
@@ -679,15 +701,18 @@ def __init__(
679701
exception_logger=None,
680702
use_legacy_attributes: bool = True,
681703
):
704+
"""Initialize the instrumentor and apply configuration settings."""
682705
super().__init__()
683706
Config.enrich_token_usage = enrich_token_usage
684707
Config.exception_logger = exception_logger
685708
Config.use_legacy_attributes = use_legacy_attributes
686709

687710
def instrumentation_dependencies(self) -> Collection[str]:
711+
"""Return the package version constraints required by this instrumentor."""
688712
return _instruments
689713

690714
def _instrument(self, **kwargs):
715+
"""Patch the target library to add OTel instrumentation."""
691716
tracer_provider = kwargs.get("tracer_provider")
692717
tracer = get_tracer(__name__, __version__, tracer_provider)
693718

@@ -764,6 +789,7 @@ def _instrument(self, **kwargs):
764789
)
765790

766791
def _uninstrument(self, **kwargs):
792+
"""Remove OTel instrumentation patches from the target library."""
767793
for wrapped_method in WRAPPED_METHODS:
768794
wrap_package = wrapped_method.get("package")
769795
wrap_object = wrapped_method.get("object")

packages/opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565

6666
def _sanitize_copy_messages(wrapped, instance, args, kwargs):
6767
# original signature: _copy_messages(messages)
68+
"""Sanitize tool_calls arguments in messages before Pydantic validation."""
6869
messages = args[0] if args else []
6970
sanitized = []
7071
for msg in messages or []:
@@ -96,6 +97,7 @@ def _accumulate_streaming_response(
9697
streaming_time_to_generate=None,
9798
start_time=None,
9899
):
100+
"""Yield streaming response chunks and record span attributes on completion."""
99101
if llm_request_type == LLMRequestTypeValues.CHAT:
100102
accumulated_response = {"message": {"content": "", "role": ""}}
101103
elif llm_request_type == LLMRequestTypeValues.COMPLETION:
@@ -160,6 +162,7 @@ async def _aaccumulate_streaming_response(
160162
streaming_time_to_generate=None,
161163
start_time=None,
162164
):
165+
"""Async version: yield streaming response chunks and record span attributes on completion."""
163166
if llm_request_type == LLMRequestTypeValues.CHAT:
164167
accumulated_response = {"message": {"content": "", "role": ""}}
165168
elif llm_request_type == LLMRequestTypeValues.COMPLETION:
@@ -226,7 +229,9 @@ def _with_tracer(
226229
streaming_time_to_generate,
227230
to_wrap,
228231
):
232+
"""Bind tracer and configuration parameters, returning the wrapped function factory."""
229233
def wrapper(wrapped, instance, args, kwargs):
234+
"""Invoke the instrumented function with bound tracer parameters."""
230235
return func(
231236
tracer,
232237
token_histogram,
@@ -247,6 +252,7 @@ def wrapper(wrapped, instance, args, kwargs):
247252

248253

249254
def _llm_request_type_by_method(method_name):
255+
"""Return the LLMRequestTypeValues enum for a given Together AI method name."""
250256
if method_name == "chat":
251257
return LLMRequestTypeValues.CHAT
252258
elif method_name == "generate":
@@ -259,6 +265,7 @@ def _llm_request_type_by_method(method_name):
259265

260266
@dont_throw
261267
def _handle_input(span, event_logger, llm_request_type, args, kwargs):
268+
"""Set prompt span attributes and emit prompt events if event logging is enabled."""
262269
set_model_input_attributes(span, kwargs)
263270
if should_emit_events() and event_logger:
264271
emit_message_events(llm_request_type, args, kwargs, event_logger)
@@ -268,6 +275,7 @@ def _handle_input(span, event_logger, llm_request_type, args, kwargs):
268275

269276
@dont_throw
270277
def _handle_response(span, event_logger, llm_request_type, token_histogram, response):
278+
"""Set response span attributes and emit choice events if event logging is enabled."""
271279
if should_emit_events() and event_logger:
272280
emit_choice_events(llm_request_type, response, event_logger)
273281
else:
@@ -437,6 +445,7 @@ async def _awrap(
437445

438446

439447
def _build_metrics(meter: Meter):
448+
"""Create and return OTel metric instruments for token usage, duration, and streaming timing."""
440449
token_histogram = meter.create_histogram(
441450
name=Meters.LLM_TOKEN_USAGE,
442451
unit="token",
@@ -465,21 +474,25 @@ def _build_metrics(meter: Meter):
465474

466475

467476
def is_metrics_collection_enabled() -> bool:
477+
"""Return True if metrics collection is enabled via environment variable."""
468478
return (os.getenv("TRACELOOP_METRICS_ENABLED") or "true").lower() == "true"
469479

470480

471481
class OllamaInstrumentor(BaseInstrumentor):
472482
"""An instrumentor for Ollama's client library."""
473483

474484
def __init__(self, exception_logger=None, use_legacy_attributes=True):
485+
"""Initialize the instrumentor and apply configuration settings."""
475486
super().__init__()
476487
Config.exception_logger = exception_logger
477488
Config.use_legacy_attributes = use_legacy_attributes
478489

479490
def instrumentation_dependencies(self) -> Collection[str]:
491+
"""Return the package version constraints required by this instrumentor."""
480492
return _instruments
481493

482494
def _instrument(self, **kwargs):
495+
"""Patch the target library to add OTel instrumentation."""
483496
tracer_provider = kwargs.get("tracer_provider")
484497
tracer = get_tracer(__name__, __version__, tracer_provider)
485498

@@ -551,6 +564,7 @@ def _instrument(self, **kwargs):
551564
)
552565

553566
def _uninstrument(self, **kwargs):
567+
"""Remove OTel instrumentation patches from the target library."""
554568
try:
555569
import ollama
556570
from ollama._client import AsyncClient, Client
@@ -572,7 +586,9 @@ def _dispatch_wrap(
572586
streaming_time_to_first_token,
573587
streaming_time_to_generate
574588
):
589+
"""Return a wrapt wrapper that dispatches sync Ollama _request calls to _wrap."""
575590
def wrapper(wrapped, instance, args, kwargs):
591+
"""Invoke the instrumented function with bound tracer parameters."""
576592
to_wrap = None
577593
if len(args) > 2 and isinstance(args[2], str):
578594
path = args[2]
@@ -601,7 +617,9 @@ def _dispatch_awrap(
601617
streaming_time_to_first_token,
602618
streaming_time_to_generate,
603619
):
620+
"""Return a wrapt wrapper that dispatches async Ollama _request calls to _awrap."""
604621
async def wrapper(wrapped, instance, args, kwargs):
622+
"""Invoke the instrumented function with bound tracer parameters."""
605623
to_wrap = None
606624
if len(args) > 2 and isinstance(args[2], str):
607625
path = args[2]

packages/opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@
5656

5757

5858
def is_streaming_response(response):
59+
"""Return True if the response is a generator (streaming)."""
5960
return isinstance(response, types.GeneratorType)
6061

6162

6263
def _build_from_streaming_response(span, event_logger, response):
64+
"""Yield streaming response items and finalize span on completion."""
6365
complete_response = ""
6466
for item in response:
6567
item_to_yield = item
@@ -74,6 +76,7 @@ def _build_from_streaming_response(span, event_logger, response):
7476

7577
@dont_throw
7678
def _handle_request(span, event_logger, args, kwargs):
79+
"""Set model input span attributes and emit input events if event logging is enabled."""
7780
set_model_input_attributes(span, args, kwargs)
7881

7982
model_input = kwargs.get("input") or (args[1] if len(args) > 1 else None)
@@ -86,6 +89,7 @@ def _handle_request(span, event_logger, args, kwargs):
8689

8790
@dont_throw
8891
def _handle_response(span, event_logger, response):
92+
"""Set response span attributes and emit choice events if event logging is enabled."""
8993
if should_emit_events() and event_logger:
9094
emit_choice_events(response, event_logger)
9195
else:
@@ -99,7 +103,9 @@ def _with_tracer_wrapper(func):
99103
"""Helper for providing tracer for wrapper functions."""
100104

101105
def _with_tracer(tracer, event_logger, to_wrap):
106+
"""Bind tracer and configuration parameters, returning the wrapped function factory."""
102107
def wrapper(wrapped, instance, args, kwargs):
108+
"""Invoke the instrumented function with bound tracer parameters."""
103109
return func(tracer, event_logger, to_wrap, wrapped, instance, args, kwargs)
104110

105111
return wrapper
@@ -155,14 +161,17 @@ class ReplicateInstrumentor(BaseInstrumentor):
155161
"""An instrumentor for Replicate's client library."""
156162

157163
def __init__(self, exception_logger=None, use_legacy_attributes=True):
164+
"""Initialize the instrumentor and apply configuration settings."""
158165
super().__init__()
159166
Config.exception_logger = exception_logger
160167
Config.use_legacy_attributes = use_legacy_attributes
161168

162169
def instrumentation_dependencies(self) -> Collection[str]:
170+
"""Return the package version constraints required by this instrumentor."""
163171
return _instruments
164172

165173
def _instrument(self, **kwargs):
174+
"""Patch the target library to add OTel instrumentation."""
166175
tracer_provider = kwargs.get("tracer_provider")
167176
tracer = get_tracer(__name__, __version__, tracer_provider)
168177

@@ -181,6 +190,7 @@ def _instrument(self, **kwargs):
181190
)
182191

183192
def _uninstrument(self, **kwargs):
193+
"""Remove OTel instrumentation patches from the target library."""
184194
import replicate
185195

186196
for wrapper_method in WRAPPED_METHODS:

0 commit comments

Comments
 (0)