OTel Context Propagation for MQ Applications: part 4 – Python

OTel logo

Previous articles in this series have shown OpenTelemetry (OTel) Context propagation for Node.js, Go, Java and C/C++ MQ applications. You should read the first article for an introduction and explanation of the scenarios and problems that need solutions.

This entry discusses Python MQ applications.

Background

Towards the end of 2025, we released an updated implementation of the Python MQI library. I didn’t write about it at the time, as this article covered the main points. And documents within the source tree had lots more details about the changes, the new designs, and the rationales for choices made.

But one thing missing from the library which would give it effective parity to the Go and Node.js language bindings was support for OTel trace context propagation. That feature is now available in version 2.0.2 of the ibmmq library, released alongside MQ 9.4.5.

Automatic Tracing

The OTel SDK developers provide automatic tracing capability for several languages and several standard (or commonly-used) packages. We take advantage of the Python libraries here.

If you only use libraries that are already known by the automatic instrumentation system, then no additional work is required in your application code to take advantage of this. The only change is how you start the application.

You can of course also explicitly instrument Python applications with your own calls to the OTel API.

The MQ component

The implementation in the ibmmq Python library is also automatic. If it can access the OTel libraries via an import, it tries to use them. If the libraries are not available, then no OTel work will be attempted. There is also an MQIPY_NOOTEL environment variable to disable the MQ interception and processing even if the OTel libraries are available.

Example

As with the other languages discussed in this series, I started with the dice-rolling application described here.

To get the OTel libraries, it’s essentially a matter of running pip install opentelemetry-distro for the packages, and then opentelemetry-bootstrap -a installto configure the environment. As always with Python, you should use a virtual environment to isolate your installed packages.

And then I replaced the work in the sample application with MQ operations. In this case, it was to make Python calls to send or receive messages through an MQ network.

Application Startup

There was no code change for instrumenting this application. Just configuration and startup options:

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
opentelemetry-instrument \
--traces_exporter otlp \
--metrics_exporter none \
--logs_exporter none \
--service_name python \
flask run -p 4000 &

Using the opentelemetry-instrumentcommand causes the Python execution to insert calls around any of the APIs it recognises, to emit the OTel traces and spans. In this case, it knows about flask and its HTTP operations.

The configuration options tell the OTel instrumentation module what kind of information it should emit, and how. I’ve requested just the tracing data, to use the OTLP/gRPC protocol.

Results

Just as in the previous examples for Go and Node, we can see Traces being linked all the way from an HTTP request through the MQ network.

And when the message is taken from a queue, the trace associated with the HTTP request is linked to the original trace.

The RemoveRFH2 option

Again, just as in the Go and Node propagators there is a need to allow applications to get messages without any unexpected RFH2 element at the front. The way I’ve allowed this in the Python MQI library is to give an optional extra element on the Queue.get method. Instead of

message = queue.get(None, md, gmo)

we create a new object and use a keyword to pass that in:

otel_options = ibmmq.OTelOptions(remove_rfh2=True}
message = queue.get(None, md, gmo, otel_options=otel_options)

The Queue.get method (and its relatives) and the QueueManager.cb method are the only places this optional object can be used.

Conclusion

This new feature brings the Python MQI bindings into parity with several other language bindings. It fills a gap that is not being addressed by the core OpenTelemetry toolkits, and will allow better insight into the behaviour of your MQ applications.

Leave a Reply

Your email address will not be published. Required fields are marked *