Skip to content

Commit

Permalink
Support for Opentelemetry Tracing. Programmatic instrumentation of Fl…
Browse files Browse the repository at this point in the history
…ask, SQLAlchemy, and Requests libraries

Signed-off-by: Mike Kingsbury <mike.kingsbury@redhat.com>
  • Loading branch information
mike-kingsbury committed Nov 27, 2023
1 parent 287e913 commit e888a60
Show file tree
Hide file tree
Showing 6 changed files with 448 additions and 0 deletions.
397 changes: 397 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ Flask-Session = "^0.5.0"
# Flask-Session seems to be incompatible with werkzeug-3.0.0
werkzeug = "<3.0.0"

# tracing support
opentelemetry-exporter-otlp = "^1.21.0"
opentelemetry-instrumentation = "^0.42b0"
opentelemetry-instrumentation-flask = "^0.42b0"
opentelemetry-instrumentation-sqlalchemy = "^0.42b0"
opentelemetry-instrumentation-requests = "^0.42b0"

[tool.poetry.extras]
test = [
"pytest",
Expand Down
3 changes: 3 additions & 0 deletions resultsdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from resultsdb.controllers.api_v3 import api as api_v3, create_endpoints
from resultsdb.messaging import load_messaging_plugin
from resultsdb.models import db
from resultsdb.tracing import setup_tracing
from . import config


Expand Down Expand Up @@ -95,6 +96,8 @@ def create_app(config_obj=None):

setup_logging(app)

setup_tracing(app)

app.logger.info("Using configuration object: %s", config_obj)
if openshift:
app.logger.info("Using OpenShift configuration")
Expand Down
2 changes: 2 additions & 0 deletions resultsdb/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class Config(object):

# Publish Taskotron-compatible fedmsgs on the 'taskotron' topic
MESSAGE_BUS_PUBLISH_TASKOTRON = False
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = None
OTEL_EXPORTER_SERVICE_NAME = "resultsdb"


class ProductionConfig(Config):
Expand Down
6 changes: 6 additions & 0 deletions resultsdb/messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
ConnectionException,
)

from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator

log = logging.getLogger(__name__)

SERIALIZE = Serializer().serialize
Expand Down Expand Up @@ -152,6 +154,9 @@ class DummyPlugin(MessagingPlugin):
history = []

def publish(self, message):
# Add telemetry information. This includes an extra key
# traceparent.
TraceContextTextMapPropagator().inject(message)
self.history.append(message)
log.info("%r->%r" % (self, message))

Expand Down Expand Up @@ -209,6 +214,7 @@ def __init__(self, **kwargs):

def publish(self, msg):
msg = json.dumps(msg)

kwargs = dict(body=msg, headers={}, destination=self.destination)

conn = stomp.connect.StompConnection11(**self.connection)
Expand Down
33 changes: 33 additions & 0 deletions resultsdb/tracing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# SPDX-License-Identifier: GPL-2.0+

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor


def setup_tracing(app):
endpoint = app.config.get("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT")
service_name = app.config.get("OTEL_EXPORTER_SERVICE_NAME")
if not endpoint or not service_name:
return
resource = Resource(attributes={SERVICE_NAME: service_name})
provider = TracerProvider(resource=resource)
instrumentor = FlaskInstrumentor()
instrumentor.instrument_app(app)
SQLAlchemyInstrumentor().instrument(
enable_commenter=True,
commenter_options={
"db_driver": True,
},
)
RequestsInstrumentor().instrument()
otlp_exporter = OTLPSpanExporter(endpoint=app.config["OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"])
processor = BatchSpanProcessor(otlp_exporter)
# processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

0 comments on commit e888a60

Please sign in to comment.