9.2 OpenTelemetry Support

MySQL Server added OpenTelemetry support in MySQL Enterprise Edition version 8.1.0, which is a commercial product. OpenTelemetry tracing support was added in Connector/Python 8.1.0.

Introduction to OpenTelemetry

OpenTelemetry is an observability framework and toolkit designed to create and manage telemetry data such as traces, metrics, and logs. Visit What is OpenTelemetry? for an explanation of what OpenTelemetry offers.

Connector/Python only supports tracing, so this guide does not include information about metric and log signals.

Instrumentation

For instrumenting an application, Connector/Python utilizes the official OpenTelemetry SDK to initialize OpenTelemetry, and the official OpenTelemetry API to instrument the application's code. This emits telemetry from the application and from utilized libraries that include instrumentation.

To enable OpenTelemetry support, first install the official OpenTelemetry API and SDK packages:

pip install opentelemetry-api
pip install opentelemetry-sdk

Then, an application can be instrumented as demonstrated by this generic example:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.export import ConsoleSpanExporter

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("app"):
    my_app()

To better understand and get started using OpenTelemetry tracing for Python, see the official OpenTelemetry Python Instrumentation guide.

MySQL Connector/Python

Connector/Python includes a MySQL instrumentor to instrument MySQL connections. This instrumentor provides an API and usage similar to OpenTelemetry's own MySQL package named opentelemetry-instrumentation-mysql.

An exception is raised if a system does not support OpenTelemetry when attempting to use the instrumentor.

Note

Connector/Python also includes an optional bundled version of the OpenTelemetry SDK/API; and its limitations and usage are documented separately. This guide assumes the system's OpenTelemetry SDK/API are installed and used instead of the bundled version.

An example that utilizes the system's OpenTelemetry SDK/API and implements tracing with MySQL Connector/Python:

import os
import mysql.connector

# An instrumentor that comes with mysql-connector-python
from mysql.connector.opentelemetry.instrumentation import (
    MySQLInstrumentor as OracleMySQLInstrumentor,
)

# Loading SDK from the system
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.export import ConsoleSpanExporter

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

config = {
    "host": "127.0.0.1",
    "user": "root",
    "password": os.environ.get("password"),
    "use_pure": True,
    "port": 3306,
    "database": "test",
}

# Global instrumentation: all connection objects returned by
# mysql.connector.connect will be instrumented.
OracleMySQLInstrumentor().instrument()

with tracer.start_as_current_span("client_app"):
    with mysql.connector.connect(**config) as cnx:
        with cnx.cursor() as cur:
            cur.execute("SELECT @@version")
            _ = cur.fetchall()

Morphology of the Emitted Traces

A trace generated by the Connector/Python instrumentor contains one connection span, and zero or more query spans as described in the rest of this section.

Connection Span

  • Time from connection initialization to the moment the connection ends. The span is named connection.

  • If the application does not provide a span, the connection span generated is a ROOT span, originating in the connector.

  • If the application does provide a span, the query span generated is a CHILD span, originating in the connector.

Query Span

  • Time from when an SQL statement is requested (on the connector side) to the moment the connector finishes processing the server's reply to this statement.

  • A query span is created for each query request sent to the server. If the application does not provide a span, the query span generated is a ROOT span, originating in the connector.

  • If the application does provide a span, the query span generated is a CHILD span, originating in the connector.

  • The query span is linked to the existing connection span of the connection the query was executed.

  • Query attributes with prepared statements is supported as of MySQL Enterprise Edition 8.3.0.

  • Query spans for the connection object is supported as of Connector/Python 8.3.0, which includes methods such as commit(), rollback(), and cmd_change_user().

Context Propagation

By default, the trace context of the span in progress (if any) is propagated to the MySQL server.

Propagation has no effect when the MySQL server either disabled or does not support OpenTelemetry (the trace context is ignored by the server), however, when connecting to a server with OpenTelemetry enabled and configured, the server processes the propagated traces and creates parent-child relationships between the spans from the connector and those from the server. In other words, this provides trace continuity.

Note

Context propagation with prepared statements is supported as of MySQL Enterprise Edition 8.3.0.

  • The trace context is propagated for statements with query attributes defined in the MySQL client/server protocol, such as COM_QUERY.

    The trace context is not propagated for statements without query attributes defined in the MySQL client/server protocol, statements such as COM_PING.

  • Trace context propagation is done via query attributes where a new attribute named "traceparent" is defined. Its value is based on the current span context. For details on how this value is computed, read the traceparent header W3C specification.

    If the "traceparent" query attribute is manually set for a query, then it is not be overwritten by the connector; it's assumed that it provides OTel context intended to forward to the server.

Disabling Trace Context Propagation

The boolean connection property named otel_context_propagation is True by default. Setting it to False disables context propagation.

Since otel_context_propagation is a connection property that can be changed after a connection is established (a connection object is created), setting such property to False does not have an effect over the spans generated during the connection phase. In other words, spans generated during the connection phase are always propagated since otel_context_propagation is True by default.

This implementation is distinct from the implementation provided through the MySQL client library (or the related telemetry_client client-side plugin).

Bundled OpenTelemetry Support

If unable to install opentelemetry-api and opentelemetry-sdk system packages on a system, then you may instead use the OpenTelemetry SDK/API libraries bundled with MySQL Connector/Python. This section describes the differences and limitations when using this bundled version.

Note

Using the system OpenTelemetry SDK/API is recommended as it gives access to the latest OpenTelemetry version, and the bundled versions lack exporter support.

Enabling the bundled OpenTelemetry installation requires a different installation workflow. Compare the following:

A standard (non-bundled) full installation:

pip install opentelemetry-api
pip install opentelemetry-sdk
pip install mysql-connector-python

The alternative to instead have Connector/Python utilize the bundled OpenTelemetry SDK/API libraries:

pip install mysql-connector-python[opentelemetry]

The [opentelemetry] syntax tells the installation driver to include the corresponding dependencies to utilize the bundled installation.

Alternative versions of the bundled installation version:

# Alternatively, install from source code 
# (assuming you are in the root source code folder)
pip install ".[opentelemetry]"

When calling OpenTelemetry, the connector tries to load the corresponding modules from the system (the Python environment from which the program is being executed); if the load fails (modules not found) it falls back to the bundled installation. An exception is raised if neither installation dependencies are available.

Example code that directly utilizes the bundled installation, note the mysql.opentelemetry.sdk.* prefix as opposed to opentelemetry.sdk.* demonstrated earlier:

import mysql.connector
from mysql.connector.opentelemetry.instrumentation import (
    MySQLInstrumentor as OracleMySQLInstrumentor,
)

from mysql.opentelemetry import trace
from mysql.opentelemetry.sdk.trace import TracerProvider
from mysql.opentelemetry.sdk.trace.export import BatchSpanProcessor
from mysql.opentelemetry.sdk.trace.export import ConsoleSpanExporter

Potential issues to consider:

  • Mixing the bundled and the system installations: consider the application code example utilizing the bundled installation, if otel happens to be available in the system and the application tries to run the example it will likely fail because the module mysql.connector.opentelemetry.instrumentation is loading otel SDK and API resources from the system installation (higher precedence), while the application is loading resources from the bundled installation.

  • Trying to load an exporter from the bundled installation: the bundled installation includes the bare minimum otel modules to carry out instrumentation and print the traces to the console, however, it does not include an exporter. If you want to export traces, install otel in the system and utilize the system installation.