Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit d67b206

Browse files
authored
Decouple exporters from Flask integration (#621)
1 parent ca20772 commit d67b206

File tree

10 files changed

+220
-328
lines changed

10 files changed

+220
-328
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright 2019, OpenCensus Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from flask import Flask
16+
from opencensus.ext.flask.flask_middleware import FlaskMiddleware
17+
18+
app = Flask(__name__)
19+
# TODO:
20+
# Replace 00000000-0000-0000-0000-000000000000 with your Instrumentation Key
21+
# https://docs.microsoft.com/en-us/azure/azure-monitor/app/create-new-resource
22+
app.config['OPENCENSUS'] = {
23+
'TRACE': {
24+
'SAMPLER': 'opencensus.trace.samplers.ProbabilitySampler(rate=1)',
25+
'EXPORTER': '''opencensus.ext.azure.trace_exporter.AzureExporter(
26+
opencensus.ext.azure.common.Options(
27+
instrumentation_key="00000000-0000-0000-0000-000000000000",
28+
timeout=29.9,
29+
))''',
30+
},
31+
}
32+
middleware = FlaskMiddleware(app)
33+
34+
35+
@app.route('/')
36+
def hello():
37+
return 'Hello World!'
38+
39+
40+
if __name__ == '__main__':
41+
import logging
42+
logger = logging.getLogger('werkzeug')
43+
logger.setLevel(logging.ERROR)
44+
app.run(host='localhost', port=8080, threaded=True)

contrib/opencensus-ext-azure/examples/server.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,9 @@
1818
from opencensus.trace import config_integration
1919
from opencensus.ext.azure.trace_exporter import AzureExporter
2020
from opencensus.ext.flask.flask_middleware import FlaskMiddleware
21-
from opencensus.trace.propagation.trace_context_http_header_format \
22-
import TraceContextPropagator
2321

2422
app = Flask(__name__)
25-
middleware = FlaskMiddleware(
26-
app,
27-
exporter=AzureExporter(),
28-
propagator=TraceContextPropagator(),
29-
)
23+
middleware = FlaskMiddleware(app, exporter=AzureExporter())
3024

3125

3226
@app.route('/')

contrib/opencensus-ext-flask/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
## Unreleased
4+
- Decoupled exporter specific logic from configuration
45

56
## 0.2.0
67
Released 2019-04-08

contrib/opencensus-ext-flask/README.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ Usage
2020
2121
from flask import Flask
2222
from opencensus.ext.flask.flask_middleware import FlaskMiddleware
23-
from opencensus.trace.propagation.trace_context_http_header_format import TraceContextPropagator
2423
2524
app = Flask(__name__)
26-
middleware = FlaskMiddleware(app, propagator=TraceContextPropagator(), blacklist_paths=['_ah/health'])
25+
middleware = FlaskMiddleware(app, blacklist_paths=['_ah/health'])
2726
2827
@app.route('/')
2928
def hello():
@@ -34,3 +33,18 @@ Usage
3433
logger = logging.getLogger('werkzeug')
3534
logger.setLevel(logging.ERROR)
3635
app.run(host='localhost', port=8080, threaded=True)
36+
37+
Additional configuration can be provided, please read
38+
`Customization <https://github.com/census-instrumentation/opencensus-python#customization>`_
39+
for a complete reference.
40+
41+
.. code:: python
42+
43+
app.config['OPENCENSUS'] = {
44+
'TRACE': {
45+
'SAMPLER': 'opencensus.trace.samplers.ProbabilitySampler(rate=1)',
46+
'EXPORTER': '''opencensus.ext.ocagent.trace_exporter.TraceExporter(
47+
service_name='foobar',
48+
)''',
49+
}
50+
}

contrib/opencensus-ext-flask/examples/simple.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414

1515
from flask import Flask
1616
from opencensus.ext.flask.flask_middleware import FlaskMiddleware
17-
from opencensus.trace.propagation.trace_context_http_header_format \
18-
import TraceContextPropagator
1917

2018
app = Flask(__name__)
21-
middleware = FlaskMiddleware(app, propagator=TraceContextPropagator())
19+
middleware = FlaskMiddleware(app)
2220

2321

2422
@app.route('/')

contrib/opencensus-ext-flask/opencensus/ext/flask/flask_middleware.py

Lines changed: 42 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import inspect
1615
import logging
16+
import six
1717
import sys
1818

1919
import flask
2020
from google.rpc import code_pb2
2121

22-
from opencensus.common.transports import sync
22+
from opencensus.common import configuration
2323
from opencensus.trace import attributes_helper
2424
from opencensus.trace import execution_context
2525
from opencensus.trace import print_exporter
@@ -28,38 +28,20 @@
2828
from opencensus.trace import status
2929
from opencensus.trace import tracer as tracer_module
3030
from opencensus.trace import utils
31-
from opencensus.trace.propagation import google_cloud_format
32-
from opencensus.trace.samplers import always_on, probability
31+
from opencensus.trace.propagation import trace_context_http_header_format
32+
from opencensus.trace.samplers import always_on
3333

3434
HTTP_METHOD = attributes_helper.COMMON_ATTRIBUTES['HTTP_METHOD']
3535
HTTP_URL = attributes_helper.COMMON_ATTRIBUTES['HTTP_URL']
3636
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
3737

3838
BLACKLIST_PATHS = 'BLACKLIST_PATHS'
39-
GCP_EXPORTER_PROJECT = 'GCP_EXPORTER_PROJECT'
40-
SAMPLING_RATE = 'SAMPLING_RATE'
41-
TRANSPORT = 'TRANSPORT'
42-
SERVICE_NAME = 'SERVICE_NAME'
43-
ZIPKIN_EXPORTER_SERVICE_NAME = 'ZIPKIN_EXPORTER_SERVICE_NAME'
44-
ZIPKIN_EXPORTER_HOST_NAME = 'ZIPKIN_EXPORTER_HOST_NAME'
45-
ZIPKIN_EXPORTER_PORT = 'ZIPKIN_EXPORTER_PORT'
46-
ZIPKIN_EXPORTER_PROTOCOL = 'ZIPKIN_EXPORTER_PROTOCOL'
47-
JAEGER_EXPORTER_HOST_NAME = 'JAEGER_EXPORTER_HOST_NAME'
48-
JAEGER_EXPORTER_PORT = 'JAEGER_EXPORTER_PORT'
49-
JAEGER_EXPORTER_AGENT_HOST_NAME = 'JAEGER_EXPORTER_AGENT_HOST_NAME'
50-
JAEGER_EXPORTER_AGENT_PORT = 'JAEGER_EXPORTER_AGENT_PORT'
51-
JAEGER_EXPORTER_SERVICE_NAME = 'JAEGER_EXPORTER_SERVICE_NAME'
52-
OCAGENT_TRACE_EXPORTER_ENDPOINT = 'OCAGENT_TRACE_EXPORTER_ENDPOINT'
5339
BLACKLIST_HOSTNAMES = 'BLACKLIST_HOSTNAMES'
5440

5541
log = logging.getLogger(__name__)
5642

5743

5844
class FlaskMiddleware(object):
59-
DEFAULT_SAMPLER = always_on.AlwaysOnSampler
60-
DEFAULT_EXPORTER = print_exporter.PrintExporter
61-
DEFAULT_PROPAGATOR = google_cloud_format.GoogleCloudFormatPropagator
62-
6345
"""Flask middleware to automatically trace requests.
6446
6547
:type app: :class: `~flask.Flask`
@@ -68,24 +50,25 @@ class FlaskMiddleware(object):
6850
:type blacklist_paths: list
6951
:param blacklist_paths: Paths that do not trace.
7052
71-
:type sampler: :class: `type`
72-
:param sampler: Class for creating new Sampler objects. It should extend
73-
from the base :class:`.Sampler` type and implement
53+
:type sampler: :class:`~opencensus.trace.samplers.base.Sampler`
54+
:param sampler: A sampler. It should extend from the base
55+
:class:`.Sampler` type and implement
7456
:meth:`.Sampler.should_sample`. Defaults to
7557
:class:`.AlwaysOnSampler`. The rest options are
7658
:class:`.AlwaysOffSampler`, :class:`.FixedRateSampler`.
7759
78-
:type exporter: :class: `type`
79-
:param exporter: Class for creating new exporter objects. Default to
80-
:class:`.PrintExporter`. The rest option is
81-
:class:`.FileExporter`.
60+
:type exporter: :class:`~opencensus.trace.base_exporter.exporter`
61+
:param exporter: An exporter. Default to
62+
:class:`.PrintExporter`. The rest options are
63+
:class:`.FileExporter`, :class:`.LoggingExporter` and
64+
trace exporter extensions.
8265
83-
:type propagator: :class: 'type'
84-
:param propagator: Class for creating new propagator objects. Default to
85-
:class:`.GoogleCloudFormatPropagator`. The rest option
66+
:type propagator: :class: 'object'
67+
:param propagator: A propagator. Default to
68+
:class:`.TraceContextPropagator`. The rest options
8669
are :class:`.BinaryFormatPropagator`,
87-
:class:`.TextFormatPropagator` and
88-
:class:`.TraceContextPropagator`.
70+
:class:`.GoogleCloudFormatPropagator` and
71+
:class:`.TextFormatPropagator`.
8972
"""
9073

9174
def __init__(self, app=None, blacklist_paths=None, sampler=None,
@@ -103,92 +86,31 @@ def init_app(self, app):
10386
self.app = app
10487

10588
# get settings from app config
106-
settings = self.app.config.get('OPENCENSUS_TRACE', {})
107-
108-
self.sampler = (self.sampler
109-
or settings.get('SAMPLER',
110-
self.DEFAULT_SAMPLER))
111-
self.exporter = (self.exporter
112-
or settings.get('EXPORTER',
113-
self.DEFAULT_EXPORTER))
114-
self.propagator = (self.propagator
115-
or settings.get('PROPAGATOR',
116-
self.DEFAULT_PROPAGATOR))
117-
118-
# get params from app config
119-
params = self.app.config.get('OPENCENSUS_TRACE_PARAMS', {})
120-
121-
self.blacklist_paths = params.get(BLACKLIST_PATHS,
122-
self.blacklist_paths)
123-
124-
# Initialize the sampler
125-
if not inspect.isclass(self.sampler):
126-
pass # handling of instantiated sampler
127-
elif self.sampler.__name__ == 'ProbabilitySampler':
128-
_rate = params.get(SAMPLING_RATE,
129-
probability.DEFAULT_SAMPLING_RATE)
130-
self.sampler = self.sampler(_rate)
131-
else:
132-
self.sampler = self.sampler()
133-
134-
transport = params.get(TRANSPORT, sync.SyncTransport)
135-
136-
# Initialize the exporter
137-
if not inspect.isclass(self.exporter):
138-
pass # handling of instantiated exporter
139-
elif self.exporter.__name__ == 'StackdriverExporter':
140-
_project_id = params.get(GCP_EXPORTER_PROJECT, None)
141-
self.exporter = self.exporter(
142-
project_id=_project_id,
143-
transport=transport)
144-
elif self.exporter.__name__ == 'JaegerExporter':
145-
_service_name = params.get(
146-
JAEGER_EXPORTER_SERVICE_NAME,
147-
self._get_service_name(params))
148-
_jaeger_host_name = params.get(
149-
JAEGER_EXPORTER_HOST_NAME, None)
150-
_jaeger_port = params.get(
151-
JAEGER_EXPORTER_PORT, None)
152-
_jaeger_agent_host_name = params.get(
153-
JAEGER_EXPORTER_AGENT_HOST_NAME, 'localhost')
154-
_jaeger_agent_port = params.get(
155-
JAEGER_EXPORTER_AGENT_PORT, 6831)
156-
self.exporter = self.exporter(
157-
service_name=_service_name,
158-
host_name=_jaeger_host_name,
159-
port=_jaeger_port,
160-
agent_host_name=_jaeger_agent_host_name,
161-
agent_port=_jaeger_agent_port,
162-
transport=transport)
163-
elif self.exporter.__name__ == 'ZipkinExporter':
164-
_service_name = self._get_service_name(params)
165-
_zipkin_host_name = params.get(
166-
ZIPKIN_EXPORTER_HOST_NAME, 'localhost')
167-
_zipkin_port = params.get(
168-
ZIPKIN_EXPORTER_PORT, 9411)
169-
_zipkin_protocol = params.get(
170-
ZIPKIN_EXPORTER_PROTOCOL, 'http')
171-
self.exporter = self.exporter(
172-
service_name=_service_name,
173-
host_name=_zipkin_host_name,
174-
port=_zipkin_port,
175-
protocol=_zipkin_protocol,
176-
transport=transport)
177-
elif self.exporter.__name__ == 'TraceExporter':
178-
_service_name = self._get_service_name(params)
179-
_endpoint = params.get(
180-
OCAGENT_TRACE_EXPORTER_ENDPOINT, None)
181-
self.exporter = self.exporter(
182-
service_name=_service_name,
183-
endpoint=_endpoint,
184-
transport=transport)
185-
else:
186-
self.exporter = self.exporter(transport=transport)
187-
188-
self.blacklist_hostnames = params.get(BLACKLIST_HOSTNAMES, None)
189-
# Initialize the propagator
190-
if inspect.isclass(self.propagator):
191-
self.propagator = self.propagator()
89+
settings = self.app.config.get('OPENCENSUS', {})
90+
settings = settings.get('TRACE', {})
91+
92+
if self.sampler is None:
93+
self.sampler = settings.get('SAMPLER', None) or \
94+
always_on.AlwaysOnSampler()
95+
if isinstance(self.sampler, six.string_types):
96+
self.sampler = configuration.load(self.sampler)
97+
98+
if self.exporter is None:
99+
self.exporter = settings.get('EXPORTER', None) or \
100+
print_exporter.PrintExporter()
101+
if isinstance(self.exporter, six.string_types):
102+
self.exporter = configuration.load(self.exporter)
103+
104+
if self.propagator is None:
105+
self.propagator = settings.get('PROPAGATOR', None) or \
106+
trace_context_http_header_format.TraceContextPropagator()
107+
if isinstance(self.propagator, six.string_types):
108+
self.propagator = configuration.load(self.propagator)
109+
110+
self.blacklist_paths = settings.get(BLACKLIST_PATHS,
111+
self.blacklist_paths)
112+
113+
self.blacklist_hostnames = settings.get(BLACKLIST_HOSTNAMES, None)
192114

193115
self.setup_trace()
194116

@@ -280,13 +202,3 @@ def _teardown_request(self, exception):
280202
tracer.finish()
281203
except Exception: # pragma: NO COVER
282204
log.error('Failed to trace request', exc_info=True)
283-
284-
def _get_service_name(self, params):
285-
_service_name = params.get(
286-
SERVICE_NAME, None)
287-
288-
if _service_name is None:
289-
_service_name = params.get(
290-
ZIPKIN_EXPORTER_SERVICE_NAME, 'my_service')
291-
292-
return _service_name

0 commit comments

Comments
 (0)