Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Commit 64e2d12

Browse files
authored
Appinsights telemetry for aiohttp (#634)
* Initial version of aiohttp telemetry middleware * black: Initial version of aiohttp telemetry middleware * created separate package * pylint: created separate package * black: created separate package * namespace renamed and tests added * testing yaml pipeline * removing pipeline * Update ci-pr-pipeline.yml for Azure Pipelines Updating pipeline for new integration package (appinsights-aiohttp)
1 parent 3fcc356 commit 64e2d12

File tree

9 files changed

+283
-4
lines changed

9 files changed

+283
-4
lines changed

ci-pr-pipeline.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,14 @@ jobs:
4141
pip install -e ./libraries/botbuilder-dialogs
4242
pip install -e ./libraries/botbuilder-azure
4343
pip install -e ./libraries/botbuilder-testing
44+
pip install -e ./libraries/botbuilder-integration-applicationinsights-aiohttp
4445
pip install -r ./libraries/botframework-connector/tests/requirements.txt
4546
pip install -r ./libraries/botbuilder-core/tests/requirements.txt
4647
pip install coveralls
4748
pip install pylint
4849
pip install black
4950
displayName: 'Install dependencies'
5051
51-
- script: 'pip install requests_mock'
52-
displayName: 'Install requests mock (REMOVE AFTER MERGING INSPECTION)'
53-
enabled: false
54-
5552
- script: |
5653
pip install pytest
5754
pip install pytest-cov
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
========================================================
3+
BotBuilder-ApplicationInsights SDK extension for aiohttp
4+
========================================================
5+
6+
.. image:: https://fuselabs.visualstudio.com/SDK_v4/_apis/build/status/Python/SDK_v4-Python-CI?branchName=master
7+
:target: https://fuselabs.visualstudio.com/SDK_v4/_apis/build/status/Python/SDK_v4-Python-CI
8+
:align: right
9+
:alt: Azure DevOps status for master branch
10+
.. image:: https://badge.fury.io/py/botbuilder-applicationinsights.svg
11+
:target: https://badge.fury.io/py/botbuilder-applicationinsights
12+
:alt: Latest PyPI package version
13+
14+
Within the Bot Framework, BotBuilder-ApplicationInsights enables the Azure Application Insights service.
15+
16+
Application Insights is an extensible Application Performance Management (APM) service for developers on multiple platforms.
17+
Use it to monitor your live bot application. It includes powerful analytics tools to help you diagnose issues and to understand
18+
what users actually do with your bot.
19+
20+
How to Install
21+
==============
22+
23+
.. code-block:: python
24+
25+
pip install botbuilder-applicationinsights-aiohttp
26+
27+
28+
Documentation/Wiki
29+
==================
30+
31+
You can find more information on the botbuilder-python project by visiting our `Wiki`_.
32+
33+
Requirements
34+
============
35+
36+
* `Python >= 3.7.0`_
37+
38+
39+
Source Code
40+
===========
41+
The latest developer version is available in a github repository:
42+
https://github.com/Microsoft/botbuilder-python/
43+
44+
45+
Contributing
46+
============
47+
48+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
49+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
50+
the rights to use your contribution. For details, visit https://cla.microsoft.com.
51+
52+
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
53+
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
54+
provided by the bot. You will only need to do this once across all repos using our CLA.
55+
56+
This project has adopted the `Microsoft Open Source Code of Conduct`_.
57+
For more information see the `Code of Conduct FAQ`_ or
58+
contact `opencode@microsoft.com`_ with any additional questions or comments.
59+
60+
Reporting Security Issues
61+
=========================
62+
63+
Security issues and bugs should be reported privately, via email, to the Microsoft Security
64+
Response Center (MSRC) at `secure@microsoft.com`_. You should
65+
receive a response within 24 hours. If for some reason you do not, please follow up via
66+
email to ensure we received your original message. Further information, including the
67+
`MSRC PGP`_ key, can be found in
68+
the `Security TechCenter`_.
69+
70+
License
71+
=======
72+
73+
Copyright (c) Microsoft Corporation. All rights reserved.
74+
75+
Licensed under the MIT_ License.
76+
77+
.. _Wiki: https://github.com/Microsoft/botbuilder-python/wiki
78+
.. _Python >= 3.7.0: https://www.python.org/downloads/
79+
.. _MIT: https://github.com/Microsoft/vscode/blob/master/LICENSE.txt
80+
.. _Microsoft Open Source Code of Conduct: https://opensource.microsoft.com/codeofconduct/
81+
.. _Code of Conduct FAQ: https://opensource.microsoft.com/codeofconduct/faq/
82+
.. _opencode@microsoft.com: mailto:opencode@microsoft.com
83+
.. _secure@microsoft.com: mailto:secure@microsoft.com
84+
.. _MSRC PGP: https://technet.microsoft.com/en-us/security/dn606155
85+
.. _Security TechCenter: https://github.com/Microsoft/vscode/blob/master/LICENSE.txt
86+
87+
.. <https://technet.microsoft.com/en-us/security/default>`_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .aiohttp_telemetry_middleware import bot_telemetry_middleware
2+
from .aiohttp_telemetry_processor import AiohttpTelemetryProcessor
3+
4+
__all__ = [
5+
"bot_telemetry_middleware",
6+
"AiohttpTelemetryProcessor",
7+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
"""Bot Framework Application Insights integration package for aiohttp library."""
4+
5+
import os
6+
7+
__title__ = "botbuilder-integration-applicationinsights-aiohttp"
8+
__version__ = (
9+
os.environ["packageVersion"] if "packageVersion" in os.environ else "4.4.0b1"
10+
)
11+
__uri__ = "https://www.github.com/Microsoft/botbuilder-python"
12+
__author__ = "Microsoft"
13+
__description__ = "Microsoft Bot Framework Bot Builder"
14+
__summary__ = "Microsoft Bot Framework Bot Builder SDK for Python."
15+
__license__ = "MIT"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from threading import current_thread
2+
from aiohttp.web import middleware
3+
4+
# Map of thread id => POST body text
5+
_REQUEST_BODIES = {}
6+
7+
8+
def retrieve_aiohttp_body():
9+
""" retrieve_flask_body
10+
Retrieve the POST body text from temporary cache.
11+
The POST body corresponds with the thread id and should resides in
12+
cache just for lifetime of request.
13+
"""
14+
result = _REQUEST_BODIES.pop(current_thread().ident, None)
15+
return result
16+
17+
18+
@middleware
19+
async def bot_telemetry_middleware(request, handler):
20+
"""Process the incoming Flask request."""
21+
if "application/json" in request.headers["Content-Type"]:
22+
body = await request.json()
23+
_REQUEST_BODIES[current_thread().ident] = body
24+
25+
response = await handler(request)
26+
return response
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
"""Telemetry processor for aiohttp."""
4+
import sys
5+
6+
from botbuilder.applicationinsights.processor.telemetry_processor import (
7+
TelemetryProcessor,
8+
)
9+
from .aiohttp_telemetry_middleware import retrieve_aiohttp_body
10+
11+
12+
class AiohttpTelemetryProcessor(TelemetryProcessor):
13+
def can_process(self) -> bool:
14+
return self.detect_aiohttp()
15+
16+
def get_request_body(self) -> str:
17+
if self.detect_aiohttp():
18+
return retrieve_aiohttp_body()
19+
return None
20+
21+
@staticmethod
22+
def detect_aiohttp() -> bool:
23+
"""Detects if running in aiohttp."""
24+
return "aiohttp" in sys.modules
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import os
5+
from setuptools import setup
6+
7+
REQUIRES = [
8+
"applicationinsights>=0.11.9",
9+
"botbuilder-schema>=4.4.0b1",
10+
"botframework-connector>=4.4.0b1",
11+
"botbuilder-core>=4.4.0b1",
12+
"botbuilder-applicationinsights>=4.4.0b1",
13+
]
14+
TESTS_REQUIRES = [
15+
"aiounittest==1.3.0",
16+
"aiohttp==3.5.4",
17+
]
18+
19+
root = os.path.abspath(os.path.dirname(__file__))
20+
21+
with open(
22+
os.path.join(
23+
root, "botbuilder", "integration", "applicationinsights", "aiohttp", "about.py"
24+
)
25+
) as f:
26+
package_info = {}
27+
info = f.read()
28+
exec(info, package_info)
29+
30+
with open(os.path.join(root, "README.rst"), encoding="utf-8") as f:
31+
long_description = f.read()
32+
33+
setup(
34+
name=package_info["__title__"],
35+
version=package_info["__version__"],
36+
url=package_info["__uri__"],
37+
author=package_info["__author__"],
38+
description=package_info["__description__"],
39+
keywords=[
40+
"BotBuilderApplicationInsights",
41+
"bots",
42+
"ai",
43+
"botframework",
44+
"botbuilder",
45+
"aiohttp",
46+
],
47+
long_description=long_description,
48+
long_description_content_type="text/x-rst",
49+
license=package_info["__license__"],
50+
packages=["botbuilder.integration.applicationinsights.aiohttp"],
51+
install_requires=REQUIRES + TESTS_REQUIRES,
52+
tests_require=TESTS_REQUIRES,
53+
include_package_data=True,
54+
classifiers=[
55+
"Programming Language :: Python :: 3.7",
56+
"Intended Audience :: Developers",
57+
"License :: OSI Approved :: MIT License",
58+
"Operating System :: OS Independent",
59+
"Development Status :: 5 - Production/Stable",
60+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
61+
],
62+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from unittest.mock import Mock
2+
from aiounittest import AsyncTestCase
3+
4+
import aiohttp # pylint: disable=unused-import
5+
6+
from botbuilder.integration.applicationinsights.aiohttp import (
7+
aiohttp_telemetry_middleware,
8+
AiohttpTelemetryProcessor,
9+
)
10+
11+
12+
class TestAiohttpTelemetryProcessor(AsyncTestCase):
13+
# pylint: disable=protected-access
14+
def test_can_process(self):
15+
assert AiohttpTelemetryProcessor.detect_aiohttp()
16+
assert AiohttpTelemetryProcessor().can_process()
17+
18+
def test_retrieve_aiohttp_body(self):
19+
aiohttp_telemetry_middleware._REQUEST_BODIES = Mock()
20+
aiohttp_telemetry_middleware._REQUEST_BODIES.pop = Mock(
21+
return_value="test body"
22+
)
23+
assert aiohttp_telemetry_middleware.retrieve_aiohttp_body() == "test body"
24+
25+
assert AiohttpTelemetryProcessor().get_request_body() == "test body"
26+
aiohttp_telemetry_middleware._REQUEST_BODIES = {}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from asyncio import Future
2+
from unittest.mock import Mock, MagicMock
3+
from aiounittest import AsyncTestCase
4+
5+
from botbuilder.integration.applicationinsights.aiohttp import (
6+
bot_telemetry_middleware,
7+
aiohttp_telemetry_middleware,
8+
)
9+
10+
11+
class TestAiohttpTelemetryMiddleware(AsyncTestCase):
12+
# pylint: disable=protected-access
13+
async def test_bot_telemetry_middleware(self):
14+
req = Mock()
15+
req.headers = {"Content-Type": "application/json"}
16+
req.json = MagicMock(return_value=Future())
17+
req.json.return_value.set_result("mock body")
18+
19+
async def handler(value):
20+
return value
21+
22+
sut = await bot_telemetry_middleware(req, handler)
23+
24+
assert "mock body" in aiohttp_telemetry_middleware._REQUEST_BODIES.values()
25+
aiohttp_telemetry_middleware._REQUEST_BODIES.clear()
26+
assert req == sut
27+
28+
def test_retrieve_aiohttp_body(self):
29+
aiohttp_telemetry_middleware._REQUEST_BODIES = Mock()
30+
aiohttp_telemetry_middleware._REQUEST_BODIES.pop = Mock(
31+
return_value="test body"
32+
)
33+
assert aiohttp_telemetry_middleware.retrieve_aiohttp_body() == "test body"
34+
35+
aiohttp_telemetry_middleware._REQUEST_BODIES = {}

0 commit comments

Comments
 (0)