Start application
DD_API_KEY=... docker-compose up --build appTest application traces To
ab -c 10 -n 200 http://127.0.0.1:8080/| from flask import Flask | |
| import concurrent.futures | |
| import urllib.request | |
| URLS = ['https://httpbin.org/bytes/1024', | |
| 'https://httpbin.org/bytes/4096'] | |
| # Retrieve a single page and report the URL and contents | |
| def load_url(url, timeout): | |
| with urllib.request.urlopen(url, timeout=timeout) as conn: | |
| return conn.read() | |
| def use_futures(): | |
| # We can use a with statement to ensure threads are cleaned up promptly | |
| with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: | |
| # Start the load operations and mark each future with its URL | |
| future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} | |
| for future in concurrent.futures.as_completed(future_to_url): | |
| url = future_to_url[future] | |
| try: | |
| data = future.result() | |
| except Exception as exc: | |
| print('{} generated an exception: {}\n'.format(url, exc)) | |
| else: | |
| print('{} page is {} bytes\n'.format(url, len(data))) | |
| def no_futures(): | |
| for url in URLS: | |
| print('No future', load_url(url, 60)) | |
| app = Flask(__name__) | |
| @app.route("/") | |
| def hello(): | |
| use_futures() | |
| # no_futures() | |
| return u'Hello!' | |
| if __name__ == "__main__": | |
| app.run() |
| version: '3' | |
| services: | |
| app: | |
| build: . | |
| depends_on: | |
| - agent | |
| environment: | |
| - 'DATADOG_TRACE_ENABLED=true' | |
| - 'DATADOG_TRACE_AGENT_HOSTNAME=agent' | |
| - 'DATADOG_PATCH_MODULES=futures:true,gevent:true' | |
| ports: | |
| - '8080:8080' | |
| agent: | |
| image: 'datadog/docker-dd-agent' | |
| environment: | |
| - 'DD_APM_ENABLED=true' | |
| - 'DD_HOSTNAME=multiple-traces' | |
| - 'DD_TAGS=env:dev' | |
| - 'DD_API_KEY=${DD_API_KEY}' | |
| ports: | |
| - 8125 | |
| - 8126 | |
| volumes: | |
| - '/var/run/docker.sock:/var/run/docker.sock:ro' | |
| - '/proc/:/host/proc/:ro' | |
| - '/sys/fs/cgroup/:/host/sys/fs/cgroup:ro' |
| FROM ubuntu:trusty | |
| WORKDIR /opt/code | |
| ENV PYENV_ROOT="/opt/pyenv" \ | |
| PATH="/opt/pyenv/bin:/opt/pyenv/shims:$PATH" \ | |
| LC_ALL="C.UTF-8" \ | |
| LANG="C.UTF-8" | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| build-essential \ | |
| ca-certificates \ | |
| curl \ | |
| git \ | |
| libbz2-dev \ | |
| libffi-dev \ | |
| libncurses5-dev \ | |
| libncursesw5-dev \ | |
| libreadline-dev \ | |
| libsqlite3-dev \ | |
| libssl-dev \ | |
| llvm \ | |
| make \ | |
| netbase \ | |
| pkg-config \ | |
| tk-dev \ | |
| wget \ | |
| xz-utils \ | |
| zlib1g-dev \ | |
| && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* | |
| RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash \ | |
| && pyenv install 3.6.7 \ | |
| && pyenv global 3.6.7 | |
| COPY requirements.txt . | |
| RUN pip install -r requirements.txt | |
| COPY app.py . | |
| COPY Gunicorn . | |
| COPY gunicorn.ini . | |
| EXPOSE 8080 | |
| ENV DATADOG_TRACE_DEBUG true | |
| # CMD ["ddtrace-run", "python", "Gunicorn"] | |
| CMD ["ddtrace-run", "gunicorn", "--log-level", "debug", "-c", "gunicorn.ini", "app:app"] |
| from gunicorn.app.base import Application | |
| from gunicorn import util | |
| from os import getenv | |
| GUNICORN_CONFIG = { | |
| 'bind': '0.0.0.0:8080', | |
| 'workers': 1, | |
| 'worker-class': 'gevent', | |
| 'threads': 8, | |
| 'timeout': 120, | |
| 'sendfile': False, # since it's disabled in Nginx by default | |
| } | |
| class GunicornApp(Application): | |
| def __init__(self, options=None): | |
| self.options = options or {} | |
| self.usage = None | |
| self.callable = None | |
| super().__init__() | |
| self.do_load_config() | |
| def init(self, *args): | |
| cfg = {} | |
| for k, v in self.options.items(): | |
| if k.lower() in self.cfg.settings and v is not None: | |
| cfg[k.lower()] = v | |
| return cfg | |
| def load(self): | |
| return util.import_app("app:app") | |
| if __name__ == '__main__': | |
| options = GUNICORN_CONFIG | |
| if getenv('DEBUG') is not None: | |
| options['reload'] = True | |
| GunicornApp(options).run() |
| bind = '0.0.0.0:8080' | |
| workers = 1 | |
| worker_class = 'gevent' | |
| threads = 8 | |
| timeout = 120 | |
| sendfile = False # since it's disabled in Nginx by default |
| bind = "0.0.0.0:8080" | |
| workers = 1 | |
| worker_class = "gevent" | |
| threads = 8 | |
| timeout = 120 | |
| sendfile = False |
| ddtrace==0.17.0 | |
| Flask==0.12 | |
| future==0.17.1 | |
| gevent==1.2.2 | |
| gunicorn==19.7.1 |