Skip to content

Commit a2dacfa

Browse files
authored
Merge pull request #148 from EyeSeeTea/feature/glowroot
Added a feature to enable glowroot in tomcat
2 parents 030ef32 + 1397ec1 commit a2dacfa

File tree

9 files changed

+120
-12
lines changed

9 files changed

+120
-12
lines changed

README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
- Operating System: GNU/Linux or Windows 10.
44
- Python >= 3.5 (with setuptools)
5-
- Docker >= 18
6-
- Docker compose >= 1.17
5+
- Docker >= 20.10.13
6+
- Docker compose >= 2.0
77
- RAM memory: At least 4Gb for instance, preferrably 8Gb.
88

99
On Ubuntu 22.04:
@@ -69,6 +69,8 @@ Create a dhis2-data image from a .sql.gz SQL file and the apps and documents (or
6969
$ d2-docker create data docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --sql=sierra-db.sql.gz [--apps-dir=path/to/apps] [--documents-dir=path/to/document] [--datavalues-dir=path/to/dataValue]
7070
```
7171

72+
There are demo database files at [databases.dhis2.org](https://databases.dhis2.org/) that may be used for testing purposses. The database downloaded should correspond to the core version created; if there is no database file for the created core version, a prior version of the database should work.
73+
7274
### Start a DHIS2 instance
7375

7476
Start a new container from a _dhis2-data_ base image:
@@ -376,3 +378,18 @@ $ cp flaskenv.secret ~/.config/d2-docker/
376378
377379
$ curl -sS 'http://localhost:5000/harbor/https://docker.eyeseetea.com/api/v2.0/quotas/1' | jq
378380
```
381+
382+
## Glowroot
383+
384+
Glowroot is an open-source Java APM (Application Performance Monitoring) tool. It can help detect and diagnose application performance problems, tracing slow requests, errors, response time breakdowns, SQL capture and more.
385+
When starting a container, there are two options to enable glowroot on the Tomcat process:
386+
- Use option `--glowroot` to use the latest version of glowroot in the Tomcat process. This requires internet access to be able to retrieve the file.
387+
- Use option `--glowroot-zip=FILE` to specify the zip file with the version of glowroot to run in the Tomcat process. This takes precedence over the other option.
388+
When enabling glowroot, it will start listening on port 4000/tcp so you can connect via browser to its interface. You may override this port with:
389+
- `--glowroot-port=PORT` to specify the APM glowroot port.
390+
391+
### Run d2-docker with glowroot enabled in the default port at the latest version available
392+
393+
```
394+
$ d2-docker start docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --glowroot
395+
```

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setuptools.setup(
66
name="d2_docker",
7-
version="1.15.0.b2",
7+
version="1.16.0",
88
description="Dockers for DHIS2 instances",
99
long_description=open("README.md", encoding="utf-8").read(),
1010
keywords=["python"],

src/d2_docker/commands/rm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def run(args):
1515
def remove_image(image):
1616
utils.logger.info("Delete image/containers: {}".format(image))
1717
utils.run_docker_compose(["stop"], image)
18-
result = utils.run_docker_compose(["ps", "-q"], data_image=image, capture_output=True)
18+
result = utils.run_docker_compose(["ps", "-aq"], data_image=image, capture_output=True)
1919
container_ids = result.stdout.decode("utf-8").splitlines()
2020
utils.logger.debug("Container IDs: {}".format(container_ids))
2121
if container_ids:

src/d2_docker/commands/start.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ def setup(parser):
4141
parser.add_argument("--postgis-version", type=str, help="Set PostGIS database version")
4242
parser.add_argument("--enable-postgres-queries-logging", action="store_true",
4343
help="Enable Postgres queries logging")
44+
45+
parser.add_argument("--glowroot", action="store_true", help="Enables glowroot in tomcat in latest version")
46+
parser.add_argument("--glowroot-zip", metavar="FILE", help="ZIP file with glowroot binaries")
47+
parser.add_argument("--glowroot-port", metavar="PORT", help="Set glowroot port")
4448

4549

4650
def run(args):
@@ -113,6 +117,9 @@ def start(args):
113117
java_opts=args.java_opts,
114118
postgis_version=args.postgis_version,
115119
enable_postgres_queries_logging=args.enable_postgres_queries_logging,
120+
glowroot=args.glowroot,
121+
glowroot_zip=args.glowroot_zip,
122+
glowroot_port=args.glowroot_port,
116123
)
117124

118125
if args.detach:

src/d2_docker/config/dhis2-core-entrypoint.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ WARFILE=/usr/local/tomcat/webapps/ROOT.war
1212
TOMCATDIR=/usr/local/tomcat
1313
DHIS2HOME=/DHIS2_home
1414
DATA_DIR=/data
15+
GLOWROOT_ZIP="/opt/glowroot.zip"
16+
GLOWROOT_DIR="/opt/glowroot"
17+
1518

1619
debug() {
1720
echo "[dhis2-core-entrypoint] $*" >&2
@@ -43,12 +46,33 @@ wait_for_data_container_to_finish_copy() {
4346

4447
}
4548

49+
setup_glowroot() {
50+
if [ -f $GLOWROOT_ZIP ] && [ ! -d $GLOWROOT_DIR ] ; then
51+
status=0
52+
output=$(unzip -q "$GLOWROOT_ZIP" -d /opt/ 2>&1) || status=$?
53+
# Ignore RC=1 that implies only warnings and no errors (like an empty zip file)
54+
if [ $status -gt 1 ]; then
55+
echo "$output"
56+
exit $status
57+
fi
58+
if [ -d $GLOWROOT_DIR ] ; then
59+
echo '{ "web": { "bindAddress": "0.0.0.0", "port": "4000" }}' > $GLOWROOT_DIR/admin.json
60+
chown -R tomcat:tomcat $GLOWROOT_DIR
61+
chmod -R u=rwX,g=rX,o-rwx $GLOWROOT_DIR
62+
echo 'export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/glowroot/glowroot.jar"' > /usr/local/tomcat/bin/setenv.sh
63+
chmod ugo+x /usr/local/tomcat/bin/setenv.sh
64+
chown tomcat:tomcat /usr/local/tomcat/bin/setenv.sh
65+
fi
66+
fi
67+
}
68+
4669
if [ "$(id -u)" = "0" ]; then
4770
if [ -f $WARFILE ]; then
4871
unzip -q $WARFILE -d $TOMCATDIR/webapps/ROOT
4972
rm -v $WARFILE # just to save space
5073
fi
5174

75+
setup_glowroot
5276
wait_for_data_container_to_finish_copy
5377

5478
mkdir -p $DATA_DIR/apps

src/d2_docker/config/dhis2-core-start.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,13 @@ run() {
163163
local host=$1 psql_port=$2
164164

165165
setup_tomcat
166-
copy_apps
167-
copy_documents
168-
copy_datavalues
169-
170166
if is_init_done; then
171-
debug "Container: already configured. Skip DB load"
167+
debug "Container: already configured. Skip DB load and keeping other changes"
172168
else
169+
debug "Container: clean. Copying tomcat files and dhis folders"
170+
copy_apps
171+
copy_documents
172+
copy_datavalues
173173
debug "Container: clean. Load DB"
174174
wait_for_postgres
175175
run_sql_files

src/d2_docker/docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ services:
55
- "com.eyeseetea.image-name=${DHIS2_DATA_IMAGE}"
66
volumes:
77
- home:/DHIS2_home
8+
- ${GLOWROOT_ZIP}:/opt/glowroot.zip
89
- ${DHIS_CONF}:/config/override/dhis2/dhis.conf
910
- ${ROOT_PATH}/config:/config
1011
- data:/data
@@ -27,6 +28,8 @@ services:
2728
- "data"
2829
ports:
2930
- "${DHIS2_CORE_DEBUG_PORT}"
31+
- "${GLOWROOT_PORT}"
32+
dns_search: .
3033
db:
3134
image: "postgis/postgis:${POSTGIS_VERSION:-14-3.2-alpine}"
3235
shm_size: 1gb

src/d2_docker/glowroot.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import atexit
2+
import json
3+
import os
4+
import shutil
5+
import tempfile
6+
import urllib.request
7+
import zipfile
8+
from d2_docker import utils
9+
10+
GLOWROOT_DEFAULT_PORT = "4000"
11+
12+
def get_latest_glowroot_url():
13+
glowroot_releases_url = "https://api.github.com/repos/glowroot/glowroot/releases/latest"
14+
glowroot_download_url = "https://github.com/glowroot/glowroot/releases/download"
15+
with urllib.request.urlopen(glowroot_releases_url) as response:
16+
data = response.read().decode()
17+
release_info = json.loads(data)
18+
19+
tag_name = release_info["tag_name"]
20+
return "{}/{}/glowroot-{}-dist.zip".format(glowroot_download_url, tag_name, tag_name.lstrip("v"))
21+
22+
def get_glowroot_zip(command, glowroot_zip, glowroot):
23+
logger = utils.logger
24+
if isinstance(command, list) and command[0] == "up":
25+
glowroot_file = tempfile.NamedTemporaryFile(delete=False, prefix="glowroot_", suffix=".zip", dir="/tmp")
26+
glowroot_path = glowroot_file.name
27+
28+
atexit.register(lambda: os.remove(glowroot_path) if os.path.exists(glowroot_path) else None)
29+
if glowroot_zip:
30+
logger.debug("Copy zip file: {} -> {}".format(glowroot_zip, glowroot_path))
31+
shutil.copy(glowroot_zip, glowroot_path)
32+
elif glowroot:
33+
glowroot_url = get_latest_glowroot_url()
34+
logger.info("Download file: {}".format(glowroot_url))
35+
urllib.request.urlretrieve(glowroot_url, glowroot_path)
36+
else:
37+
# empty zipfile
38+
with zipfile.ZipFile(glowroot_path, mode="w") as zf:
39+
pass
40+
else:
41+
glowroot_path = None
42+
43+
return utils.get_absfile_for_docker_volume(glowroot_path)
44+
45+
def get_port_glowroot(glowroot_port, glowroot_zip, glowroot):
46+
port = glowroot_port if glowroot_port else GLOWROOT_DEFAULT_PORT
47+
return "{}:{}".format(port, GLOWROOT_DEFAULT_PORT) if (glowroot_port or glowroot_zip or glowroot) else None

src/d2_docker/utils.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from typing import Optional
1616

1717
import d2_docker
18+
from d2_docker.glowroot import get_glowroot_zip, get_port_glowroot
1819
from .image_name import ImageName
1920

2021
PROJECT_NAME_PREFIX = "d2-docker"
@@ -261,6 +262,9 @@ def run_docker_compose(
261262
tomcat_server=None,
262263
postgis_version=None,
263264
enable_postgres_queries_logging=False,
265+
glowroot=None,
266+
glowroot_zip=None,
267+
glowroot_port=None,
264268
**kwargs,
265269
):
266270
"""
@@ -270,6 +274,7 @@ def run_docker_compose(
270274
271275
The DHIS2_CORE_IMAGE is inferred from the data repo, if not specified.
272276
"""
277+
273278
final_image_name = data_image or get_running_image_name()
274279
project_name = get_project_name(final_image_name)
275280
core_image_name = core_image or get_core_image_name(data_image)
@@ -296,13 +301,18 @@ def run_docker_compose(
296301
# Add ROOT_PATH from environment (required when run inside a docker)
297302
("ROOT_PATH", ROOT_PATH),
298303
("PSQL_ENABLE_QUERY_LOGS", "") if not enable_postgres_queries_logging else None,
304+
("GLOWROOT_PORT", get_port_glowroot(glowroot_port, glowroot_zip, glowroot)),
305+
("GLOWROOT_ZIP", get_glowroot_zip(args, glowroot_zip, glowroot)),
299306
]
300307
env = dict((k, v) for (k, v) in [pair for pair in env_pairs if pair] if v is not None)
301308

302309
def process_yaml(data):
303-
if "DHIS2_CORE_DEBUG_PORT" not in env:
304-
core = data["services"]["core"]
305-
core["ports"] = [port for port in core["ports"] if "DHIS2_CORE_DEBUG_PORT" not in port]
310+
# Removes ports for "core" service in docker-compose if the environmental variables are not established
311+
core = data["services"]["core"]
312+
env_ports = ["DHIS2_CORE_DEBUG_PORT", "GLOWROOT_PORT"]
313+
for env_port in env_ports:
314+
if env_port not in env:
315+
core["ports"] = [port for port in core["ports"] if env_port not in port]
306316

307317
return data
308318

0 commit comments

Comments
 (0)