Skip to content

Commit 5dde4a4

Browse files
mrnicegyu11GitHKAndrei Neaguodeimaizsanderegg
authored
🐛 Fix aiohttp server autoinstrumentation (ITISFoundation#6391)
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Dustin Kaiser <[email protected]> Co-authored-by: Andrei Neagu <[email protected]> Co-authored-by: Andrei Neagu <[email protected]> Co-authored-by: Odei Maiz <[email protected]> Co-authored-by: Sylvain <[email protected]> Co-authored-by: Pedro Crespo-Valero <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: matusdrobuliak66 <[email protected]> Co-authored-by: Julian Querido <[email protected]> Co-authored-by: Odei Maiz <[email protected]>
1 parent ad0a35d commit 5dde4a4

File tree

5 files changed

+206
-149
lines changed

5 files changed

+206
-149
lines changed

packages/service-library/src/servicelib/aiohttp/tracing.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from opentelemetry.instrumentation.aiohttp_client import ( # pylint:disable=no-name-in-module
1313
AioHttpClientInstrumentor,
1414
)
15-
from opentelemetry.instrumentation.aiohttp_server import ( # pylint:disable=no-name-in-module
16-
AioHttpServerInstrumentor,
15+
from opentelemetry.instrumentation.aiohttp_server import (
16+
middleware as aiohttp_server_opentelemetry_middleware, # pylint:disable=no-name-in-module
1717
)
1818
from opentelemetry.instrumentation.aiopg import ( # pylint:disable=no-name-in-module
1919
AiopgInstrumentor,
@@ -72,8 +72,24 @@ def setup_tracing(
7272

7373
# Add the span processor to the tracer provider
7474
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter)) # type: ignore[attr-defined] # https://github.com/open-telemetry/opentelemetry-python/issues/3713
75-
# Instrument aiohttp server and client
76-
AioHttpServerInstrumentor().instrument()
75+
# Instrument aiohttp server
76+
# Explanation for custom middleware call DK 10/2024:
77+
# OpenTelemetry Aiohttp autoinstrumentation is meant to be used by only calling `AioHttpServerInstrumentor().instrument()`
78+
# The call `AioHttpServerInstrumentor().instrument()` monkeypatches the __init__() of aiohttp's web.application() to inject the tracing middleware, in it's `__init__()`.
79+
# In simcore, we want to switch tracing on or off using the simcore-settings-library.
80+
# The simcore-settings library in turn depends on the instance of web.application(), i.e. the aiohttp webserver, to exist. So here we face a hen-and-egg problem.
81+
# At the time when the instrumentation should be configured, the instance of web.application already exists and the overwrite to the __init__() is never called
82+
#
83+
# Since the code that is provided (monkeypatched) in the __init__ that the opentelemetry-autoinstrumentation-library provides is only 4 lines,
84+
# just adding a middleware, we are free to simply execute this "missed call" [since we can't call the monkeypatch'ed __init__()] in this following line:
85+
app.middlewares.insert(0, aiohttp_server_opentelemetry_middleware)
86+
# Code of the aiohttp server instrumentation: github.com/open-telemetry/opentelemetry-python-contrib/blob/eccb05c808a7d797ef5b6ecefed3590664426fbf/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py#L246
87+
# For reference, the above statement was written for:
88+
# - osparc-simcore 1.77.x
89+
# - opentelemetry-api==1.27.0
90+
# - opentelemetry-instrumentation==0.48b0
91+
92+
# Instrument aiohttp client
7793
AioHttpClientInstrumentor().instrument()
7894
if instrument_aiopg:
7995
AiopgInstrumentor().instrument()

services/datcore-adapter/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ FROM python:${PYTHON_VERSION}-slim-bookworm as base
44

55
#
66
# USAGE:
7-
# cd sercices/datcore-adapter
7+
# cd services/datcore-adapter
88
# docker build -f Dockerfile -t datcore-adapter:prod --target production ../../
99
# docker run datcore-adapter:prod
1010
#

services/web/server/tests/unit/isolated/conftest.py

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
from faker import Faker
88
from pytest_mock import MockerFixture
99
from pytest_simcore.helpers.dict_tools import ConfigDict
10-
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
10+
from pytest_simcore.helpers.monkeypatch_envs import (
11+
setenvs_from_dict,
12+
setenvs_from_envfile,
13+
)
1114
from pytest_simcore.helpers.typing_env import EnvVarsDict
1215

1316

@@ -89,6 +92,145 @@ def mock_env_deployer_pipeline(monkeypatch: pytest.MonkeyPatch) -> EnvVarsDict:
8992
)
9093

9194

95+
@pytest.fixture
96+
def mock_env_devel_environment(
97+
mock_env_devel_environment: EnvVarsDict, # pylint: disable=redefined-outer-name
98+
monkeypatch: pytest.MonkeyPatch,
99+
) -> EnvVarsDict:
100+
# Overrides to ensure dev-features are enabled testings
101+
return mock_env_devel_environment | setenvs_from_dict(
102+
monkeypatch,
103+
envs={
104+
"WEBSERVER_DEV_FEATURES_ENABLED": "1",
105+
},
106+
)
107+
108+
109+
@pytest.fixture
110+
def mock_env_makefile(monkeypatch: pytest.MonkeyPatch) -> EnvVarsDict:
111+
"""envvars produced @Makefile (export)"""
112+
# TODO: add Makefile recipe 'make dump-envs' to produce the file we load here
113+
return setenvs_from_dict(
114+
monkeypatch,
115+
{
116+
"API_SERVER_API_VERSION": "0.3.0",
117+
"BUILD_DATE": "2022-01-14T21:28:15Z",
118+
"CATALOG_API_VERSION": "0.3.2",
119+
"CLIENT_WEB_OUTPUT": "/home/crespo/devp/osparc-simcore/services/static-webserver/client/source-output",
120+
"DATCORE_ADAPTER_API_VERSION": "0.1.0-alpha",
121+
"DIRECTOR_API_VERSION": "0.1.0",
122+
"DIRECTOR_V2_API_VERSION": "2.0.0",
123+
"DOCKER_IMAGE_TAG": "production",
124+
"DOCKER_REGISTRY": "local",
125+
"S3_ENDPOINT": "http://127.0.0.1:9001",
126+
"STORAGE_API_VERSION": "0.2.1",
127+
"SWARM_HOSTS": "",
128+
"SWARM_STACK_NAME": "master-simcore",
129+
"SWARM_STACK_NAME_NO_HYPHEN": "master_simcore",
130+
"VCS_REF_CLIENT": "99b8022d2",
131+
"VCS_STATUS_CLIENT": "'modified/untracked'",
132+
"VCS_URL": "[email protected]:pcrespov/osparc-simcore.git",
133+
"WEBSERVER_API_VERSION": "0.7.0",
134+
},
135+
)
136+
137+
138+
@pytest.fixture
139+
def mock_env_dockerfile_build(monkeypatch: pytest.MonkeyPatch) -> EnvVarsDict:
140+
#
141+
# docker run -it --hostname "{{.Node.Hostname}}-{{.Service.Name}}-{{.Task.Slot}}" local/webserver:production printenv
142+
#
143+
return setenvs_from_envfile(
144+
monkeypatch,
145+
"""\
146+
GPG_KEY=123456789123456789
147+
HOME=/home/scu
148+
HOSTNAME=osparc-master-55-master-simcore_master_webserver-1
149+
IS_CONTAINER_CONTEXT=Yes
150+
LANG=C.UTF-8
151+
PATH=/home/scu/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
152+
PWD=/home/scu
153+
PYTHON_GET_PIP_SHA256=6123659241292b2147b58922b9ffe11dda66b39d52d8a6f3aa310bc1d60ea6f7
154+
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/a1675ab6c2bd898ed82b1f58c486097f763c74a9/public/get-pip.py
155+
PYTHON_PIP_VERSION=21.1.3
156+
PYTHON_VERSION=3.11.9
157+
PYTHONDONTWRITEBYTECODE=1
158+
PYTHONOPTIMIZE=TRUE
159+
SC_BOOT_MODE=production
160+
SC_BUILD_DATE=2022-01-09T12:26:29Z
161+
SC_BUILD_TARGET=production
162+
SC_HEALTHCHECK_INTERVAL=30
163+
SC_HEALTHCHECK_RETRY=3
164+
SC_USER_ID=8004
165+
SC_USER_NAME=scu
166+
SC_VCS_REF=dd536f998
167+
[email protected]:ITISFoundation/osparc-simcore.git
168+
TERM=xterm
169+
VIRTUAL_ENV=/home/scu/.venv
170+
""",
171+
)
172+
173+
174+
@pytest.fixture
175+
def mock_webserver_service_environment(
176+
monkeypatch: pytest.MonkeyPatch,
177+
mock_env_makefile: EnvVarsDict, # pylint: disable=redefined-outer-name
178+
mock_env_devel_environment: EnvVarsDict, # pylint: disable=redefined-outer-name
179+
mock_env_dockerfile_build: EnvVarsDict, # pylint: disable=redefined-outer-name
180+
mock_env_deployer_pipeline: EnvVarsDict, # pylint: disable=redefined-outer-name
181+
) -> EnvVarsDict:
182+
"""
183+
Mocks environment produce in the docker compose config with a .env (.env-devel)
184+
and launched with a makefile
185+
"""
186+
# @docker compose config (overrides)
187+
# TODO: get from docker compose config
188+
# r'- ([A-Z2_]+)=\$\{\1:-([\w-]+)\}'
189+
190+
# - .env-devel + docker-compose service environs
191+
# hostname: "{{.Node.Hostname}}-{{.Service.Name}}-{{.Task.Slot}}"
192+
193+
# environment:
194+
# - CATALOG_HOST=${CATALOG_HOST:-catalog}
195+
# - CATALOG_PORT=${CATALOG_PORT:-8000}
196+
# - DIAGNOSTICS_MAX_AVG_LATENCY=10
197+
# - DIAGNOSTICS_MAX_TASK_DELAY=30
198+
# - DIRECTOR_PORT=${DIRECTOR_PORT:-8080}
199+
# - DIRECTOR_V2_HOST=${DIRECTOR_V2_HOST:-director-v2}
200+
# - DIRECTOR_V2_PORT=${DIRECTOR_V2_PORT:-8000}
201+
# - STORAGE_HOST=${STORAGE_HOST:-storage}
202+
# - STORAGE_PORT=${STORAGE_PORT:-8080}
203+
# - SWARM_STACK_NAME=${SWARM_STACK_NAME:-simcore}
204+
# - WEBSERVER_LOGLEVEL=${LOG_LEVEL:-WARNING}
205+
# env_file:
206+
# - ../.env
207+
mock_envs_docker_compose_environment = setenvs_from_dict(
208+
monkeypatch,
209+
{
210+
# Emulates MYVAR=${MYVAR:-default}
211+
"CATALOG_HOST": os.environ.get("CATALOG_HOST", "catalog"),
212+
"CATALOG_PORT": os.environ.get("CATALOG_PORT", "8000"),
213+
"DIAGNOSTICS_MAX_AVG_LATENCY": "30",
214+
"DIRECTOR_PORT": os.environ.get("DIRECTOR_PORT", "8080"),
215+
"DIRECTOR_V2_HOST": os.environ.get("DIRECTOR_V2_HOST", "director-v2"),
216+
"DIRECTOR_V2_PORT": os.environ.get("DIRECTOR_V2_PORT", "8000"),
217+
"STORAGE_HOST": os.environ.get("STORAGE_HOST", "storage"),
218+
"STORAGE_PORT": os.environ.get("STORAGE_PORT", "8080"),
219+
"SWARM_STACK_NAME": os.environ.get("SWARM_STACK_NAME", "simcore"),
220+
"WEBSERVER_LOGLEVEL": os.environ.get("LOG_LEVEL", "WARNING"),
221+
"SESSION_COOKIE_MAX_AGE": str(7 * 24 * 60 * 60),
222+
},
223+
)
224+
225+
return (
226+
mock_env_makefile
227+
| mock_env_devel_environment
228+
| mock_env_dockerfile_build
229+
| mock_env_deployer_pipeline
230+
| mock_envs_docker_compose_environment
231+
)
232+
233+
92234
@pytest.fixture
93235
def mocked_login_required(mocker: MockerFixture):
94236

services/web/server/tests/unit/isolated/test_application_settings.py

Lines changed: 0 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,11 @@
33
# pylint:disable=no-name-in-module
44

55
import json
6-
import os
76

87
import pytest
98
from aiohttp import web
109
from models_library.utils.json_serialization import json_dumps
1110
from pydantic import HttpUrl, parse_obj_as
12-
from pytest_simcore.helpers.monkeypatch_envs import (
13-
setenvs_from_dict,
14-
setenvs_from_envfile,
15-
)
1611
from pytest_simcore.helpers.typing_env import EnvVarsDict
1712
from simcore_service_webserver.application_settings import (
1813
APP_SETTINGS_KEY,
@@ -21,144 +16,6 @@
2116
)
2217

2318

24-
@pytest.fixture
25-
def mock_env_devel_environment(
26-
mock_env_devel_environment: EnvVarsDict, monkeypatch: pytest.MonkeyPatch
27-
) -> EnvVarsDict:
28-
# Overrides to ensure dev-features are enabled testings
29-
return mock_env_devel_environment | setenvs_from_dict(
30-
monkeypatch,
31-
envs={
32-
"WEBSERVER_DEV_FEATURES_ENABLED": "1",
33-
},
34-
)
35-
36-
37-
@pytest.fixture
38-
def mock_env_makefile(monkeypatch: pytest.MonkeyPatch) -> EnvVarsDict:
39-
"""envvars produced @Makefile (export)"""
40-
# TODO: add Makefile recipe 'make dump-envs' to produce the file we load here
41-
return setenvs_from_dict(
42-
monkeypatch,
43-
{
44-
"API_SERVER_API_VERSION": "0.3.0",
45-
"BUILD_DATE": "2022-01-14T21:28:15Z",
46-
"CATALOG_API_VERSION": "0.3.2",
47-
"CLIENT_WEB_OUTPUT": "/home/crespo/devp/osparc-simcore/services/static-webserver/client/source-output",
48-
"DATCORE_ADAPTER_API_VERSION": "0.1.0-alpha",
49-
"DIRECTOR_API_VERSION": "0.1.0",
50-
"DIRECTOR_V2_API_VERSION": "2.0.0",
51-
"DOCKER_IMAGE_TAG": "production",
52-
"DOCKER_REGISTRY": "local",
53-
"S3_ENDPOINT": "http://127.0.0.1:9001",
54-
"STORAGE_API_VERSION": "0.2.1",
55-
"SWARM_HOSTS": "",
56-
"SWARM_STACK_NAME": "master-simcore",
57-
"SWARM_STACK_NAME_NO_HYPHEN": "master_simcore",
58-
"VCS_REF_CLIENT": "99b8022d2",
59-
"VCS_STATUS_CLIENT": "'modified/untracked'",
60-
"VCS_URL": "[email protected]:pcrespov/osparc-simcore.git",
61-
"WEBSERVER_API_VERSION": "0.7.0",
62-
},
63-
)
64-
65-
66-
@pytest.fixture
67-
def mock_env_dockerfile_build(monkeypatch: pytest.MonkeyPatch) -> EnvVarsDict:
68-
#
69-
# docker run -it --hostname "{{.Node.Hostname}}-{{.Service.Name}}-{{.Task.Slot}}" local/webserver:production printenv
70-
#
71-
return setenvs_from_envfile(
72-
monkeypatch,
73-
"""\
74-
GPG_KEY=123456789123456789
75-
HOME=/home/scu
76-
HOSTNAME=osparc-master-55-master-simcore_master_webserver-1
77-
IS_CONTAINER_CONTEXT=Yes
78-
LANG=C.UTF-8
79-
PATH=/home/scu/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
80-
PWD=/home/scu
81-
PYTHON_GET_PIP_SHA256=6123659241292b2147b58922b9ffe11dda66b39d52d8a6f3aa310bc1d60ea6f7
82-
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/a1675ab6c2bd898ed82b1f58c486097f763c74a9/public/get-pip.py
83-
PYTHON_PIP_VERSION=21.1.3
84-
PYTHON_VERSION=3.11.9
85-
PYTHONDONTWRITEBYTECODE=1
86-
PYTHONOPTIMIZE=TRUE
87-
SC_BOOT_MODE=production
88-
SC_BUILD_DATE=2022-01-09T12:26:29Z
89-
SC_BUILD_TARGET=production
90-
SC_HEALTHCHECK_INTERVAL=30
91-
SC_HEALTHCHECK_RETRY=3
92-
SC_USER_ID=8004
93-
SC_USER_NAME=scu
94-
SC_VCS_REF=dd536f998
95-
[email protected]:ITISFoundation/osparc-simcore.git
96-
TERM=xterm
97-
VIRTUAL_ENV=/home/scu/.venv
98-
""",
99-
)
100-
101-
102-
@pytest.fixture
103-
def mock_webserver_service_environment(
104-
monkeypatch: pytest.MonkeyPatch,
105-
mock_env_makefile: EnvVarsDict,
106-
mock_env_devel_environment: EnvVarsDict,
107-
mock_env_dockerfile_build: EnvVarsDict,
108-
mock_env_deployer_pipeline: EnvVarsDict,
109-
) -> EnvVarsDict:
110-
"""
111-
Mocks environment produce in the docker compose config with a .env (.env-devel)
112-
and launched with a makefile
113-
"""
114-
# @docker compose config (overrides)
115-
# TODO: get from docker compose config
116-
# r'- ([A-Z2_]+)=\$\{\1:-([\w-]+)\}'
117-
118-
# - .env-devel + docker-compose service environs
119-
# hostname: "{{.Node.Hostname}}-{{.Service.Name}}-{{.Task.Slot}}"
120-
121-
# environment:
122-
# - CATALOG_HOST=${CATALOG_HOST:-catalog}
123-
# - CATALOG_PORT=${CATALOG_PORT:-8000}
124-
# - DIAGNOSTICS_MAX_AVG_LATENCY=10
125-
# - DIAGNOSTICS_MAX_TASK_DELAY=30
126-
# - DIRECTOR_PORT=${DIRECTOR_PORT:-8080}
127-
# - DIRECTOR_V2_HOST=${DIRECTOR_V2_HOST:-director-v2}
128-
# - DIRECTOR_V2_PORT=${DIRECTOR_V2_PORT:-8000}
129-
# - STORAGE_HOST=${STORAGE_HOST:-storage}
130-
# - STORAGE_PORT=${STORAGE_PORT:-8080}
131-
# - SWARM_STACK_NAME=${SWARM_STACK_NAME:-simcore}
132-
# - WEBSERVER_LOGLEVEL=${LOG_LEVEL:-WARNING}
133-
# env_file:
134-
# - ../.env
135-
mock_envs_docker_compose_environment = setenvs_from_dict(
136-
monkeypatch,
137-
{
138-
# Emulates MYVAR=${MYVAR:-default}
139-
"CATALOG_HOST": os.environ.get("CATALOG_HOST", "catalog"),
140-
"CATALOG_PORT": os.environ.get("CATALOG_PORT", "8000"),
141-
"DIAGNOSTICS_MAX_AVG_LATENCY": "30",
142-
"DIRECTOR_PORT": os.environ.get("DIRECTOR_PORT", "8080"),
143-
"DIRECTOR_V2_HOST": os.environ.get("DIRECTOR_V2_HOST", "director-v2"),
144-
"DIRECTOR_V2_PORT": os.environ.get("DIRECTOR_V2_PORT", "8000"),
145-
"STORAGE_HOST": os.environ.get("STORAGE_HOST", "storage"),
146-
"STORAGE_PORT": os.environ.get("STORAGE_PORT", "8080"),
147-
"SWARM_STACK_NAME": os.environ.get("SWARM_STACK_NAME", "simcore"),
148-
"WEBSERVER_LOGLEVEL": os.environ.get("LOG_LEVEL", "WARNING"),
149-
"SESSION_COOKIE_MAX_AGE": str(7 * 24 * 60 * 60),
150-
},
151-
)
152-
153-
return (
154-
mock_env_makefile
155-
| mock_env_devel_environment
156-
| mock_env_dockerfile_build
157-
| mock_env_deployer_pipeline
158-
| mock_envs_docker_compose_environment
159-
)
160-
161-
16219
@pytest.fixture
16320
def app_settings(
16421
mock_webserver_service_environment: EnvVarsDict,

0 commit comments

Comments
 (0)