-
Notifications
You must be signed in to change notification settings - Fork 649
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Document how to work with fork process web server models(Gunicorn, uW…
…SGI etc...) (#1609)
- Loading branch information
1 parent
6f42def
commit c387aa3
Showing
10 changed files
with
321 additions
and
2 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,66 @@ | ||
Working With Fork Process Models | ||
================================ | ||
|
||
The `BatchSpanProcessor` is not fork-safe and doesn't work well with application servers | ||
(Gunicorn, uWSGI) which are based on the pre-fork web server model. The `BatchSpanProcessor` | ||
spawns a thread to run in the background to export spans to the telemetry backend. During the fork, the child | ||
process inherits the lock which is held by the parent process and deadlock occurs. We can use fork hooks to | ||
get around this limitation of the span processor. | ||
|
||
Please see http://bugs.python.org/issue6721 for the problems about Python locks in (multi)threaded | ||
context with fork. | ||
|
||
Gunicorn post_fork hook | ||
----------------------- | ||
|
||
.. code-block:: python | ||
from opentelemetry import trace | ||
from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter | ||
from opentelemetry.sdk.resources import Resource | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
def post_fork(server, worker): | ||
server.log.info("Worker spawned (pid: %s)", worker.pid) | ||
resource = Resource.create(attributes={ | ||
"service.name": "api-service" | ||
}) | ||
trace.set_tracer_provider(TracerProvider(resource=resource)) | ||
span_processor = BatchSpanProcessor( | ||
OTLPSpanExporter(endpoint="localhost:4317") | ||
) | ||
trace.get_tracer_provider().add_span_processor(span_processor) | ||
uWSGI postfork decorator | ||
------------------------ | ||
|
||
.. code-block:: python | ||
from uwsgidecorators import postfork | ||
from opentelemetry import trace | ||
from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter | ||
from opentelemetry.sdk.resources import Resource | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
@postfork | ||
def init_tracing(): | ||
resource = Resource.create(attributes={ | ||
"service.name": "api-service" | ||
}) | ||
trace.set_tracer_provider(TracerProvider(resource=resource)) | ||
span_processor = BatchSpanProcessor( | ||
OTLPSpanExporter(endpoint="localhost:4317") | ||
) | ||
trace.get_tracer_provider().add_span_processor(span_processor) | ||
The source code for the examples with Flask app are available :scm_web:`here <docs/examples/fork-process-model/>`. |
11 changes: 11 additions & 0 deletions
11
docs/examples/fork-process-model/flask-gunicorn/README.rst
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,11 @@ | ||
Installation | ||
------------ | ||
.. code-block:: sh | ||
pip install -rrequirements.txt | ||
Run application | ||
--------------- | ||
.. code-block:: sh | ||
gunicorn app -c gunicorn.config.py |
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,58 @@ | ||
# Copyright The 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. | ||
|
||
import flask | ||
from flask import request | ||
|
||
from opentelemetry import trace | ||
from opentelemetry.instrumentation.flask import FlaskInstrumentor | ||
|
||
application = flask.Flask(__name__) | ||
|
||
FlaskInstrumentor().instrument_app(application) | ||
|
||
|
||
def fib_slow(n): | ||
if n <= 1: | ||
return n | ||
return fib_slow(n - 1) + fib_fast(n - 2) | ||
|
||
|
||
def fib_fast(n): | ||
nth_fib = [0] * (n + 2) | ||
nth_fib[1] = 1 | ||
for i in range(2, n + 1): | ||
nth_fib[i] = nth_fib[i - 1] + nth_fib[i - 2] | ||
return nth_fib[n] | ||
|
||
|
||
@application.route("/fibonacci") | ||
def fibonacci(): | ||
tracer = trace.get_tracer(__name__) | ||
n = int(request.args.get("n", 1)) | ||
with tracer.start_as_current_span("root"): | ||
with tracer.start_as_current_span("fib_slow") as slow_span: | ||
ans = fib_slow(n) | ||
slow_span.set_attribute("n", n) | ||
slow_span.set_attribute("nth_fibonacci", ans) | ||
with tracer.start_as_current_span("fib_fast") as fast_span: | ||
ans = fib_fast(n) | ||
fast_span.set_attribute("n", n) | ||
fast_span.set_attribute("nth_fibonacci", ans) | ||
|
||
return "F({}) is: ({})".format(n, ans) | ||
|
||
|
||
if __name__ == "__main__": | ||
application.run() |
50 changes: 50 additions & 0 deletions
50
docs/examples/fork-process-model/flask-gunicorn/gunicorn.config.py
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,50 @@ | ||
# Copyright The 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 opentelemetry import trace | ||
from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter | ||
from opentelemetry.sdk.resources import Resource | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
||
bind = "127.0.0.1:8000" | ||
|
||
# Sample Worker processes | ||
workers = 4 | ||
worker_class = "sync" | ||
worker_connections = 1000 | ||
timeout = 30 | ||
keepalive = 2 | ||
|
||
# Sample logging | ||
errorlog = "-" | ||
loglevel = "info" | ||
accesslog = "-" | ||
access_log_format = ( | ||
'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' | ||
) | ||
|
||
|
||
def post_fork(server, worker): | ||
server.log.info("Worker spawned (pid: %s)", worker.pid) | ||
|
||
resource = Resource.create(attributes={"service.name": "api-service"}) | ||
|
||
trace.set_tracer_provider(TracerProvider(resource=resource)) | ||
# This uses insecure connection for the purpose of example. Please see the | ||
# OTLP Exporter documentation for other options. | ||
span_processor = BatchSpanProcessor( | ||
OTLPSpanExporter(endpoint="localhost:4317", insecure=True) | ||
) | ||
trace.get_tracer_provider().add_span_processor(span_processor) |
20 changes: 20 additions & 0 deletions
20
docs/examples/fork-process-model/flask-gunicorn/requirements.txt
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,20 @@ | ||
click==7.1.2 | ||
Flask==1.1.2 | ||
googleapis-common-protos==1.52.0 | ||
grpcio==1.35.0 | ||
gunicorn==20.0.4 | ||
itsdangerous==1.1.0 | ||
Jinja2==2.11.3 | ||
MarkupSafe==1.1.1 | ||
opentelemetry-api==0.18b0 | ||
opentelemetry-exporter-otlp==0.18b0 | ||
opentelemetry-instrumentation==0.18b0 | ||
opentelemetry-instrumentation-flask==0.18b1 | ||
opentelemetry-instrumentation-wsgi==0.18b1 | ||
opentelemetry-sdk==0.18b0 | ||
protobuf==3.14.0 | ||
six==1.15.0 | ||
thrift==0.13.0 | ||
uWSGI==2.0.19.1 | ||
Werkzeug==1.0.1 | ||
wrapt==1.12.1 |
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,12 @@ | ||
Installation | ||
------------ | ||
.. code-block:: sh | ||
pip install -rrequirements.txt | ||
Run application | ||
--------------- | ||
|
||
.. code-block:: sh | ||
uwsgi --http :8000 --wsgi-file app.py --callable application --master --enable-threads |
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,76 @@ | ||
# Copyright The 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. | ||
|
||
import flask | ||
from flask import request | ||
from uwsgidecorators import postfork | ||
|
||
from opentelemetry import trace | ||
from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter | ||
from opentelemetry.instrumentation.flask import FlaskInstrumentor | ||
from opentelemetry.sdk.resources import Resource | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
||
application = flask.Flask(__name__) | ||
|
||
FlaskInstrumentor().instrument_app(application) | ||
|
||
|
||
@postfork | ||
def init_tracing(): | ||
resource = Resource.create(attributes={"service.name": "api-service"}) | ||
|
||
trace.set_tracer_provider(TracerProvider(resource=resource)) | ||
# This uses insecure connection for the purpose of example. Please see the | ||
# OTLP Exporter documentation for other options. | ||
span_processor = BatchSpanProcessor( | ||
OTLPSpanExporter(endpoint="localhost:4317", insecure=True) | ||
) | ||
trace.get_tracer_provider().add_span_processor(span_processor) | ||
|
||
|
||
def fib_slow(n): | ||
if n <= 1: | ||
return n | ||
return fib_slow(n - 1) + fib_fast(n - 2) | ||
|
||
|
||
def fib_fast(n): | ||
nth_fib = [0] * (n + 2) | ||
nth_fib[1] = 1 | ||
for i in range(2, n + 1): | ||
nth_fib[i] = nth_fib[i - 1] + nth_fib[i - 2] | ||
return nth_fib[n] | ||
|
||
|
||
@application.route("/fibonacci") | ||
def fibonacci(): | ||
tracer = trace.get_tracer(__name__) | ||
n = int(request.args.get("n", 1)) | ||
with tracer.start_as_current_span("root"): | ||
with tracer.start_as_current_span("fib_slow") as slow_span: | ||
ans = fib_slow(n) | ||
slow_span.set_attribute("n", n) | ||
slow_span.set_attribute("nth_fibonacci", ans) | ||
with tracer.start_as_current_span("fib_fast") as fast_span: | ||
ans = fib_fast(n) | ||
fast_span.set_attribute("n", n) | ||
fast_span.set_attribute("nth_fibonacci", ans) | ||
|
||
return "F({}) is: ({})".format(n, ans) | ||
|
||
|
||
if __name__ == "__main__": | ||
application.run() |
20 changes: 20 additions & 0 deletions
20
docs/examples/fork-process-model/flask-uwsgi/requirements.txt
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,20 @@ | ||
click==7.1.2 | ||
Flask==1.1.2 | ||
googleapis-common-protos==1.52.0 | ||
grpcio==1.35.0 | ||
gunicorn==20.0.4 | ||
itsdangerous==1.1.0 | ||
Jinja2==2.11.3 | ||
MarkupSafe==1.1.1 | ||
opentelemetry-api==0.18b0 | ||
opentelemetry-exporter-otlp==0.18b0 | ||
opentelemetry-instrumentation==0.18b0 | ||
opentelemetry-instrumentation-flask==0.18b1 | ||
opentelemetry-instrumentation-wsgi==0.18b1 | ||
opentelemetry-sdk==0.18b0 | ||
protobuf==3.14.0 | ||
six==1.15.0 | ||
thrift==0.13.0 | ||
uWSGI==2.0.19.1 | ||
Werkzeug==1.0.1 | ||
wrapt==1.12.1 |