Skip to content
Snippets Groups Projects
Commit 661f78ef authored by ale's avatar ale
Browse files

Switch to opentelemetry

Opencensus has been replaced, there are some API changes.
parent bd24db4f
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@ import hashlib
import pkg_resources
from flask import request, session, g
from flask_talisman import DENY
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from .tracing import setup_tracing
from whitenoise import WhiteNoise
......@@ -14,6 +15,9 @@ DEFAULT_LANGUAGES = [
]
_telemetry_instrumentor = FlaskInstrumentor()
def init_app(app, talisman):
"""Initialize the Flask application."""
......@@ -44,7 +48,9 @@ def init_app(app, talisman):
app.config['SUPPORTED_LANGUAGES_ISO'] = [
x[0] for x in app.config['SUPPORTED_LANGUAGES']]
setup_tracing(app, app.import_name)
_telemetry_instrumentor.instrument_app(app)
if setup_tracing(app.import_name):
app.logger.info('configured request tracing')
# Autodetect language as best as we can, by retrieving it in order
# from either:
......
from flask_testing import TestCase
from ai_web_common.flask_ai.app import init_app
from ai_web_common.flask_ai.test import TestCase
from flask import Flask, make_response
from flask_talisman import Talisman
app = Flask(__name__)
talisman = Talisman()
@app.route('/')
def index():
return make_response('ok')
class TestSimpleApp(TestCase):
def create_app(self):
app.config.update({
'TESTING': True,
'DEBUG': False,
})
init_app(app, talisman)
return app
def test_request(self):
r = self.client.get('/')
self.assertEquals(200, r.status_code)
self.assertEquals('ok', r.data.decode('utf-8'))
import json
import os
from urllib.parse import urlsplit
from opencensus.trace import config_integration
from opentelemetry import trace
from opentelemetry.exporter.zipkin.proto.http import ZipkinExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
tracing_config_file = os.getenv('TRACING_CONFIG', '/etc/tracing/client.conf')
def setup_tracing(app, service_name):
def setup_tracing(service_name):
try:
with open(tracing_config_file) as fd:
config = json.load(fd)
except (OSError, IOError):
return
return False
if 'report_url' not in config:
return
return False
resource = Resource(attributes={
SERVICE_NAME: service_name,
})
# Patch the 'requests' module so that HTTP clients propagate the
# trace ID. Note that this is mostly useless, as the requests
# integration only patches the high-level API (get, post) and does
# not touch the low-level Session interface that we're using for
# our own RPC calls.
config_integration.trace_integrations(['requests'])
zipkin_exporter = ZipkinExporter(endpoint=config['report_url'])
app.logger.info('configured request tracing with service=%s',
service_name)
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(zipkin_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
return True
......@@ -8,9 +8,11 @@ import threading
import time
import urllib3
import urllib3.util
from opencensus.trace import attributes_helper
from opencensus.trace import execution_context
from opencensus.trace import span as span_module
from opentelemetry import trace
from opentelemetry.trace.status import Status
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.instrumentation.utils import http_status_to_status_code
DNS_CACHE_TTL = 60
......@@ -20,11 +22,6 @@ DEFAULT_MAX_TIMEOUT = 30
DEFAULT_MAX_BACKOFF_INTERVAL = 3
HTTP_URL = attributes_helper.COMMON_ATTRIBUTES['HTTP_URL']
HTTP_HOST = attributes_helper.COMMON_ATTRIBUTES['HTTP_HOST']
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
class StatusError(Exception):
def __init__(self, url, resp, extra_msg=None):
......@@ -229,11 +226,16 @@ class ClientStub():
target_addr, target_port = targets.next()
tracer = execution_context.get_opencensus_tracer()
with tracer.span(name=f'[client-rpc] {self.NAME}') as span:
span.span_kind = span_module.SpanKind.CLIENT
tracer.add_attribute_to_current_span(HTTP_URL, parsed_url.url)
tracer.add_attribute_to_current_span(HTTP_HOST, target_addr)
tracer = trace.get_tracer(self.NAME)
with tracer.start_as_current_span(
f'[client-rpc] {self.NAME}',
kind=trace.SpanKind.CLIENT,
attributes={
SpanAttributes.HTTP_URL: parsed_url.url,
SpanAttributes.HTTP_HOST: target_addr,
SpanAttributes.HTTP_METHOD: 'POST',
},
) as span:
pool_args = {
'cls': urllib3.HTTPConnectionPool,
......@@ -279,8 +281,8 @@ class ClientStub():
retries=False,
)
try:
tracer.add_attribute_to_current_span(
HTTP_STATUS_CODE, str(resp.status))
span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, resp.status)
span.set_status(Status(http_status_to_status_code(resp.status)))
if resp.status == 429 or resp.status > 500:
raise RetriableStatusError(parsed_url, resp)
......
......@@ -14,9 +14,9 @@ setup(
"backoff",
"Flask",
"flask-talisman",
"opencensus",
"opencensus-ext-zipkin",
"opencensus-ext-requests",
"opentelemetry-distro",
"opentelemetry-exporter-zipkin-proto-http",
"opentelemetry-instrumentation-flask",
"sso",
"urllib3",
"whitenoise",
......
......@@ -5,6 +5,7 @@ envlist = py3
deps=
git+https://git.autistici.org/ai/sso.git#egg=sso&subdirectory=src/python
cryptography
Flask-Testing
coverage
nose
mock
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment