diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 13c05acea..eceeeaa55 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,8 +7,9 @@ permissions: env: NOTIFY_ENVIRONMENT: test + NEW_RELIC_CONFIG_FILE: newrelic.ini + NEW_RELIC_ENVIRONMENT: test FLASK_APP: application.py - FLASK_ENV: development WERKZEUG_DEBUG_PIN: off REDIS_ENABLED: 0 NODE_VERSION: 16.15.1 diff --git a/.github/workflows/daily_checks.yml b/.github/workflows/daily_checks.yml index 8506d138e..83bd800e4 100644 --- a/.github/workflows/daily_checks.yml +++ b/.github/workflows/daily_checks.yml @@ -11,8 +11,9 @@ permissions: env: NOTIFY_ENVIRONMENT: test + NEW_RELIC_CONFIG_FILE: newrelic.ini + NEW_RELIC_ENVIRONMENT: test FLASK_APP: application.py - FLASK_ENV: development WERKZEUG_DEBUG_PIN: off REDIS_ENABLED: 0 NODE_VERSION: 16.15.1 diff --git a/Makefile b/Makefile index eac26f3db..7a1adebf8 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ watch-frontend: ## Build frontend and watch for changes .PHONY: run-flask run-flask: ## Run flask - pipenv run flask run -p 6012 --host=0.0.0.0 + pipenv run newrelic-admin run-program flask run -p 6012 --host=0.0.0.0 .PHONY: npm-audit npm-audit: ## Check for vulnerabilities in NPM packages @@ -48,6 +48,7 @@ py-lint: ## Run python linting scanners pipenv run isort --check-only ./app ./tests .PHONY: py-test +py-test: export NEW_RELIC_ENVIRONMENT=test py-test: ## Run python unit tests pipenv run py.test -n auto --maxfail=10 tests/ diff --git a/Pipfile b/Pipfile index 3e3e977da..e770004dc 100644 --- a/Pipfile +++ b/Pipfile @@ -31,8 +31,8 @@ pytz = "==2022.1" rtreelib = "==0.2.0" werkzeug = "~=2.2" wtforms = "==3.0.1" -notifications-utils = {editable = true, ref = "main", git = "https://github.com/GSA/notifications-utils.git"} newrelic = "*" +notifications-utils = {editable = true, ref = "request-unbound-error", git = "https://github.com/GSA/notifications-utils.git"} [dev-packages] isort = "==5.10.1" diff --git a/Pipfile.lock b/Pipfile.lock index 7cbd7e583..ea8c93a02 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7dbbe21d77da5c1cfed8a33aeaf66af6d05f1ee36c1bdd60e5e87f7fababc3a4" + "sha256": "04c7d4f97a5d60595b87980ef748d3ed77587067943f5e44a88ff3451a119f20" }, "pipfile-spec": 6, "requires": { @@ -49,19 +49,19 @@ }, "boto3": { "hashes": [ - "sha256:0b1f82d4565ed875c7975ac0be5665e8d948613c01bcb0e49df6d4f5af670cc8", - "sha256:319ddb274f8f83b035b88a3b127c465bf6fe3e3fc2d668869b489e992c47ca77" + "sha256:4e876ba5d64928cde0c416dd844f04f22d6b73d14002bbc3ca55591f80f49927", + "sha256:c729bb0af76e85a2776b6bd3da8d9fa0f4b91b425eab51612aa53956f644ee23" ], "markers": "python_version >= '3.7'", - "version": "==1.26.52" + "version": "==1.26.54" }, "botocore": { "hashes": [ - "sha256:a0b89a33305cfa6251c6e1142deb7567e216e37e25363159f45fb81dc5b474e5", - "sha256:de55b6333fb13c66da9055972d7e4efff5dcc5a087478a2b70e99d888b29a24c" + "sha256:ca3ef7588daa664fe196d3234718db5f6b5dab961507500b4bb921e31133eea1", + "sha256:f2fe17ed6b8e163769a715f81cb6ce3d4628d172918de535256bdf34d29b704f" ], "markers": "python_version >= '3.7'", - "version": "==1.29.52" + "version": "==1.29.54" }, "cachetools": { "hashes": [ @@ -693,7 +693,7 @@ "notifications-utils": { "editable": true, "git": "https://github.com/GSA/notifications-utils.git", - "ref": "d88d48026171991de4d8398e5f9f8c2063297885" + "ref": "4e22e22524933bf81863f4ff105268c720ea40a1" }, "numpy": { "hashes": [ @@ -971,11 +971,11 @@ }, "setuptools": { "hashes": [ - "sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab", - "sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6" + "sha256:6f590d76b713d5de4e49fe4fbca24474469f53c83632d5d0fd056f7ff7e8112b", + "sha256:ac4008d396bc9cd983ea483cb7139c0240a07bbc74ffb6232fceffedc6cf03a8" ], "markers": "python_version >= '3.7'", - "version": "==66.0.0" + "version": "==66.1.1" }, "shapely": { "hashes": [ @@ -1139,19 +1139,19 @@ }, "boto3": { "hashes": [ - "sha256:0b1f82d4565ed875c7975ac0be5665e8d948613c01bcb0e49df6d4f5af670cc8", - "sha256:319ddb274f8f83b035b88a3b127c465bf6fe3e3fc2d668869b489e992c47ca77" + "sha256:4e876ba5d64928cde0c416dd844f04f22d6b73d14002bbc3ca55591f80f49927", + "sha256:c729bb0af76e85a2776b6bd3da8d9fa0f4b91b425eab51612aa53956f644ee23" ], "markers": "python_version >= '3.7'", - "version": "==1.26.52" + "version": "==1.26.54" }, "botocore": { "hashes": [ - "sha256:a0b89a33305cfa6251c6e1142deb7567e216e37e25363159f45fb81dc5b474e5", - "sha256:de55b6333fb13c66da9055972d7e4efff5dcc5a087478a2b70e99d888b29a24c" + "sha256:ca3ef7588daa664fe196d3234718db5f6b5dab961507500b4bb921e31133eea1", + "sha256:f2fe17ed6b8e163769a715f81cb6ce3d4628d172918de535256bdf34d29b704f" ], "markers": "python_version >= '3.7'", - "version": "==1.29.52" + "version": "==1.29.54" }, "cachecontrol": { "extras": [ @@ -1335,13 +1335,6 @@ "markers": "python_full_version >= '3.6.0'", "version": "==3.0.1" }, - "commonmark": { - "hashes": [ - "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", - "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" - ], - "version": "==0.9.1" - }, "cryptography": { "hashes": [ "sha256:1a6915075c6d3a5e1215eab5d99bcec0da26036ff2102a1038401d6ef5bef25b", @@ -1501,6 +1494,14 @@ ], "version": "==0.12.2" }, + "markdown-it-py": { + "hashes": [ + "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27", + "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.0" + }, "markupsafe": { "hashes": [ "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed", @@ -1564,6 +1565,14 @@ ], "version": "==0.6.1" }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, "moto": { "hashes": [ "sha256:20607a0fd0cf6530e05ffb623ca84d3f45d50bddbcec2a33705a0cf471e71289", @@ -1671,11 +1680,11 @@ }, "pip-audit": { "hashes": [ - "sha256:3ea2fc5c70bf335362d4d81a7bd1084787efac34929e422f79bd8cf8804da2e2", - "sha256:e0c9fe070a16aefdbb9c4d43df6a0183bc951375a293f58264c5e80b5edb57d7" + "sha256:1259629fe24302e257052e977146f56bebf34927740d5efd184aaafa3b1b3b38", + "sha256:f9632b9f67bcf3fda78ef7651a03c8ed926d1eaeda474dcbdcb26a5518dd6ffc" ], "index": "pypi", - "version": "==2.4.13" + "version": "==2.4.14" }, "pip-requirements-parser": { "hashes": [ @@ -1874,11 +1883,11 @@ }, "rich": { "hashes": [ - "sha256:81c73a30b144bbcdedc13f4ea0b6ffd7fdc3b0d3cc259a9402309c8e4aee1964", - "sha256:f846bff22a43e8508aebf3f0f2410ce1c6f4cde429098bd58d91fde038c57299" + "sha256:7c963f0d03819221e9ac561e1bc866e3f95a02248c1234daa48954e6d381c003", + "sha256:f1a00cdd3eebf999a15d85ec498bfe0b1a77efe9b34f645768a54132ef444ac5" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.1.0" + "version": "==13.2.0" }, "s3transfer": { "hashes": [ @@ -1890,11 +1899,11 @@ }, "setuptools": { "hashes": [ - "sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab", - "sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6" + "sha256:6f590d76b713d5de4e49fe4fbca24474469f53c83632d5d0fd056f7ff7e8112b", + "sha256:ac4008d396bc9cd983ea483cb7139c0240a07bbc74ffb6232fceffedc6cf03a8" ], "markers": "python_version >= '3.7'", - "version": "==66.0.0" + "version": "==66.1.1" }, "six": { "hashes": [ diff --git a/manifest.yml b/manifest.yml index 5323e0785..01ec57a45 100644 --- a/manifest.yml +++ b/manifest.yml @@ -22,7 +22,7 @@ applications: NOTIFY_APP_NAME: admin NOTIFY_LOG_LEVEL: INFO FLASK_APP: application.py - FLASK_ENV: production + FLASK_DEBUG: "false" REDIS_ENABLED: ((REDIS_ENABLED)) ADMIN_BASE_URL: https://((public_admin_route)) API_HOST_NAME: https://notify-api-((env)).apps.internal:61443 diff --git a/newrelic.ini b/newrelic.ini new file mode 100644 index 000000000..63ee1ea2c --- /dev/null +++ b/newrelic.ini @@ -0,0 +1,222 @@ +# --------------------------------------------------------------------------- + +# +# This file configures the New Relic Python Agent. +# +# The path to the configuration file should be supplied to the function +# newrelic.agent.initialize() when the agent is being initialized. +# +# The configuration file follows a structure similar to what you would +# find for Microsoft Windows INI files. For further information on the +# configuration file format see the Python ConfigParser documentation at: +# +# http://docs.python.org/library/configparser.html +# +# For further discussion on the behaviour of the Python agent that can +# be configured via this configuration file see: +# +# http://newrelic.com/docs/python/python-agent-configuration +# + +# --------------------------------------------------------------------------- + +# Here are the settings that are common to all environments. + +[newrelic] + +# You must specify the license key associated with your New +# Relic account. This key binds the Python Agent's data to your +# account in the New Relic service. +# license_key is set via NEW_RELIC_LICENSE_KEY env var + +host = gov-collector.newrelic.com + +# The application name. Set this to be the name of your +# application as you would like it to show up in New Relic UI. +# The UI will then auto-map instances of your application into a +# entry on your home dashboard page. +app_name = us-notify-admin (Development) + +# New Relic offers distributed tracing for monitoring and analyzing modern +# distributed systems.Enable distributed tracing. +distributed_tracing.enabled = true + +# When "true", the agent collects performance data about your +# application and reports this data to the New Relic UI at +# newrelic.com. This global switch is normally overridden for +# each environment below. +monitor_mode = true + +# Sets the name of a file to log agent messages to. Useful for +# debugging any issues with the agent. This is not set by +# default as it is not known in advance what user your web +# application processes will run as and where they have +# permission to write to. Whatever you set this to you must +# ensure that the permissions for the containing directory and +# the file itself are correct, and that the user that your web +# application runs as can write to the file. If not able to +# write out a log file, it is also possible to say "stderr" and +# output to standard error output. This would normally result in +# output appearing in your web server log. +#log_file = /tmp/newrelic-python-agent.log + +# Sets the level of detail of messages sent to the log file, if +# a log file location has been provided. Possible values, in +# increasing order of detail, are: "critical", "error", "warning", +# "info" and "debug". When reporting any agent issues to New +# Relic technical support, the most useful setting for the +# support engineers is "debug". However, this can generate a lot +# of information very quickly, so it is best not to keep the +# agent at this level for longer than it takes to reproduce the +# problem you are experiencing. +log_level = info + +# The Python Agent communicates with the New Relic service using +# SSL by default. Note that this does result in an increase in +# CPU overhead, over and above what would occur for a non SSL +# connection, to perform the encryption involved in the SSL +# communication. This work is though done in a distinct thread +# to those handling your web requests, so it should not impact +# response times. You can if you wish revert to using a non SSL +# connection, but this will result in information being sent +# over a plain socket connection and will not be as secure. +ssl = true + +# High Security Mode enforces certain security settings, and +# prevents them from being overridden, so that no sensitive data +# is sent to New Relic. Enabling High Security Mode means that +# SSL is turned on, request parameters are not collected, and SQL +# can not be sent to New Relic in its raw form. To activate High +# Security Mode, it must be set to 'true' in this local .ini +# configuration file AND be set to 'true' in the server-side +# configuration in the New Relic user interface. For details, see +# https://docs.newrelic.com/docs/subscriptions/high-security +high_security = false + +# The Python Agent will attempt to connect directly to the New +# Relic service. If there is an intermediate firewall between +# your host and the New Relic service that requires you to use a +# HTTP proxy, then you should set both the "proxy_host" and +# "proxy_port" settings to the required values for the HTTP +# proxy. The "proxy_user" and "proxy_pass" settings should +# additionally be set if proxy authentication is implemented by +# the HTTP proxy. The "proxy_scheme" setting dictates what +# protocol scheme is used in talking to the HTTP proxy. This +# would normally always be set as "http" which will result in the +# agent then using a SSL tunnel through the HTTP proxy for end to +# end encryption. +# proxy_scheme = http +# proxy_host = hostname +# proxy_port = 8080 +# proxy_user = +# proxy_pass = + +# Capturing request parameters is off by default. To enable the +# capturing of request parameters, first ensure that the setting +# "attributes.enabled" is set to "true" (the default value), and +# then add "request.parameters.*" to the "attributes.include" +# setting. For details about attributes configuration, please +# consult the documentation. +# attributes.include = request.parameters.* + +# The transaction tracer captures deep information about slow +# transactions and sends this to the UI on a periodic basis. The +# transaction tracer is enabled by default. Set this to "false" +# to turn it off. +transaction_tracer.enabled = true + +# Threshold in seconds for when to collect a transaction trace. +# When the response time of a controller action exceeds this +# threshold, a transaction trace will be recorded and sent to +# the UI. Valid values are any positive float value, or (default) +# "apdex_f", which will use the threshold for a dissatisfying +# Apdex controller action - four times the Apdex T value. +transaction_tracer.transaction_threshold = apdex_f + +# When the transaction tracer is on, SQL statements can +# optionally be recorded. The recorder has three modes, "off" +# which sends no SQL, "raw" which sends the SQL statement in its +# original form, and "obfuscated", which strips out numeric and +# string literals. +transaction_tracer.record_sql = obfuscated + +# Threshold in seconds for when to collect stack trace for a SQL +# call. In other words, when SQL statements exceed this +# threshold, then capture and send to the UI the current stack +# trace. This is helpful for pinpointing where long SQL calls +# originate from in an application. +transaction_tracer.stack_trace_threshold = 0.5 + +# Determines whether the agent will capture query plans for slow +# SQL queries. Only supported in MySQL and PostgreSQL. Set this +# to "false" to turn it off. +transaction_tracer.explain_enabled = true + +# Threshold for query execution time below which query plans +# will not not be captured. Relevant only when "explain_enabled" +# is true. +transaction_tracer.explain_threshold = 0.5 + +# Space separated list of function or method names in form +# 'module:function' or 'module:class.function' for which +# additional function timing instrumentation will be added. +transaction_tracer.function_trace = + +# The error collector captures information about uncaught +# exceptions or logged exceptions and sends them to UI for +# viewing. The error collector is enabled by default. Set this +# to "false" to turn it off. +error_collector.enabled = true + +# To stop specific errors from reporting to the UI, set this to +# a space separated list of the Python exception type names to +# ignore. The exception name should be of the form 'module:class'. +error_collector.ignore_errors = + +# Browser monitoring is the Real User Monitoring feature of the UI. +# For those Python web frameworks that are supported, this +# setting enables the auto-insertion of the browser monitoring +# JavaScript fragments. +browser_monitoring.auto_instrument = true + +# A thread profiling session can be scheduled via the UI when +# this option is enabled. The thread profiler will periodically +# capture a snapshot of the call stack for each active thread in +# the application to construct a statistically representative +# call tree. +thread_profiler.enabled = true + +# --------------------------------------------------------------------------- + +# +# The application environments. These are specific settings which +# override the common environment settings. The settings related to a +# specific environment will be used when the environment argument to the +# newrelic.agent.initialize() function has been defined to be either +# "development", "test", "staging" or "production". +# + +[newrelic:development] +app_name = us-notify-admin (Development) + +[newrelic:test] +app_name = us-notify-admin (Test) +monitor_mode = false + +[newrelic:sandbox] +app_name = us-notify-admin (Sandbox) +monitor_mode = false + +[newrelic:staging] +app_name = us-notify-admin (Staging) +monitor_mode = true + +[newrelic:demo] +app_name = us-notify-admin (Demo) +monitor_mode = true + +[newrelic:production] +app_name = us-notify-admin +monitor_mode = true + +# --------------------------------------------------------------------------- diff --git a/sample.env b/sample.env index 5b7e99192..fc7954ba9 100644 --- a/sample.env +++ b/sample.env @@ -21,7 +21,7 @@ AWS_SECRET_ACCESS_KEY="don't write secrets to the sample file" # Application NOTIFY_ENVIRONMENT=development FLASK_APP=application.py -FLASK_ENV=development +FLASK_DEBUG=true WERKZEUG_DEBUG_PIN=off NODE_VERSION=16.15.1 @@ -35,3 +35,9 @@ NODE_VERSION=16.15.1 # Local direct setup API_HOST_NAME=http://localhost:6011 REDIS_URL=redis://localhost:6379/0 + +############################################################# + +# New Relic +NEW_RELIC_CONFIG_FILE=newrelic.ini +NEW_RELIC_LICENSE_KEY="don't write secrets to the sample file"