forked from open-telemetry/opentelemetry-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add autoinstrumentation prototype for Flask
Fixes open-telemetry#300
- Loading branch information
Showing
26 changed files
with
875 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
opentelemetry.auto_instrumentation.patcher package | ||
================================================== | ||
|
||
|
||
Module contents | ||
--------------- | ||
|
||
.. automodule:: opentelemetry.auto_instrumentation.patcher |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Overview | ||
|
||
This example shows how to use auto-instrumentation in OpenTelemetry. This example is also based on a previous example | ||
for OpenTracing that can be found [here](https://github.com/yurishkuro/opentracing-tutorial/tree/master/python). | ||
|
||
This example uses 2 scripts whose main difference is they being instrumented manually or not: | ||
|
||
1. `publisher_instrumented.py` which has been instrumented manually | ||
2. `publisher_uninstrumented.py` which has not been instrumented manually | ||
|
||
The former will be run without the automatic instrumentation agent and the latter with the automatic instrumentation | ||
agent. They should produce an equal result, showing that the automatic instrumentation agent does the equivalent | ||
of what manual instrumentation does. | ||
|
||
In order to understand this better, here is the relevant part of both scripts: | ||
|
||
## Publisher instrumented manually | ||
|
||
`publisher_instrumented.py` | ||
|
||
```python | ||
@app.route("/publish_request") | ||
def publish_request(): | ||
|
||
with tracer.start_as_current_span( | ||
"publish_request", propagators.extract(get_as_list, request.headers) | ||
): | ||
hello_str = request.args.get("helloStr") | ||
print(hello_str) | ||
return "published" | ||
``` | ||
|
||
## Publisher not instrumented manually | ||
|
||
`publisher_uninstrumented.py` | ||
|
||
```python | ||
@app.route("/publish_request") | ||
def publish_request(): | ||
hello_str = request.args.get("helloStr") | ||
print(hello_str) | ||
return "published" | ||
``` | ||
|
||
# Preparation | ||
|
||
This example will be executed in a separate virtual environment: | ||
|
||
```sh | ||
$ mkdir auto_instrumentation | ||
$ virtualenv auto_instrumentation | ||
$ source auto_instrumentation/bin/activate | ||
``` | ||
|
||
# Installation | ||
|
||
```sh | ||
$ git clone [email protected]:open-telemetry/opentelemetry-python.git | ||
$ cd opentelemetry-python | ||
$ pip3 install -e opentelemetry-api | ||
$ pip3 install -e opentelemetry-sdk | ||
$ pip3 install -e opentelemetry-auto-instrumentation | ||
$ pip3 install -e ext/opentelemetry-ext-flask | ||
$ pip3 install flask | ||
$ pip3 install requests | ||
``` | ||
|
||
# Execution | ||
|
||
## Execution of the manually instrumented publisher | ||
|
||
This is done in 3 separate consoles, one to run each of the scripts that make up this example: | ||
|
||
```sh | ||
$ source auto_instrumentation/bin/activate | ||
$ python3 opentelemetry-python/examples/auto_instrumentation/formatter.py | ||
``` | ||
|
||
```sh | ||
$ source auto_instrumentation/bin/activate | ||
$ python3 opentelemetry-python/examples/auto_instrumentation/publisher_instrumented.py | ||
``` | ||
|
||
```sh | ||
$ source auto_instrumentation/bin/activate | ||
$ python3 opentelemetry-python/examples/auto_instrumentation/hello.py testing | ||
``` | ||
|
||
The execution of `publisher_instrumented.py` should return an output similar to: | ||
|
||
```sh | ||
Hello, testing! | ||
Span(name="publish", context=SpanContext(trace_id=0xd18be4c644d3be57a8623bbdbdbcef76, span_id=0x6162c475bab8d365, trace_state={}), kind=SpanKind.SERVER, parent=SpanContext(trace_id=0xd18be4c644d3be57a8623bbdbdbcef76, span_id=0xdafb264c5b1b6ed0, trace_state={}), start_time=2019-12-19T01:11:12.172866Z, end_time=2019-12-19T01:11:12.173383Z) | ||
127.0.0.1 - - [18/Dec/2019 19:11:12] "GET /publish?helloStr=Hello%2C+testing%21 HTTP/1.1" 200 - | ||
``` | ||
|
||
## Execution of an automatically instrumented publisher | ||
|
||
Now, kill the execution of `publisher_instrumented.py` with `ctrl + c` and run this instead: | ||
|
||
```sh | ||
$ opentelemetry-auto-instrumentation opentelemetry-python/examples/auto_instrumentation/publisher_uninstrumented.py | ||
``` | ||
|
||
In the console where you previously executed `hello.py`, run again this again: | ||
|
||
```sh | ||
$ python3 opentelemetry-python/examples/auto_instrumentation/hello.py testing | ||
``` | ||
|
||
The execution of `publisher_uninstrumented.py` should return an output similar to: | ||
|
||
```sh | ||
Hello, testing! | ||
Span(name="publish", context=SpanContext(trace_id=0xd18be4c644d3be57a8623bbdbdbcef76, span_id=0x6162c475bab8d365, trace_state={}), kind=SpanKind.SERVER, parent=SpanContext(trace_id=0xd18be4c644d3be57a8623bbdbdbcef76, span_id=0xdafb264c5b1b6ed0, trace_state={}), start_time=2019-12-19T01:11:12.172866Z, end_time=2019-12-19T01:11:12.173383Z) | ||
127.0.0.1 - - [18/Dec/2019 19:11:12] "GET /publish?helloStr=Hello%2C+testing%21 HTTP/1.1" 200 - | ||
``` | ||
|
||
As you can see, both outputs are equal since the automatic instrumentation does what the manual instrumentation does too. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from flask import Flask, request | ||
|
||
from opentelemetry import propagators, trace | ||
from opentelemetry.context.propagation.tracecontexthttptextformat import ( | ||
TraceContextHTTPTextFormat, | ||
) | ||
from opentelemetry.propagators import set_global_httptextformat | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import ( | ||
ConsoleSpanExporter, | ||
SimpleExportSpanProcessor, | ||
) | ||
from utils import get_as_list | ||
|
||
app = Flask(__name__) | ||
|
||
trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) | ||
tracer = trace.tracer_provider().get_tracer(__name__) | ||
|
||
trace.tracer_provider().add_span_processor( | ||
SimpleExportSpanProcessor(ConsoleSpanExporter()) | ||
) | ||
set_global_httptextformat(TraceContextHTTPTextFormat) | ||
|
||
|
||
@app.route("/format_request") | ||
def format_request(): | ||
|
||
with tracer.start_as_current_span( | ||
"format_request", | ||
parent=propagators.extract(get_as_list, request.headers), | ||
): | ||
hello_to = request.args.get("helloTo") | ||
return "Hello, %s!" % hello_to | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run(port=8081) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from sys import argv | ||
|
||
from flask import Flask | ||
from requests import get | ||
|
||
from opentelemetry import propagators, trace | ||
from opentelemetry.context.propagation.tracecontexthttptextformat import ( | ||
TraceContextHTTPTextFormat, | ||
) | ||
from opentelemetry.propagators import set_global_httptextformat | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import ( | ||
ConsoleSpanExporter, | ||
SimpleExportSpanProcessor, | ||
) | ||
|
||
app = Flask(__name__) | ||
|
||
trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) | ||
tracer = trace.tracer_provider().get_tracer(__name__) | ||
|
||
trace.tracer_provider().add_span_processor( | ||
SimpleExportSpanProcessor(ConsoleSpanExporter()) | ||
) | ||
set_global_httptextformat(TraceContextHTTPTextFormat) | ||
|
||
|
||
def http_get(port, path, param, value): | ||
|
||
headers = {} | ||
propagators.inject(tracer, dict.__setitem__, headers) | ||
|
||
requested = get( | ||
"http://localhost:{}/{}".format(port, path), | ||
params={param: value}, | ||
headers=headers, | ||
) | ||
|
||
assert requested.status_code == 200 | ||
return requested.text | ||
|
||
|
||
assert len(argv) == 2 | ||
|
||
hello_to = argv[1] | ||
|
||
with tracer.start_as_current_span("hello") as hello_span: | ||
|
||
with tracer.start_as_current_span("hello-format", parent=hello_span): | ||
hello_str = http_get(8081, "format_request", "helloTo", hello_to) | ||
|
||
with tracer.start_as_current_span("hello-publish", parent=hello_span): | ||
http_get(8082, "publish_request", "helloStr", hello_str) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from flask import Flask, request | ||
|
||
from opentelemetry import propagators, trace | ||
from opentelemetry.context.propagation.tracecontexthttptextformat import ( | ||
TraceContextHTTPTextFormat, | ||
) | ||
from opentelemetry.propagators import set_global_httptextformat | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import ( | ||
ConsoleSpanExporter, | ||
SimpleExportSpanProcessor, | ||
) | ||
from utils import get_as_list | ||
|
||
app = Flask(__name__) | ||
|
||
trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) | ||
tracer = trace.tracer_provider().get_tracer(__name__) | ||
|
||
trace.tracer_provider().add_span_processor( | ||
SimpleExportSpanProcessor(ConsoleSpanExporter()) | ||
) | ||
set_global_httptextformat(TraceContextHTTPTextFormat) | ||
|
||
|
||
@app.route("/publish_request") | ||
def publish_request(): | ||
|
||
with tracer.start_as_current_span( | ||
"publish_request", propagators.extract(get_as_list, request.headers) | ||
): | ||
hello_str = request.args.get("helloStr") | ||
print(hello_str) | ||
return "published" | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run(port=8082) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from flask import Flask, request | ||
|
||
from opentelemetry import trace | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import ( | ||
ConsoleSpanExporter, | ||
SimpleExportSpanProcessor, | ||
) | ||
|
||
app = Flask(__name__) | ||
|
||
trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) | ||
|
||
trace.tracer_provider().add_span_processor( | ||
SimpleExportSpanProcessor(ConsoleSpanExporter()) | ||
) | ||
|
||
|
||
@app.route("/publish_request") | ||
def publish_request(): | ||
hello_str = request.args.get("helloStr") | ||
print(hello_str) | ||
return "published" | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run(port=8082) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
|
||
def get_as_list(dict_object, key): | ||
value = dict_object.get(key) | ||
return value if value is not None else [] | ||
|
||
|
||
__all__ = ["get_as_list"] |
Oops, something went wrong.