Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Celery #41

Merged
merged 104 commits into from Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
30494e4
Work in progress
andyneff Mar 18, 2020
9096ce9
Update vsi_common
andyneff Mar 19, 2020
04d951c
POC of celery task with settings runs
andyneff Apr 5, 2020
cd1a85a
Logging can now be reconfigured
andyneff Apr 5, 2020
c474330
Set result serializer
andyneff Apr 7, 2020
2662b62
Almost working
andyneff Apr 8, 2020
5212227
Task map translation working for POC
andyneff Apr 14, 2020
57789cf
Added zone to logger
andyneff Apr 15, 2020
4c53858
terra.zone set to task in dummy, sync, and celery executor
andyneff Apr 15, 2020
4672189
Set terra.zone for tasks universally
andyneff Apr 16, 2020
c61d107
Fix typo [ci-skip]
andyneff Apr 16, 2020
7aa1b59
Merge pull request #31 from VisionSystemsInc/terra_zone_task
andyneff Apr 16, 2020
e4ac27b
Auto translate arguments to task functions
andyneff Apr 16, 2020
e87e77f
Misc changed
andyneff Apr 17, 2020
5545d6e
Fix resetting zone on exception [skipci]
andyneff Apr 20, 2020
9baed1e
Merge pull request #32 from VisionSystemsInc/translate_kwargs
andyneff Apr 20, 2020
70b9266
Merge pull request #33 from VisionSystemsInc/task_zone_exception
andyneff Apr 20, 2020
1944ae6
Return values in celery get volume translations
andyneff Apr 21, 2020
baa16a1
Change celery executor log message levels
andyneff Apr 21, 2020
83806e0
Merge pull request #34 from VisionSystemsInc/fix_volumes_and_return
andyneff Apr 21, 2020
ed1be5e
create a simple __main__.py to start customizing celery
scott-vsi Apr 21, 2020
938bbef
Merge pull request #35 from VisionSystemsInc/scott-vsi-celery-main
scott-vsi Apr 21, 2020
2372d1d
disallow a few more characters in the randomly generated passwords
scott-vsi Apr 21, 2020
9fdad33
Handle non-string case of dict patching
andyneff Apr 21, 2020
a9bed5d
Merge pull request #37 from VisionSystemsInc/celery_worker_limit
andyneff Apr 22, 2020
4fdf927
Merge pull request #36 from VisionSystemsInc/scott-vsi-update-pwd-mask
scott-vsi Apr 22, 2020
a0eec50
fix hostname and zone logging identifiers
scott-vsi May 1, 2020
1c5b532
fix ask_question usage
scott-vsi May 1, 2020
90f743f
Disable docker-compoes's tty allocation
scott-vsi May 1, 2020
ddb29df
WIP logging from tasks and runners is sent over a TCP socket to the c…
scott-vsi May 1, 2020
ba358f2
minor modifications
scott-vsi May 1, 2020
dd628da
should still be equiv
scott-vsi May 4, 2020
9f94508
add FIXME
scott-vsi May 4, 2020
ea09e5f
update some comments; only close the socket if it exists; but things …
scott-vsi May 4, 2020
639c5b7
use signals to coordinate setting up of the logger between logger.py …
scott-vsi May 5, 2020
03dd663
add base executor
scott-vsi May 6, 2020
618a5fd
update comments
scott-vsi May 6, 2020
14dce8b
update comments
scott-vsi May 6, 2020
2c44cbc
get a stack trace when an exception happens in a celery worker
scott-vsi May 6, 2020
555187f
Add celery as a proper dependency
andyneff May 6, 2020
d329eed
Unhardcode logging server
andyneff May 6, 2020
a169977
Fix flower and redis_commander
andyneff May 8, 2020
9f613b7
Remove run redis.
andyneff May 8, 2020
439b30c
set task vs task_controller zones right
andyneff May 8, 2020
ec65c2c
Refactor some [ci-skip]
andyneff May 8, 2020
6f6e00b
Minor cleanups
andyneff May 8, 2020
ff97027
Mid fixing
andyneff May 9, 2020
b98b85e
Logging working!
andyneff May 9, 2020
9de92ca
Fixes
andyneff May 11, 2020
3e53e1c
Remove debugging prints
andyneff May 11, 2020
494a8df
Merge pull request #38 from andyneff/sgrichar-celery-alpha
andyneff May 12, 2020
6e0ba4f
Clean up celery main
andyneff May 12, 2020
95721a6
Broken
andyneff May 13, 2020
0ffc409
Added more to demo app
andyneff May 14, 2020
1fd7748
Runner logging messages with new stderr filter
andyneff May 18, 2020
eb02ec2
Finished demo app
andyneff May 19, 2020
4edae6b
Fixed other computes/executors
andyneff May 19, 2020
00f3421
Added uuid to setting dump filenames
andyneff May 20, 2020
1dbe2ba
Fixing tests executor celery
andyneff May 20, 2020
4dd0f38
Fixing tests compute docker
andyneff May 20, 2020
062370c
Fixing tests compute virtualenv/utils
andyneff May 20, 2020
be80e94
Fixing tests executor dummy
andyneff May 20, 2020
5470b5b
Fixing tests logger
andyneff May 20, 2020
df7d4b0
Fixing unit tests
andyneff May 22, 2020
391e26b
Working on Logger case
andyneff May 28, 2020
b32676d
Settings tests passing
andyneff May 28, 2020
e138787
Logging tests passing
andyneff May 28, 2020
8610871
Tests passing
andyneff May 28, 2020
370d345
Refactor tests to use common case classes
andyneff May 28, 2020
b8e79dc
Pep8
andyneff May 28, 2020
be0e0f8
Docs
andyneff Jun 1, 2020
f5e8fe9
Fix CI
andyneff Jun 1, 2020
30d51d8
Minor cleanup
andyneff Jun 1, 2020
8a7904d
Merge pull request #39 from VisionSystemsInc/sgrichar-celery-alpha
andyneff Jun 2, 2020
9987b7f
Minor cleanup
andyneff Jun 2, 2020
e9fbd35
Fixing tests
andyneff May 4, 2020
1eb80f6
Working on logging/executor mock in tests
andyneff May 6, 2020
b7fb55d
Rebase forgotten commit onto celery
andyneff Jun 2, 2020
54def9f
Pep 8
andyneff Jun 2, 2020
3eb2a84
Add warning for Thread Pool
andyneff Jun 3, 2020
fc8070d
Remove old commented code
andyneff Jun 3, 2020
806614a
Added review changes
andyneff Jun 4, 2020
dbcb59e
Fixed exceptions printing to stderr in ipython
andyneff Jun 4, 2020
90eaa92
Changed default compute
andyneff Jun 4, 2020
ac5f5bc
Added TERRA_DISABLE_SETTINGS_DUMP
andyneff Jun 4, 2020
db02b57
Added TERRA_DISABLE_TERRA_LOG
andyneff Jun 4, 2020
63057a1
Fix root logger
andyneff Jun 4, 2020
cac374f
Customized ThreadPoolExecutor _adjust_thread_count
andyneff Jun 5, 2020
7a08252
Restored ThreadPoolExecutor.py
andyneff Jun 5, 2020
1a1d1ce
Multithreaded safe settings POC working
andyneff Jun 6, 2020
6041176
Cleanup of thread safe settings
andyneff Jun 6, 2020
cdb5df3
ThreadPoolExecutor auto downcasts settings
andyneff Jun 6, 2020
4a770e9
Unittest and pep8
andyneff Jun 6, 2020
2f9af4f
Add a little doc
andyneff Jun 6, 2020
bb145a3
Added reviewed changes
andyneff Jun 8, 2020
f208f34
Merge pull request #43 from VisionSystemsInc/multithread_safe_settings
andyneff Jun 8, 2020
96d308f
Get ThreadPoolExecutor tests working again
andyneff Jun 8, 2020
504292a
Documentation fixes [ci skip]
andyneff Jun 9, 2020
b7a2590
Remove TERRA_DOCKER_RUNTIME, not a Terra var
andyneff Jun 9, 2020
2998faa
Added terra_setup
andyneff Jun 9, 2020
786719a
Updated vsi_common
andyneff Jun 9, 2020
28de71c
Oops [skip ci]
andyneff Jun 10, 2020
4549480
Restore test to no longer need a delayed import
andyneff Jun 10, 2020
3620ac2
Add README steps for terra_setup
andyneff Jun 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 24 additions & 6 deletions Justfile
Expand Up @@ -28,6 +28,12 @@ JUST_DEFAULTIFY_FUNCTIONS+=(terra_caseify)
function Terra_Pipenv()
{
if [[ ${TERRA_LOCAL-} == 1 ]]; then
if [ -n "${VIRTUAL_ENV+set}" ]; then
echo "Warning: You appear to be in a virtual env" >&2
echo "Deactivate external virtual envs before running just" >&2
ask_question "Continue?" answer_continue n
[ "$answer_continue" == "0" ] && return 1
fi
PIPENV_PIPFILE="${TERRA_CWD}/Pipfile" pipenv ${@+"${@}"} || return $?
else
Just-docker-compose -f "${TERRA_CWD}/docker-compose-main.yml" run ${TERRA_PIPENV_IMAGE-terra} pipenv ${@+"${@}"} || return $?
Expand Down Expand Up @@ -115,10 +121,6 @@ function terra_caseify()
extra_args=$#
;;

run_redis) # Run redis
Just-docker-compose -f "${TERRA_CWD}/docker-compose.yml" run redis ${@+"${@}"}
extra_args=$#
;;
run_celery) # Starts a celery worker
local node_name
if [[ ${TERRA_LOCAL-} == 1 ]]; then
Expand All @@ -127,7 +129,22 @@ function terra_caseify()
node_name="docker@%h"
fi

Terra_Pipenv run celery -A terra.executor.celery.app worker --loglevel="${TERRA_CELLER_LOG_LEVEL-INFO}" -n "${node_name}"
# Untested
if [ "${OS-}" = "Windows_NT" ]; then
# https://www.distributedpython.com/2018/08/21/celery-4-windows/
local FORKED_BY_MULTIPROCESSING
export FORKED_BY_MULTIPROCESSING=1
fi

# We might be able to use CELERY_LOADER to avoid the -A argument
Terra_Pipenv run python -m terra.executor.celery -A terra.executor.celery.app worker --loglevel="${TERRA_CELERY_LOG_LEVEL-INFO}" -n "${node_name}"
;;

run_flower) # Start the flower server
Terra_Pipenv run python -m terra.executor.celery -A terra.executor.celery.app flower
;;
shutdown_celery) # Shuts down all celery works on all nodes
andyneff marked this conversation as resolved.
Show resolved Hide resolved
Terra_Pipenv run python -c "from terra.executor.celery import app; app.control.broadcast('shutdown')"
;;

### Run Debugging containers ###
Expand Down Expand Up @@ -203,7 +220,8 @@ function terra_caseify()
terra_test-pep8) # Run pep8 test
justify terra pep8
echo "Running flake8..."
Terra_Pipenv run bash -c 'flake8 \
Terra_Pipenv run bash -c 'cd ${TERRA_TERRA_DIR};
flake8 \
"${TERRA_TERRA_DIR}/terra"'
;;

Expand Down
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -17,3 +17,13 @@ source 'setup.env'
just terra sync
just terra run
```

## Running an app in celery

1. `just terra up` - To start redis queue (only once)
2. `just run celery` - To start a celery worker (run on each worker node)
3. `just run dsm ...` - To start processing job

When done
4. `just shutdown celery` - To shutdown _all_ celery workers on _all_ nodes
5. `just terra down` - To shutdown redis.
32 changes: 19 additions & 13 deletions docker-compose-main.yml
Expand Up @@ -6,17 +6,17 @@ services:
dockerfile: docker/terra.Dockerfile
# prevent different users from clobbering each others images
image: ${TERRA_DOCKER_REPO}:terra_${TERRA_USERNAME}
environment:
environment: &terra_environment
# Variables for docker_entrypoint.bsh
- DOCKER_UID=${TERRA_UID}
- DOCKER_GIDS=${TERRA_GIDS}
- DOCKER_GROUP_NAMES=${TERRA_GROUP_NAMES}
- DOCKER_USERNAME=user
- DISPLAY
- JUSTFILE=${TERRA_TERRA_DIR_DOCKER}/docker/terra.Justfile
- JUST_SETTINGS=${TERRA_TERRA_DIR_DOCKER}/terra.env
- PYTHONPATH=${TERRA_PYTHONPATH-}
- TZ
DOCKER_UID: ${TERRA_UID}
DOCKER_GIDS: ${TERRA_GIDS}
DOCKER_GROUP_NAMES: ${TERRA_GROUP_NAMES}
DOCKER_USERNAME: user
JUSTFILE: ${TERRA_TERRA_DIR_DOCKER}/docker/terra.Justfile
JUST_SETTINGS: ${TERRA_TERRA_DIR_DOCKER}/terra.env
PYTHONPATH: ${TERRA_PYTHONPATH-}
DISPLAY:
TZ:
cap_add:
- SYS_PTRACE # Useful for gdb
volumes:
Expand All @@ -38,6 +38,12 @@ services:
source: terra-venv
target: /venv

terra-demo:
<<: *terra
environment:
<<: *terra_environment
TERRA_SETTINGS_FILE:

redis-commander:
image: rediscommander/redis-commander
ports:
Expand All @@ -46,14 +52,14 @@ services:
- source: redis_secret
target: ${TERRA_REDIS_SECRET_DOCKER}
- source: redis_commander_secret
target: ${TERRA_REDIS_COMMANDER_SECRET_FILE}
target: ${TERRA_REDIS_COMMANDER_SECRET}
command: |
sh -c '
echo -n '"'"'{
"connections":[
{
"password": "'"'"' > /redis-commander/config/local-production.json
cat /run/secrets/redis_password | sed '"'"'s|\\|\\\\|g;s|"|\\"|g'"'"' >> /redis-commander/config/local-production.json
cat /run/secrets/${TERRA_REDIS_SECRET_DOCKER} | sed '"'"'s|\\|\\\\|g;s|"|\\"|g'"'"' >> /redis-commander/config/local-production.json
echo -n '"'"'",
"host": "${TERRA_REDIS_HOSTNAME_DOCKER}",
"label": "terra",
Expand All @@ -68,7 +74,7 @@ services:
"httpAuth": {
"username": "admin",
"passwordHash": "'"'"'>> /redis-commander/config/local-production.json
cat "/run/secrets/${TERRA_REDIS_COMMANDER_SECRET_FILE}" | sed '"'"'s|\\|\\\\|g;s|"|\\"|g'"'"' >> /redis-commander/config/local-production.json
cat "/run/secrets/${TERRA_REDIS_COMMANDER_SECRET}" | sed '"'"'s|\\|\\\\|g;s|"|\\"|g'"'"' >> /redis-commander/config/local-production.json
echo '"'"'"
}
}
Expand Down
3 changes: 3 additions & 0 deletions docs/conf.py
Expand Up @@ -51,6 +51,7 @@
intersphinx_mapping = {
'python': ('https://docs.python.org/3.6', None),
'vsi_common': ('https://visionsystemsinc.github.io/vsi_common/', None),
'celery': ('https://docs.celeryproject.org/en/stable/', None)
}

# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -103,6 +104,8 @@
('py:class', 'json.encoder.JSONEncoder'),
('py:class', 'concurrent.futures._base.Executor'),
('py:class', 'concurrent.futures._base.Future'),
('py:class', 'concurrent.futures.process.ProcessPoolExecutor'),
('py:class', 'concurrent.futures.thread.ThreadPoolExecutor'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

('py:class', 'argparse._AppendAction'),
('py:data', 'logging.DEBUG'),
('py:data', 'logging.WARNING'),
Expand Down
13 changes: 13 additions & 0 deletions docs/terra/settings.rst
@@ -1,6 +1,19 @@

.. _settings:

Terra Settings
--------------

.. option:: terra.zone

Terra can be running in one of three areas of execution, or "zones": the master controller (``controller``), a service runner (``runner``), or a task (``task``). The different zones could all be running on the main host, or other containers or computers, depending on the compute and executor.

The master controller includes: the CLI, workflow, stage and service definitions layers.

This variable is automatically updated, and should only be read.

Default: ``controller``

Workflow Settings
-----------------

Expand Down
2 changes: 1 addition & 1 deletion external/vsi_common
Submodule vsi_common updated 60 files
+6 −1 .travis.yml
+8 −0 .vscode/settings.json
+3 −3 README.md
+1 −0 appveyor.yml
+1 −1 docker/recipes
+2 −0 docker/tests/bash_test.Dockerfile
+10 −11 docs/style.rst
+9 −8 linux/.just
+12 −12 linux/Just_wrap
+1 −1 linux/ask_question
+3 −3 linux/bin_utils.bsh
+1 −0 linux/circular_source.bsh
+6 −7 linux/command_tools.bsh
+9 −6 linux/container_functions.bsh
+2 −3 linux/cuda_info.bsh
+1 −1 linux/dir_tools.bsh
+6 −6 linux/docker_compose_override
+25 −19 linux/docker_functions.bsh
+3 −3 linux/elements.bsh
+4 −0 linux/file_tools.bsh
+1 −1 linux/findin
+2 −2 linux/findinpaths
+678 −0 linux/git_mirror
+4 −4 linux/git_safe_update
+1 −1 linux/group_names
+11 −4 linux/just_bashcov_functions.bsh
+1 −0 linux/just_common.bsh
+2 −2 linux/just_diff
+21 −21 linux/just_docker_functions.bsh
+25 −21 linux/just_entrypoint.sh
+13 −11 linux/just_entrypoint_functions
+7 −8 linux/just_entrypoint_user_functions.bsh
+49 −38 linux/just_functions.bsh
+74 −64 linux/just_git_functions.bsh
+5 −2 linux/just_singularity_functions.bsh
+3 −3 linux/just_sphinx_functions.bsh
+7 −1 linux/just_test_functions.bsh
+2 −2 linux/linux_accounts.bsh
+1 −1 linux/mount_tools.bsh
+14 −5 linux/new_just
+4 −4 linux/pbdb.bsh
+1 −0 linux/pipenv_functions.bsh
+1 −1 linux/quotemire
+2 −2 linux/real_path
+1 −1 linux/requirements.bsh
+1 −1 linux/set_flags.bsh
+2 −2 linux/signal_tools.bsh
+10 −13 linux/singularity_functions.bsh
+3 −3 linux/source_once.bsh
+6 −6 linux/string_tools.bsh
+4 −4 linux/time_tools.bsh
+1 −1 linux/uwecho.bsh
+9 −3 python/vsi/test/utils.py
+24 −0 python/vsi/tools/logging.py
+5 −2 python/vsi/tools/vdb_rpdb.py
+251 −0 tests/int/test-git_mirror.bsh
+6 −6 tests/quiz-testlib.bsh
+1 −1 tests/run_tests
+23 −2 tests/test-testlib.bsh
+28 −0 tests/testlib.bsh
4 changes: 3 additions & 1 deletion setup.py
Expand Up @@ -11,6 +11,8 @@
extra_requires=extra_requires,
install_requires=[
"jstyleson",
"envcontext"
"envcontext",
# I use signal and task from celery, no matter what
"celery"
]
)
12 changes: 8 additions & 4 deletions terra.env
Expand Up @@ -72,16 +72,20 @@ fi

if [[ ! -f /.dockerenv && ! -s "${TERRA_REDIS_SECRET_FILE}" ]]; then
source "${VSI_COMMON_DIR}/linux/random.bsh"
# No quotes allowed
urandom_password 20 '\x21\x23-\x26\x28-\x7E' > "${TERRA_REDIS_SECRET_FILE}"
# Allow printable ascii characters excpet quotes, ';' (for an unknown redis/celery parsing reason), ':' or '@' (for redis url reasons)
urandom_password 20 '\x21\x23-\x26\x28-\x39\x3c-\x3f\x41-\x7E' > "${TERRA_REDIS_SECRET_FILE}"
fi

#**
# .. envvar:: TERRA_CELERY_MAIN_NAME
#
# Name of the main module if running as __main__. This is used as the prefix for auto-generated task names.
# (Optional) Name of the main module if running as __main__. This is used as the prefix for auto-generated task names that are defined in the same module as ``__main__`` (Usually caused by ``python -m``). At first, python will try ``sys.modules['__main__'].__spec__.name``, before using this value, when that fails.
#
# .. envvar:: TERRA_KEEP_TEMP_DIR
#
# Optional environment variable, that when set to ``1`` will keep the temporary config files generated for containers. For debug use.
andyneff marked this conversation as resolved.
Show resolved Hide resolved
#**
: ${TERRA_CELERY_MAIN_NAME=terra}

#**
# .. envvar:: TERRA_CELERY_CONF
#
Expand Down
111 changes: 105 additions & 6 deletions terra/compute/base.py
@@ -1,8 +1,17 @@
import os

import time
import atexit
from logging import StreamHandler
from logging.handlers import SocketHandler
import threading
import warnings

from terra import settings
import terra.compute.utils
from terra.executor import Executor
from terra.logger import getLogger
from terra.logger import (
getLogger, LogRecordSocketReceiver, SkipStdErrAddFilter
)
logger = getLogger(__name__)


Expand Down Expand Up @@ -63,9 +72,6 @@ def add_volume(self, local, remote, flags=None, prefix=None,
self._validate_volume(local, remote, local_must_exist=local_must_exist)
self.volumes.append((local, remote))

def get_volume_map(self, config, service_info):
return []

def pre_run(self):
'''
A function that runs before the run service
Expand All @@ -75,7 +81,13 @@ def pre_run(self):
:class:`terra.compute.base.BaseService` is mainly responsible for handling
Executors that need a separate volume translation
'''
self.executor_configuration_map = Executor.configuration_map(self)

# The executor volume map is calculated on the host side, where all the
# information is available. For example if using docker and celery, then
# docker config need to be run to get the container volumes, and that has
# to be run on the host machine. So this is calculated here.
settings.executor.volume_map = Executor.configuration_map(self)
logger.debug4("Executor Volume map: %s", settings.executor.volume_map)

def post_run(self):
pass
Expand Down Expand Up @@ -156,6 +168,9 @@ def defaultCommand(self, service_class, *args, **kwargs):
# bind function and return it
return defaultCommand.__get__(self, type(self))

def get_volume_map(self, config, service_info):
return []

def run_service(self, *args, **kwargs):
'''
Place holder for code to run an instance in the compute. Runs
Expand All @@ -178,5 +193,89 @@ def configuration_map_service(self, service_info):

return service_info.volumes

@staticmethod
def configure_logger(sender, **kwargs):
if settings.terra.zone == 'controller':
# Setup log file for use in configure
sender._log_file = os.path.join(
settings.processing_dir,
terra.logger._SetupTerraLogger.default_log_prefix)
os.makedirs(settings.processing_dir, exist_ok=True)
sender._log_file = open(sender._log_file, 'a')
sender.main_log_handler = StreamHandler(stream=sender._log_file)
sender.root_logger.addHandler(sender.main_log_handler)

# setup the TCP socket listener
sender.tcp_logging_server = LogRecordSocketReceiver(
settings.logging.server.hostname, settings.logging.server.port)
listener_thread = threading.Thread(
target=sender.tcp_logging_server.serve_until_stopped)
listener_thread.setDaemon(True)
listener_thread.start()

# Wait up to a second, to make sure the thread started
for _ in range(1000):
if sender.tcp_logging_server.ready:
break
time.sleep(0.001)
else: # pragma: no cover
warnings.warn("TCP Logging server thread did not startup. "
"This is probably not a problem, unless logging isn't "
"working.", RuntimeWarning)

# Auto cleanup
@atexit.register
def cleanup_thread():
sender.tcp_logging_server.abort = 1
listener_thread.join(timeout=5)
if listener_thread.is_alive(): # pragma: no cover
warnings.warn("TCP Logger Server Thread did not shut down "
"gracefully. Attempting to exit anyways.",
RuntimeWarning)
elif settings.terra.zone == 'runner':
sender.main_log_handler = SocketHandler(
settings.logging.server.hostname, settings.logging.server.port)
# By default, all runners have access to the master controllers stderr,
# so there is no need for the master controller to echo out the log
# messages a second time.
sender.main_log_handler.addFilter(SkipStdErrAddFilter())
sender.root_logger.addHandler(sender.main_log_handler)

@staticmethod
def reconfigure_logger(sender, **kwargs):
# sender is logger in this case
#
# The default logging handler is a StreamHandler. This will reconfigure its
# output stream

if settings.terra.zone == 'controller':
log_file = os.path.join(
settings.processing_dir,
terra.logger._SetupTerraLogger.default_log_prefix)

# Check to see if _log_file is unset. If it is, this is due to _log_file
# being called without configure being called. While it is not important
# this work, it's more likely for unit testsing
# if not os.path.samefile(log_file, sender._log_file.name):
if getattr(sender, '_log_file', None) is not None and \
log_file != sender._log_file.name:
os.makedirs(settings.processing_dir, exist_ok=True)
sender._log_file.close()
sender._log_file = open(log_file, 'a')
elif settings.terra.zone == 'runner':
# Only if it's changed
if settings.logging.server.hostname != sender.main_log_handler.host or \
settings.logging.server.port != sender.main_log_handler.port:
# Reconnect Socket Handler
sender.main_log_handler.close()
try:
sender.root_logger.removeHandler(sender.main_log_handler)
except ValueError: # pragma: no cover
pass

sender.main_log_handler = SocketHandler(
settings.logging.server.hostname, settings.logging.server.port)
sender.root_logger.addHandler(sender.main_log_handler)


services = {}