Skip to content

Instantiating AsyncPGInstrumentor after .instrument has been called causes tracing to fail #1790

@marcuslimdw

Description

@marcuslimdw

Describe your environment

Python 3.11 on a M2 Mac.

Steps to reproduce

Run the following code (with python -m asyncio to allow top-level async/await):

import asyncpg

from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.trace import set_tracer_provider

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
set_tracer_provider(provider)

dsn = "postgres://postgres:password@localhost:54320/postgres"

AsyncPGInstrumentor().instrument()
AsyncPGInstrumentor()

connection = await asyncpg.connect(dsn)
await connection.execute("SELECT 1")

What is the expected behavior?

The SQL query runs successfully and a span is exported to the console.

What is the actual behavior?
What did you see instead?

AttributeError: 'NoneType' object has no attribute 'start_as_current_span'

Additional context

Each instantiation of AsyncPGInstrumentor runs __init__, which sets self._tracer to None. However, BaseInstrumentor overrides __new__ to implement the singleton pattern, so only one instance of AsyncPGInstrumentor is ever created. Instantiating AsyncPGInstrumentor after instrument has been called (which sets self._tracer) therefore sets self._tracer back to None, which is a state inconsistent with _is_instrumented_by_opentelemetry (which will still be True).

A simple solution is to remove the line self._tracer = None.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions