Skip to content

Commit 10c63fc

Browse files
committed
feat: create Scout APM plugin
This plugin enables Scout APM reporting for the edx-platform backend.
1 parent c1d6855 commit 10c63fc

File tree

10 files changed

+178
-0
lines changed

10 files changed

+178
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.*.swp
2+
!.gitignore
3+
TODO
4+
__pycache__
5+
*.egg-info/
6+
/build/
7+
/dist/
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
recursive-include tutor_scout_apm/patches *
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Scout APM plugin for `Tutor <https://docs.tutor.overhang.io>`_
2+
==============================================================
3+
4+
This plugin allows Open edX LMS and Studio site operators add support for Scout APM monitoring.
5+
6+
Installation
7+
------------
8+
9+
This will install the `Scout APM <https://scoutapm.com/>`_ plugin directly from Github::
10+
11+
pip install git+https://github.com/openedx/openedx-tutor-plugins.git#subdirectory=plugins/tutor-contrib-scout-apm
12+
13+
Alternatively, you can clone the parent repository locally and install it from the checkout::
14+
15+
git clone https://github.com/openedx/openedx-tutor-plugins.git
16+
cd openedx-tutor-plugins/plugins/tutor-contrib-scout-apm
17+
pip install -e .
18+
19+
Usage
20+
-----
21+
22+
Once installed, run the following commands to enable it::
23+
24+
tutor plugins enable scout-apm
25+
tutor images build openedx-dev
26+
27+
Add the following entries to your Tutor ``config.yml`` file:
28+
29+
* ``SCOUT_KEY``: Get this from your Scout APM account.
30+
* ``SCOUT_NAME``: A user friendly name for your application. It will have "| LMS" or "| Studio" appended to it. So if you put "Sumac Test Server", the two Scout apps being reported will be "Sumac Test Server | LMS" and "Sumac Test Server | Studio".
31+
32+
License
33+
-------
34+
35+
This software is licensed under the terms of the AGPLv3.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import io
2+
import os
3+
from setuptools import setup, find_packages
4+
5+
HERE = os.path.abspath(os.path.dirname(__file__))
6+
7+
8+
def load_readme():
9+
with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f:
10+
return f.read()
11+
12+
13+
def load_about():
14+
about = {}
15+
with io.open(
16+
os.path.join(HERE, "tutor_scout_apm", "__about__.py"),
17+
"rt",
18+
encoding="utf-8",
19+
) as f:
20+
exec(f.read(), about) # pylint: disable=exec-used
21+
return about
22+
23+
24+
ABOUT = load_about()
25+
26+
27+
setup(
28+
name="tutor-scout-apm",
29+
version=ABOUT["__version__"],
30+
url="https://github.com/openedx/openedx-tutor-plugins",
31+
project_urls={
32+
"Code": "https://github.com/openedx/openedx-tutor-plugins",
33+
"Issue tracker": "https://github.com/openedx/openedx-tutor-plugins/issues",
34+
},
35+
license="AGPLv3",
36+
author="David Ormsbee",
37+
description="Scout APM plugin for Tutor",
38+
long_description=load_readme(),
39+
packages=find_packages(exclude=["tests*"]),
40+
include_package_data=True,
41+
python_requires=">=3.8",
42+
install_requires=["tutor"],
43+
extras_require={"dev": ["tutor[dev]>=16.0.0,<19.0.0"]},
44+
entry_points={
45+
"tutor.plugin.v1": [
46+
"scout-apm = tutor_scout_apm.plugin"
47+
]
48+
},
49+
classifiers=[
50+
"Development Status :: 3 - Alpha",
51+
"Intended Audience :: Developers",
52+
"License :: OSI Approved :: GNU Affero General Public License v3",
53+
"Operating System :: OS Independent",
54+
"Programming Language :: Python",
55+
"Programming Language :: Python :: 3.9",
56+
"Programming Language :: Python :: 3.10",
57+
"Programming Language :: Python :: 3.11",
58+
"Programming Language :: Python :: 3.12",
59+
],
60+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "1.0.0"

plugins/tutor-contrib-scout-apm/tutor_scout_apm/__init__.py

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SCOUT_MONITOR = True
2+
SCOUT_KEY = "{{ SCOUT_KEY }}"
3+
SCOUT_NAME = "{{ SCOUT_NAME }} | Studio"
4+
5+
# Prepend the Scout APM before everything else so that it can inject its
6+
# monitoring.
7+
INSTALLED_APPS.insert(0, "scout_apm.django")
8+
9+
SCOUT_MIDDLEWARE = [
10+
"scout_apm.django.middleware.MiddlewareTimingMiddleware",
11+
"scout_apm.django.middleware.ViewTimingMiddleware",
12+
]
13+
MIDDLEWARE = SCOUT_MIDDLEWARE + MIDDLEWARE
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared \
2+
pip install "scout-apm>=3.2.1,<4.0"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SCOUT_MONITOR = True
2+
SCOUT_KEY = "{{ SCOUT_KEY }}"
3+
SCOUT_NAME = "{{ SCOUT_NAME }} | LMS"
4+
5+
# Prepend the Scout APM before everything else so that it can inject its
6+
# monitoring.
7+
INSTALLED_APPS.insert(0, "scout_apm.django")
8+
9+
SCOUT_MIDDLEWARE = [
10+
"scout_apm.django.middleware.MiddlewareTimingMiddleware",
11+
"scout_apm.django.middleware.ViewTimingMiddleware",
12+
]
13+
MIDDLEWARE = SCOUT_MIDDLEWARE + MIDDLEWARE
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from __future__ import annotations
2+
from glob import glob
3+
import os
4+
import pkg_resources
5+
import uuid
6+
7+
from tutor import hooks as tutor_hooks
8+
9+
from .__about__ import __version__
10+
11+
########################################
12+
# CONFIGURATION
13+
########################################
14+
15+
tutor_hooks.Filters.CONFIG_DEFAULTS.add_item(
16+
("SCOUT_KEY", "")
17+
)
18+
tutor_hooks.Filters.CONFIG_DEFAULTS.add_item(
19+
("SCOUT_NAME", "")
20+
)
21+
22+
########################################
23+
# INITIALIZATION TASKS
24+
########################################
25+
26+
27+
########################################
28+
# TEMPLATE RENDERING
29+
########################################
30+
31+
32+
########################################
33+
# PATCH LOADING
34+
########################################
35+
36+
# For each file in tutor_media/patches,
37+
# apply a patch based on the file's name and contents.
38+
patch_files = glob(
39+
os.path.join(
40+
pkg_resources.resource_filename("tutor_scout_apm", "patches"),
41+
"*",
42+
)
43+
)
44+
for path in patch_files:
45+
with open(path, encoding="utf-8") as patch_file:
46+
tutor_hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read()))

0 commit comments

Comments
 (0)