Repository: StackStorm/st2

Issue:
Ability to filter out AUDIT logs
##### SUMMARY

Currently, the log files `/var/log/st2/st2*.log` contain all of the AUDIT log information as well as the INFO and DEBUG information. These AUDIT logs are duplicated in the `/var/log/st2/st2*.audit.log` files.

In our case the `/var/log/st2/st2scheduler.log` and `/var/log/st2/st2scheduler.log` are both 5GB in size (10GB total) in less than 24h of runtime.

We would like the ability to disable sending AUDIT logs to the `/var/log/st2/st2*.log` files since the information is duplicated anyways.

##### ISSUE TYPE
 - Feature Idea

##### STACKSTORM VERSION
```
$ st2 --version
st2 2.10.1, on Python 2.7.5
```

##### OS / ENVIRONMENT / INSTALL METHOD
```
$ uname -a
Linux nor1devssd01.dev.encore.tech 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 15 17:36:42 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.6 (Maipo)

Install method = puppet-st2
```

##### STEPS TO REPRODUCE
```
$ grep "AUDIT action" st2scheduler.log | wc -l
1447
```

##### EXPECTED RESULTS
```
$ grep "AUDIT action" st2scheduler.log | wc -l
0
```

##### ACTUAL RESULTS

I think the "chattyness" of st2scheduler could be turned down as well. Not sure the entire action and results need to be printed every time a scheduling change occurs? (maybe it does?)



Discussion:
Looking at how Python logging works, it looks like you set a "log level" and then any logs that have a HIGHER number than that value are written out. Here's the default table values:

https://docs.python.org/2/library/logging.html#logging-levels

| Level    | Numeric Value |
|----------|---------------|
| CRITICAL | 50            |
| ERROR    | 40            |
| WARNING  | 30            |
| INFO     | 20            |
| DEBUG    | 10            |
| NOT_SET  | 0             |

`AUDIT` seems to be a custom level that's defined here: https://github.com/StackStorm/st2/blob/master/st2common/st2common/log.py#L49-L50

It is set to `CRITICAL + 10`, so no matter what we change the `level` to on the logging handlers, AUDIT logs will always be written.
I agree - I encountered this issue / limitation in the past.

I will check if we can set it to a lower value and if that works (IIRC, I already tried that in the past and there were some issues so we might need a different "filter out" approach).

Resolving patch:
diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py
--- a/st2common/st2common/log.py
+++ b/st2common/st2common/log.py
@@ -46,6 +46,9 @@
     'ignore_statsd_log_messages'
 ]
 
+# NOTE: We set AUDIT to the highest log level which means AUDIT log messages will always be
+# included (e.g. also if log level is set to INFO). To avoid that, we need to explicitly filter
+# out AUDIT log level in service setup code.
 logging.AUDIT = logging.CRITICAL + 10
 logging.addLevelName(logging.AUDIT, 'AUDIT')
 
diff --git a/st2common/st2common/service_setup.py b/st2common/st2common/service_setup.py
--- a/st2common/st2common/service_setup.py
+++ b/st2common/st2common/service_setup.py
@@ -22,6 +22,7 @@
 import os
 import sys
 import traceback
+import logging as stdlib_logging
 
 from oslo_config import cfg
 
@@ -35,6 +36,7 @@
 from st2common.models.utils.profiling import enable_profiling
 from st2common import triggers
 from st2common.rbac.migrations import run_all as run_all_rbac_migrations
+from st2common.logging.filters import LogLevelFilter
 
 # Note: This is here for backward compatibility.
 # Function has been moved in a standalone module to avoid expensive in-direct
