diff --git a/README.md b/README.md index d6cd1cd..99f1d52 100644 --- a/README.md +++ b/README.md @@ -383,14 +383,42 @@ $ curl -sS 'http://localhost:5000/harbor/https://docker.eyeseetea.com/api/v2.0/q ## Glowroot 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. -When starting a container, there are two options to enable glowroot on the Tomcat process: -- 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. -- 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. -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: -- `--glowroot-port=PORT` to specify the APM glowroot port. +The startup script in the core container expects a `/opt/glowroot.zip` file; if it exists, it will decompress that file and enable a default configuration for glowroot in the tomcat process. +The only needed parameter to use glowroot is the `--glowroot-port`, as the metrics are exposes through its own http connection, so the port must be opened in the container. +To use glowroot: -### Run d2-docker with glowroot enabled in the default port at the latest version available +- start d2-docker with `--glowroot-port=` (default port for glowroot is 4000, but any available port can be used) +- download the latest version of glowroot to the host machine: ``` -$ d2-docker start docker.eyeseetea.com/eyeseetea/dhis2-data:2.37.9-sierra --glowroot +lastversion=$(wget -q -O - https://api.github.com/repos/glowroot/glowroot/releases/latest | jq '.tag_name' | sed 's_"__g') +wget -q https://github.com/glowroot/glowroot/releases/download/$lastversion/glowroot-${lastversion#v}-dist.zip ``` + +- determine the core instance name (note that as there might be several d2-docker instances running, you must pick the one you want manually from the list) + +``` +docker ps | awk '/core.1/ {print $NF}' +``` + +- copy the zip file to the core container with the filename `/opt/glowroot.zip`: + +``` +docker cp glowroot-0.14.4-dist.zip ${core_instance_name}:/opt/glowroot.zip +``` + +- restart the core container: + +``` +docker restart ${core_instance_name} +``` + +Glowroot is configured to store its data for several days, so the size of its folder should be limited to some extent. This size may be further reduced editing the configuration via WebUI, but might require a restart of the container. Configuration (and glowroot historical data) will be kept unless the `/opt/glowroot` folder is deleted from the container and restarted. + +To remove glowroot from a container you must: + +- connect to the core container (`docker exec -it ${core_instance_name} bash`) +- inside the core container, remove the `/opt/glowroot.zip` file +- inside the core container, remove the `/opt/glowroot` folder +- inside the core container, remove the `/usr/local/tomcat/bin/setenv.sh` file. (This is not extrictly necessary as the jar file will no longer exist and won't be able to start, but if it is not removed, some warnings/errors may be generated upon tomcat start) +- exit the core container and restart it (`docker restart ${core_instance_name}`) diff --git a/src/d2_docker/commands/start.py b/src/d2_docker/commands/start.py index c59a5b8..bfa72b3 100644 --- a/src/d2_docker/commands/start.py +++ b/src/d2_docker/commands/start.py @@ -42,8 +42,6 @@ def setup(parser): parser.add_argument("--enable-postgres-queries-logging", action="store_true", help="Enable Postgres queries logging") - parser.add_argument("--glowroot", action="store_true", help="Enables glowroot in tomcat in latest version") - parser.add_argument("--glowroot-zip", metavar="FILE", help="ZIP file with glowroot binaries") parser.add_argument("--glowroot-port", metavar="PORT", help="Set glowroot port") @@ -117,9 +115,7 @@ def start(args): java_opts=args.java_opts, postgis_version=args.postgis_version, enable_postgres_queries_logging=args.enable_postgres_queries_logging, - glowroot=args.glowroot, - glowroot_zip=args.glowroot_zip, - glowroot_port=args.glowroot_port, + glowroot_port=args.glowroot_port ) if args.detach: diff --git a/src/d2_docker/config/dhis2-core-entrypoint.sh b/src/d2_docker/config/dhis2-core-entrypoint.sh index ffc3a3f..6756169 100755 --- a/src/d2_docker/config/dhis2-core-entrypoint.sh +++ b/src/d2_docker/config/dhis2-core-entrypoint.sh @@ -57,6 +57,33 @@ setup_glowroot() { fi if [ -d $GLOWROOT_DIR ] ; then echo '{ "web": { "bindAddress": "0.0.0.0", "port": "4000" }}' > $GLOWROOT_DIR/admin.json + echo '{"transactions":{"slowThresholdMillis":2000,"profilingIntervalMillis":1000,"captureThreadStats":true}, + "jvm":{"maskSystemProperties":["*password*","*token*","*access*","*secret*"],"maskMBeanAttributes":["*password*","*token*","*access*","*secret*"]}, + "uiDefaults":{"defaultTransactionType":"Web","defaultPercentiles":[50,95,99],"defaultGaugeNames":["java.lang:type=Memory:HeapMemoryUsage.used"]}, + "advanced":{"immediatePartialStoreThresholdSeconds":60,"maxTransactionAggregates":500,"maxQueryAggregates":500,"maxServiceCallAggregates":500, + "maxTraceEntriesPerTransaction":2000,"maxProfileSamplesPerTransaction":50000,"mbeanGaugeNotFoundDelaySeconds":60},"gauges":[{"mbeanObjectName":"java.lang:type=Memory", + "mbeanAttributes":[{"name":"HeapMemoryUsage.used"}]},{"mbeanObjectName":"java.lang:type=GarbageCollector,name=*","mbeanAttributes":[{"name":"CollectionCount","counter":true}, + {"name":"CollectionTime","counter":true}]},{"mbeanObjectName":"java.lang:type=MemoryPool,name=*","mbeanAttributes":[{"name":"Usage.used"}]}, + {"mbeanObjectName":"java.lang:type=OperatingSystem","mbeanAttributes":[{"name":"FreePhysicalMemorySize"},{"name":"ProcessCpuLoad"},{"name":"SystemCpuLoad"}]}], + "plugins":[{"properties":{"stackTraceThresholdMillis":1000},"id":"cassandra"},{"properties":{"stackTraceThresholdMillis":1000},"id":"elasticsearch"}, + {"properties":{"sessionUserAttribute":"","captureSessionAttributes":[],"captureRequestParameters":["*"],"maskRequestParameters":["*password*","*token*","*access*","*secret*"], + "captureRequestHeaders":[],"captureResponseHeaders":[],"traceErrorOn4xxResponseCode":false,"captureRequestRemoteAddr":false,"captureRequestRemoteHostname":false, + "captureRequestRemotePort":false,"captureRequestLocalAddr":false,"captureRequestLocalHostname":false,"captureRequestLocalPort":false,"captureRequestServerHostname":false, + "captureRequestServerPort":false},"id":"jakartaservlet"},{"properties":{"captureRequestHeaders":[],"maskRequestHeaders":["Authorization"],"captureRequestRemoteAddr":false, + "captureRequestRemoteHost":false,"captureResponseHeaders":[],"traceErrorOn4xxResponseCode":false},"id":"java-http-server"},{"properties":{"useAltTransactionNaming":false}, + "id":"jaxrs"},{"properties":{"captureBindParametersIncludes":[".*"],"captureBindParametersExcludes":[],"captureResultSetNavigate":true,"captureResultSetGet":false, + "captureConnectionPoolLeaks":false,"captureConnectionPoolLeakDetails":false,"captureGetConnection":true,"captureConnectionClose":false,"capturePreparedStatementCreation":false, + "captureStatementClose":false,"captureTransactionLifecycleTraceEntries":false,"captureConnectionLifecycleTraceEntries":false,"stackTraceThresholdMillis":1000},"id":"jdbc"}, + {"properties":{"traceErrorOnErrorWithThrowable":true,"traceErrorOnErrorWithoutThrowable":false,"traceErrorOnWarningWithThrowable":false,"traceErrorOnWarningWithoutThrowable":false}, + "id":"logger"},{"properties":{"stackTraceThresholdMillis":1000},"id":"mongodb"},{"properties":{"useAltTransactionNaming":false},"id":"play"},{"properties":{"sessionUserAttribute":"", + "captureSessionAttributes":[],"captureRequestParameters":["*"],"maskRequestParameters":["*password*","*token*","*access*","*secret*"],"captureRequestHeaders":[], + "captureResponseHeaders":[],"traceErrorOn4xxResponseCode":false,"captureRequestRemoteAddr":false,"captureRequestRemoteHostname":false,"captureRequestRemotePort":false, + "captureRequestLocalAddr":false,"captureRequestLocalHostname":false,"captureRequestLocalPort":false,"captureRequestServerHostname":false,"captureRequestServerPort":false}, + "id":"servlet"},{"properties":{"useAltTransactionNaming":false},"id":"spring"}],"instrumentation":[{"className":"org.hisp.dhis.webapi.controller.event.TrackedEntityInstanceController", + "methodName":"getTrackedEntityInstances","methodParameterTypes":[".."],"order":0,"captureKind":"other","transactionType":"Web","transactionNameTemplate":"/api/trackedEntityInstances: GET"}, + {"className":"org.hisp.dhis.tracker.report.DefaultTrackerImportService","methodName":"importTracker","methodParameterTypes":[".."],"order":0,"captureKind":"transaction", + "transactionType":"Web","transactionNameTemplate":"/api/tracker: import","alreadyInTransactionBehavior":"capture-new-transaction","traceEntryMessageTemplate":"{{0}}", + "traceEntryStackThresholdMillis":300,"traceEntryCaptureSelfNested":true,"timerName":"Timer"}]}' > $GLOWROOT_DIR/config.json chown -R tomcat:tomcat $GLOWROOT_DIR chmod -R u=rwX,g=rX,o-rwx $GLOWROOT_DIR echo 'export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/glowroot/glowroot.jar"' > /usr/local/tomcat/bin/setenv.sh diff --git a/src/d2_docker/docker-compose.yml b/src/d2_docker/docker-compose.yml index 1b8eda2..f0f8d22 100644 --- a/src/d2_docker/docker-compose.yml +++ b/src/d2_docker/docker-compose.yml @@ -5,7 +5,6 @@ services: - "com.eyeseetea.image-name=${DHIS2_DATA_IMAGE}" volumes: - home:/DHIS2_home - - ${GLOWROOT_ZIP}:/opt/glowroot.zip - ${DHIS_CONF}:/config/override/dhis2/dhis.conf - ${ROOT_PATH}/config:/config - data:/data diff --git a/src/d2_docker/glowroot.py b/src/d2_docker/glowroot.py index a5a542f..52b5766 100644 --- a/src/d2_docker/glowroot.py +++ b/src/d2_docker/glowroot.py @@ -42,6 +42,6 @@ def get_glowroot_zip(command, glowroot_zip, glowroot): return utils.get_absfile_for_docker_volume(glowroot_path) -def get_port_glowroot(glowroot_port, glowroot_zip, glowroot): +def get_port_glowroot(glowroot_port): port = glowroot_port if glowroot_port else GLOWROOT_DEFAULT_PORT - return "{}:{}".format(port, GLOWROOT_DEFAULT_PORT) if (glowroot_port or glowroot_zip or glowroot) else None + return "{}:{}".format(port, GLOWROOT_DEFAULT_PORT) if glowroot_port else None diff --git a/src/d2_docker/utils.py b/src/d2_docker/utils.py index bc2bf93..138c372 100644 --- a/src/d2_docker/utils.py +++ b/src/d2_docker/utils.py @@ -15,7 +15,7 @@ from typing import Optional import d2_docker -from d2_docker.glowroot import get_glowroot_zip, get_port_glowroot +from d2_docker.glowroot import get_port_glowroot from .image_name import ImageName PROJECT_NAME_PREFIX = "d2-docker" @@ -262,8 +262,6 @@ def run_docker_compose( tomcat_server=None, postgis_version=None, enable_postgres_queries_logging=False, - glowroot=None, - glowroot_zip=None, glowroot_port=None, **kwargs, ): @@ -301,8 +299,7 @@ def run_docker_compose( # Add ROOT_PATH from environment (required when run inside a docker) ("ROOT_PATH", ROOT_PATH), ("PSQL_ENABLE_QUERY_LOGS", "") if not enable_postgres_queries_logging else None, - ("GLOWROOT_PORT", get_port_glowroot(glowroot_port, glowroot_zip, glowroot)), - ("GLOWROOT_ZIP", get_glowroot_zip(args, glowroot_zip, glowroot)), + ("GLOWROOT_PORT", get_port_glowroot(glowroot_port)) ] env = dict((k, v) for (k, v) in [pair for pair in env_pairs if pair] if v is not None)