@@ -112,6 +114,20 @@ def setup(service, config, setup_db=True, register_mq_exchanges=True,
         else:
             raise e
 
+    exclude_log_levels = [stdlib_logging.AUDIT]
+    handlers = stdlib_logging.getLoggerClass().manager.root.handlers
+
+    for handler in handlers:
+        # If log level is not set to DEBUG we filter out "AUDIT" log messages. This way we avoid
+        # duplicate "AUDIT" messages in production deployments where default service log level is
+        # set to "INFO" and we already log messages with level AUDIT to a special dedicated log
+        # file.
+        ignore_audit_log_messages = (handler.level >= stdlib_logging.INFO and
+                                     handler.level < stdlib_logging.AUDIT)
+        if not is_debug_enabled and ignore_audit_log_messages:
+            LOG.debug('Excluding log messages with level "AUDIT" for handler "%s"' % (handler))
+            handler.addFilter(LogLevelFilter(log_levels=exclude_log_levels))
+
     if not is_debug_enabled:
         # NOTE: statsd logger logs everything by default under INFO so we ignore those log
         # messages unless verbose / debug mode is used


Test patch:
diff --git a/st2common/tests/integration/test_service_setup_log_level_filtering.py b/st2common/tests/integration/test_service_setup_log_level_filtering.py
new file mode 100644
--- /dev/null
+++ b/st2common/tests/integration/test_service_setup_log_level_filtering.py
@@ -0,0 +1,123 @@
+# Licensed to the StackStorm, Inc ('StackStorm') under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+
+import os
+import sys
+import signal
+
+import eventlet
+from eventlet.green import subprocess
+
+from st2tests.base import IntegrationTestCase
+from st2tests.fixturesloader import get_fixtures_base_path
+
+__all__ = [
+    'ServiceSetupLogLevelFilteringTestCase'
+]
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
+FIXTURES_DIR = get_fixtures_base_path()
+
+ST2_CONFIG_INFO_LL_PATH = os.path.join(FIXTURES_DIR, 'conf/st2.tests.api.info_log_level.conf')
+ST2_CONFIG_INFO_LL_PATH = os.path.abspath(ST2_CONFIG_INFO_LL_PATH)
+
+ST2_CONFIG_DEBUG_LL_PATH = os.path.join(FIXTURES_DIR, 'conf/st2.tests.api.debug_log_level.conf')
+ST2_CONFIG_DEBUG_LL_PATH = os.path.abspath(ST2_CONFIG_DEBUG_LL_PATH)
+
+ST2_CONFIG_AUDIT_LL_PATH = os.path.join(FIXTURES_DIR, 'conf/st2.tests.api.audit_log_level.conf')
+ST2_CONFIG_AUDIT_LL_PATH = os.path.abspath(ST2_CONFIG_AUDIT_LL_PATH)
+
+ST2_CONFIG_SYSTEM_DEBUG_PATH = os.path.join(FIXTURES_DIR,
+                                            'conf/st2.tests.api.system_debug_true.conf')
+ST2_CONFIG_SYSTEM_DEBUG_PATH = os.path.abspath(ST2_CONFIG_SYSTEM_DEBUG_PATH)
+
+PYTHON_BINARY = sys.executable
+
+ST2API_BINARY = os.path.join(BASE_DIR, '../../../st2api/bin/st2api')
+ST2API_BINARY = os.path.abspath(ST2API_BINARY)
+
+CMD = [PYTHON_BINARY, ST2API_BINARY, '--config-file']
+
+
+class ServiceSetupLogLevelFilteringTestCase(IntegrationTestCase):
+    def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self):
+        # 1. INFO log level - audit messages should not be included
+        process = self._start_process(config_path=ST2_CONFIG_INFO_LL_PATH)
+        self.add_process(process=process)
+
+        # Give it some time to start up
+        eventlet.sleep(3)
+        process.send_signal(signal.SIGKILL)
+
+        # First 3 log lines are debug messages about the environment which are always logged
+        stdout = '\n'.join(process.stdout.read().decode('utf-8').split('\n')[3:])
+
+        self.assertTrue('INFO [-]' in stdout)
+        self.assertTrue('DEBUG [-]' not in stdout)
+        self.assertTrue('AUDIT [-]' not in stdout)
+
+        # 2. DEBUG log level - audit messages should be included
+        process = self._start_process(config_path=ST2_CONFIG_DEBUG_LL_PATH)
+        self.add_process(process=process)
+
+        # Give it some time to start up
+        eventlet.sleep(5)
+        process.send_signal(signal.SIGKILL)
+
+        # First 3 log lines are debug messages about the environment which are always logged
+        stdout = '\n'.join(process.stdout.read().decode('utf-8').split('\n')[3:])
+
+        self.assertTrue('INFO [-]' in stdout)
+        self.assertTrue('DEBUG [-]' in stdout)
+        self.assertTrue('AUDIT [-]' in stdout)
+
+        # 3. AUDIT log level - audit messages should be included
+        process = self._start_process(config_path=ST2_CONFIG_AUDIT_LL_PATH)
+        self.add_process(process=process)
+
+        # Give it some time to start up
+        eventlet.sleep(5)
+        process.send_signal(signal.SIGKILL)
+
+        # First 3 log lines are debug messages about the environment which are always logged
+        stdout = '\n'.join(process.stdout.read().decode('utf-8').split('\n')[3:])
+
+        self.assertTrue('INFO [-]' not in stdout)
+        self.assertTrue('DEBUG [-]' not in stdout)
+        self.assertTrue('AUDIT [-]' in stdout)
+
+        # 2. INFO log level but system.debug set to True
+        process = self._start_process(config_path=ST2_CONFIG_SYSTEM_DEBUG_PATH)
+        self.add_process(process=process)
+
+        # Give it some time to start up
+        eventlet.sleep(5)
+        process.send_signal(signal.SIGKILL)
+
+        # First 3 log lines are debug messages about the environment which are always logged
+        stdout = '\n'.join(process.stdout.read().decode('utf-8').split('\n')[3:])
+
+        self.assertTrue('INFO [-]' in stdout)
+        self.assertTrue('DEBUG [-]' in stdout)
+        self.assertTrue('AUDIT [-]' in stdout)
+
+    def _start_process(self, config_path):
+        cmd = CMD + [config_path]
+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                                   shell=False, preexec_fn=os.setsid)
+        return process
diff --git a/st2tests/st2tests/fixtures/conf/st2.tests.api.audit_log_level.conf b/st2tests/st2tests/fixtures/conf/st2.tests.api.audit_log_level.conf
new file mode 100644
--- /dev/null
+++ b/st2tests/st2tests/fixtures/conf/st2.tests.api.audit_log_level.conf
@@ -0,0 +1,99 @@
+# Config file used by integration tests
+
+[database]
+db_name = st2-test
+
+[api]
+# Host and port to bind the API server.
+host = 127.0.0.1
+port = 9101
+logging = st2tests/st2tests/fixtures/conf/logging.api.audit.conf
+mask_secrets = False
+# allow_origin is required for handling CORS in st2 web UI.
+# allow_origin = http://myhost1.example.com:3000,http://myhost2.example.com:3000
+
+[sensorcontainer]
+logging = st2tests/conf/logging.sensorcontainer.conf
+sensor_node_name = sensornode1
+partition_provider = name:default
+
+[rulesengine]
+logging = st2reactor/conf/logging.rulesengine.conf
+
+[timersengine]
+logging = st2reactor/conf/logging.timersengine.conf
+
+[actionrunner]
+logging = st2actions/conf/logging.conf
+
+[auth]
+host = 127.0.0.1
+port = 9100
+use_ssl = False
+debug = False
+enable = False
+logging = st2tests/conf/logging.auth.conf
+
+mode = standalone
+backend = flat_file
+backend_kwargs = {"file_path": "st2auth/conf/htpasswd_dev"}
+
+# Base URL to the API endpoint excluding the version (e.g. http://myhost.net:9101/)
+api_url = http://127.0.0.1:9101/
+
+[system]
+debug = False
+# This way integration tests can write to this directory
+base_path = /tmp
+
+[garbagecollector]
+logging = st2reactor/conf/logging.garbagecollector.conf
+
+action_executions_ttl = 20
+action_executions_output_ttl = 10
+trigger_instances_ttl = 20
+purge_inquiries = True
+
+collection_interval = 1
+sleep_delay = 0.1
+
+[content]
+system_packs_base_path =
+packs_base_paths = st2tests/st2tests/fixtures/packs/
+
+[syslog]
+host = 127.0.0.1
+port = 514
+facility = local7
+protocol = udp
+
+[webui]
+# webui_base_url = https://mywebhost.domain
+
+[log]
+excludes = requests,paramiko
+redirect_stderr = False
+mask_secrets = False
+
+[system_user]
+user = stanley
+ssh_key_file = /home/vagrant/.ssh/stanley_rsa
+
+[messaging]
+url = amqp://guest:guest@127.0.0.1:5672/
+
+[ssh_runner]
+remote_dir = /tmp
+
+[resultstracker]
+logging = st2actions/conf/logging.resultstracker.conf
+query_interval = 0.1
+
+[notifier]
+logging = st2actions/conf/logging.notifier.conf
+
+[exporter]
+logging = st2exporter/conf/logging.exporter.conf
+
+[mistral]
+jitter_interval = 0
diff --git a/st2tests/st2tests/fixtures/conf/st2.tests.api.debug_log_level.conf b/st2tests/st2tests/fixtures/conf/st2.tests.api.debug_log_level.conf
new file mode 100644
--- /dev/null
+++ b/st2tests/st2tests/fixtures/conf/st2.tests.api.debug_log_level.conf
@@ -0,0 +1,99 @@
+# Config file used by integration tests
+
+[database]
+db_name = st2-test
+
+[api]
+# Host and port to bind the API server.
+host = 127.0.0.1
+port = 9101
+logging = st2tests/st2tests/fixtures/conf/logging.api.debug.conf
+mask_secrets = False
+# allow_origin is required for handling CORS in st2 web UI.
+# allow_origin = http://myhost1.example.com:3000,http://myhost2.example.com:3000
+
+[sensorcontainer]
+logging = st2tests/conf/logging.sensorcontainer.conf
+sensor_node_name = sensornode1
+partition_provider = name:default
+
+[rulesengine]
+logging = st2reactor/conf/logging.rulesengine.conf
+
+[timersengine]
+logging = st2reactor/conf/logging.timersengine.conf
+
+[actionrunner]
+logging = st2actions/conf/logging.conf
+
+[auth]
+host = 127.0.0.1
+port = 9100
+use_ssl = False
+debug = False
+enable = False
+logging = st2tests/conf/logging.auth.conf
+
+mode = standalone
+backend = flat_file
+backend_kwargs = {"file_path": "st2auth/conf/htpasswd_dev"}
+
+# Base URL to the API endpoint excluding the version (e.g. http://myhost.net:9101/)
+api_url = http://127.0.0.1:9101/
+
+[system]
+debug = False
+# This way integration tests can write to this directory
+base_path = /tmp
+
+[garbagecollector]
+logging = st2reactor/conf/logging.garbagecollector.conf
+
+action_executions_ttl = 20
+action_executions_output_ttl = 10
+trigger_instances_ttl = 20
+purge_inquiries = True
+
+collection_interval = 1
+sleep_delay = 0.1
+
+[content]
+system_packs_base_path =
+packs_base_paths = st2tests/st2tests/fixtures/packs/
+
+[syslog]
+host = 127.0.0.1
+port = 514
+facility = local7
+protocol = udp
+
+[webui]
+# webui_base_url = https://mywebhost.domain
+
+[log]
+excludes = requests,paramiko
+redirect_stderr = False
+mask_secrets = False
+
+[system_user]
+user = stanley
+ssh_key_file = /home/vagrant/.ssh/stanley_rsa
+
+[messaging]
+url = amqp://guest:guest@127.0.0.1:5672/
+
+[ssh_runner]
+remote_dir = /tmp
+
+[resultstracker]
+logging = st2actions/conf/logging.resultstracker.conf
+query_interval = 0.1
+
+[notifier]
+logging = st2actions/conf/logging.notifier.conf
+
+[exporter]
+logging = st2exporter/conf/logging.exporter.conf
+
+[mistral]
+jitter_interval = 0
diff --git a/st2tests/st2tests/fixtures/conf/st2.tests.api.info_log_level.conf b/st2tests/st2tests/fixtures/conf/st2.tests.api.info_log_level.conf
new file mode 100644
--- /dev/null
+++ b/st2tests/st2tests/fixtures/conf/st2.tests.api.info_log_level.conf
@@ -0,0 +1,99 @@
+# Config file used by integration tests
+
+[database]
+db_name = st2-test
+
+[api]
+# Host and port to bind the API server.
+host = 127.0.0.1
+port = 9101
+logging = st2tests/st2tests/fixtures/conf/logging.api.info.conf
+mask_secrets = False
+# allow_origin is required for handling CORS in st2 web UI.
+# allow_origin = http://myhost1.example.com:3000,http://myhost2.example.com:3000
+
+[sensorcontainer]
+logging = st2tests/conf/logging.sensorcontainer.conf
+sensor_node_name = sensornode1
+partition_provider = name:default
+
+[rulesengine]
+logging = st2reactor/conf/logging.rulesengine.conf
+
+[timersengine]
+logging = st2reactor/conf/logging.timersengine.conf
+
+[actionrunner]
+logging = st2actions/conf/logging.conf
+
+[auth]
+host = 127.0.0.1
+port = 9100
+use_ssl = False
+debug = False
+enable = False
+logging = st2tests/conf/logging.auth.conf
+
+mode = standalone
+backend = flat_file
+backend_kwargs = {"file_path": "st2auth/conf/htpasswd_dev"}
+
+# Base URL to the API endpoint excluding the version (e.g. http://myhost.net:9101/)
+api_url = http://127.0.0.1:9101/
+
+[system]
+debug = False
+# This way integration tests can write to this directory
+base_path = /tmp
+
+[garbagecollector]
+logging = st2reactor/conf/logging.garbagecollector.conf
+
+action_executions_ttl = 20
+action_executions_output_ttl = 10
+trigger_instances_ttl = 20
+purge_inquiries = True
+
+collection_interval = 1
+sleep_delay = 0.1
+
+[content]
+system_packs_base_path =
+packs_base_paths = st2tests/st2tests/fixtures/packs/
+
+[syslog]
+host = 127.0.0.1
+port = 514
+facility = local7
+protocol = udp
+
+[webui]
+# webui_base_url = https://mywebhost.domain
+
+[log]
+excludes = requests,paramiko
+redirect_stderr = False
+mask_secrets = False
+
+[system_user]
+user = stanley
+ssh_key_file = /home/vagrant/.ssh/stanley_rsa
+
+[messaging]
+url = amqp://guest:guest@127.0.0.1:5672/
+
+[ssh_runner]
+remote_dir = /tmp
+
+[resultstracker]
+logging = st2actions/conf/logging.resultstracker.conf
+query_interval = 0.1
+
+[notifier]
+logging = st2actions/conf/logging.notifier.conf
+
+[exporter]
+logging = st2exporter/conf/logging.exporter.conf
+
+[mistral]
+jitter_interval = 0
diff --git a/st2tests/st2tests/fixtures/conf/st2.tests.api.system_debug_true.conf b/st2tests/st2tests/fixtures/conf/st2.tests.api.system_debug_true.conf
new file mode 100644
--- /dev/null
+++ b/st2tests/st2tests/fixtures/conf/st2.tests.api.system_debug_true.conf
@@ -0,0 +1,99 @@
+# Config file used by integration tests
+
+[database]
+db_name = st2-test
+
+[api]
+# Host and port to bind the API server.
+host = 127.0.0.1
+port = 9101
+logging = st2tests/st2tests/fixtures/conf/logging.api.info.conf
+mask_secrets = False
+# allow_origin is required for handling CORS in st2 web UI.
+# allow_origin = http://myhost1.example.com:3000,http://myhost2.example.com:3000
+
+[sensorcontainer]
+logging = st2tests/conf/logging.sensorcontainer.conf
+sensor_node_name = sensornode1
+partition_provider = name:default
+
+[rulesengine]
+logging = st2reactor/conf/logging.rulesengine.conf
+
+[timersengine]
+logging = st2reactor/conf/logging.timersengine.conf
+
+[actionrunner]
+logging = st2actions/conf/logging.conf
+
+[auth]
+host = 127.0.0.1
+port = 9100
+use_ssl = False
+debug = False
+enable = False
+logging = st2tests/conf/logging.auth.conf
+
+mode = standalone
+backend = flat_file
+backend_kwargs = {"file_path": "st2auth/conf/htpasswd_dev"}
+
+# Base URL to the API endpoint excluding the version (e.g. http://myhost.net:9101/)
+api_url = http://127.0.0.1:9101/
+
+[system]
+debug = True
+# This way integration tests can write to this directory
+base_path = /tmp
+
+[garbagecollector]
+logging = st2reactor/conf/logging.garbagecollector.conf
+
+action_executions_ttl = 20
+action_executions_output_ttl = 10
+trigger_instances_ttl = 20
+purge_inquiries = True
+
+collection_interval = 1
+sleep_delay = 0.1
+
+[content]
+system_packs_base_path =
+packs_base_paths = st2tests/st2tests/fixtures/packs/
+
+[syslog]
+host = 127.0.0.1
+port = 514
+facility = local7
+protocol = udp
+
+[webui]
+# webui_base_url = https://mywebhost.domain
+
+[log]
+excludes = requests,paramiko
+redirect_stderr = False
+mask_secrets = False
+
+[system_user]
+user = stanley
+ssh_key_file = /home/vagrant/.ssh/stanley_rsa
+
+[messaging]
+url = amqp://guest:guest@127.0.0.1:5672/
+
+[ssh_runner]
+remote_dir = /tmp
+
+[resultstracker]
+logging = st2actions/conf/logging.resultstracker.conf
+query_interval = 0.1
+
+[notifier]
+logging = st2actions/conf/logging.notifier.conf
+
+[exporter]
+logging = st2exporter/conf/logging.exporter.conf
+
+[mistral]
+jitter_interval = 0
diff --git a/st2tests/st2tests/fixtures/conf/st2.tests.conf b/st2tests/st2tests/fixtures/conf/st2.tests.conf
new file mode 100644
--- /dev/null
+++ b/st2tests/st2tests/fixtures/conf/st2.tests.conf
@@ -0,0 +1,100 @@
+# Config file used by integration tests
+
+[database]
+db_name = st2-test
+
+[api]
+# Host and port to bind the API server.
+host = 127.0.0.1
+port = 9101
+logging = st2tests/conf/logging.api.conf
+mask_secrets = False
+# allow_origin is required for handling CORS in st2 web UI.
+# allow_origin = http://myhost1.example.com:3000,http://myhost2.example.com:3000
+
+[sensorcontainer]
+logging = st2tests/conf/logging.sensorcontainer.conf
+sensor_node_name = sensornode1
+partition_provider = name:default
+
+[rulesengine]
+logging = st2reactor/conf/logging.rulesengine.conf
+
+[timersengine]
+logging = st2reactor/conf/logging.timersengine.conf
+
+[actionrunner]
+logging = st2actions/conf/logging.conf
+
+[auth]
+host = 127.0.0.1
+port = 9100
+use_ssl = False
+debug = False
+enable = False
+logging = st2tests/conf/logging.auth.conf
+
+mode = standalone
+backend = flat_file
+backend_kwargs = {"file_path": "st2auth/conf/htpasswd_dev"}
+
+# Base URL to the API endpoint excluding the version (e.g. http://myhost.net:9101/)
+api_url = http://127.0.0.1:9101/
+
+[system]
+debug = False
+
+# This way integration tests can write to this directory
+base_path = /tmp
+
+[garbagecollector]
+logging = st2reactor/conf/logging.garbagecollector.conf
+
+action_executions_ttl = 20
+action_executions_output_ttl = 10
+trigger_instances_ttl = 20
+purge_inquiries = True
+
+collection_interval = 1
+sleep_delay = 0.1
+
+[content]
+system_packs_base_path =
+packs_base_paths = st2tests/st2tests/fixtures/packs/
+
+[syslog]
+host = 127.0.0.1
+port = 514
+facility = local7
+protocol = udp
+
+[webui]
+# webui_base_url = https://mywebhost.domain
+
+[log]
+excludes = requests,paramiko
+redirect_stderr = False
+mask_secrets = False
+
+[system_user]
+user = stanley
+ssh_key_file = /home/vagrant/.ssh/stanley_rsa
+
+[messaging]
+url = amqp://guest:guest@127.0.0.1:5672/
+
+[ssh_runner]
+remote_dir = /tmp
+
+[resultstracker]
+logging = st2actions/conf/logging.resultstracker.conf
+query_interval = 0.1
+
+[notifier]
+logging = st2actions/conf/logging.notifier.conf
+
+[exporter]
+logging = st2exporter/conf/logging.exporter.conf
+
+[mistral]
+jitter_interval = 0