python specific app setting logs added (#1353)
* python specific app setting logs added * lint * refactor * codeowner * manual convert dict to string * moved to utils, more efficient * added to old tests, created new * addressing comments * fixing tests, efficiency * python worker ext * removed comma * FLAKE --------- Co-authored-by: Varad Meru <vrdmr@users.noreply.github.com>
This commit is contained in:
Родитель
d4200f8669
Коммит
56f5caf097
|
@ -10,4 +10,4 @@
|
||||||
# For all file changes, github would automatically
|
# For all file changes, github would automatically
|
||||||
# include the following people in the PRs.
|
# include the following people in the PRs.
|
||||||
|
|
||||||
* @vrdmr @gavin-aguiar @YunchuWang @pdthummar
|
* @vrdmr @gavin-aguiar @YunchuWang @pdthummar @hallvictoria
|
||||||
|
|
|
@ -21,16 +21,19 @@ import grpc
|
||||||
|
|
||||||
from . import bindings, constants, functions, loader, protos
|
from . import bindings, constants, functions, loader, protos
|
||||||
from .bindings.shared_memory_data_transfer import SharedMemoryManager
|
from .bindings.shared_memory_data_transfer import SharedMemoryManager
|
||||||
from .constants import (PYTHON_THREADPOOL_THREAD_COUNT,
|
from .constants import (PYTHON_ROLLBACK_CWD_PATH,
|
||||||
|
PYTHON_THREADPOOL_THREAD_COUNT,
|
||||||
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
|
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
|
||||||
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37,
|
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37,
|
||||||
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
|
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
|
||||||
PYTHON_ENABLE_DEBUG_LOGGING, SCRIPT_FILE_NAME,
|
PYTHON_ENABLE_DEBUG_LOGGING,
|
||||||
|
SCRIPT_FILE_NAME,
|
||||||
PYTHON_LANGUAGE_RUNTIME, CUSTOMER_PACKAGES_PATH)
|
PYTHON_LANGUAGE_RUNTIME, CUSTOMER_PACKAGES_PATH)
|
||||||
from .extension import ExtensionManager
|
from .extension import ExtensionManager
|
||||||
from .logging import disable_console_logging, enable_console_logging
|
from .logging import disable_console_logging, enable_console_logging
|
||||||
from .logging import (logger, error_logger, is_system_log_category,
|
from .logging import (logger, error_logger, is_system_log_category,
|
||||||
CONSOLE_LOG_PREFIX, format_exception)
|
CONSOLE_LOG_PREFIX, format_exception)
|
||||||
|
from .utils.app_setting_manager import get_python_appsetting_state
|
||||||
from .utils.common import get_app_setting, is_envvar_true
|
from .utils.common import get_app_setting, is_envvar_true
|
||||||
from .utils.dependency import DependencyManager
|
from .utils.dependency import DependencyManager
|
||||||
from .utils.tracing import marshall_exception_trace
|
from .utils.tracing import marshall_exception_trace
|
||||||
|
@ -265,11 +268,14 @@ class Dispatcher(metaclass=DispatcherMeta):
|
||||||
'python version %s, '
|
'python version %s, '
|
||||||
'worker version %s, '
|
'worker version %s, '
|
||||||
'request ID %s.'
|
'request ID %s.'
|
||||||
|
'App Settings state: %s.'
|
||||||
' To enable debug level logging, please refer to '
|
' To enable debug level logging, please refer to '
|
||||||
'https://aka.ms/python-enable-debug-logging',
|
'https://aka.ms/python-enable-debug-logging',
|
||||||
sys.version,
|
sys.version,
|
||||||
VERSION,
|
VERSION,
|
||||||
self.request_id)
|
self.request_id,
|
||||||
|
get_python_appsetting_state()
|
||||||
|
)
|
||||||
|
|
||||||
worker_init_request = request.worker_init_request
|
worker_init_request = request.worker_init_request
|
||||||
host_capabilities = worker_init_request.capabilities
|
host_capabilities = worker_init_request.capabilities
|
||||||
|
@ -546,9 +552,11 @@ class Dispatcher(metaclass=DispatcherMeta):
|
||||||
try:
|
try:
|
||||||
logger.info('Received FunctionEnvironmentReloadRequest, '
|
logger.info('Received FunctionEnvironmentReloadRequest, '
|
||||||
'request ID: %s,'
|
'request ID: %s,'
|
||||||
|
'App Settings state: %s.'
|
||||||
' To enable debug level logging, please refer to '
|
' To enable debug level logging, please refer to '
|
||||||
'https://aka.ms/python-enable-debug-logging',
|
'https://aka.ms/python-enable-debug-logging',
|
||||||
self.request_id)
|
self.request_id,
|
||||||
|
get_python_appsetting_state())
|
||||||
|
|
||||||
func_env_reload_request = \
|
func_env_reload_request = \
|
||||||
request.function_environment_reload_request
|
request.function_environment_reload_request
|
||||||
|
@ -689,7 +697,7 @@ class Dispatcher(metaclass=DispatcherMeta):
|
||||||
name, directory, invoc_request.invocation_id,
|
name, directory, invoc_request.invocation_id,
|
||||||
_invocation_id_local, trace_context, retry_context)
|
_invocation_id_local, trace_context, retry_context)
|
||||||
|
|
||||||
@disable_feature_by(constants.PYTHON_ROLLBACK_CWD_PATH)
|
@disable_feature_by(PYTHON_ROLLBACK_CWD_PATH)
|
||||||
def _change_cwd(self, new_cwd: str):
|
def _change_cwd(self, new_cwd: str):
|
||||||
if os.path.exists(new_cwd):
|
if os.path.exists(new_cwd):
|
||||||
os.chdir(new_cwd)
|
os.chdir(new_cwd)
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from ..constants import (PYTHON_ROLLBACK_CWD_PATH,
|
||||||
|
PYTHON_THREADPOOL_THREAD_COUNT,
|
||||||
|
PYTHON_ISOLATE_WORKER_DEPENDENCIES,
|
||||||
|
PYTHON_ENABLE_WORKER_EXTENSIONS,
|
||||||
|
PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT,
|
||||||
|
PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT_39,
|
||||||
|
PYTHON_ENABLE_DEBUG_LOGGING,
|
||||||
|
FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED)
|
||||||
|
|
||||||
|
|
||||||
|
def get_python_appsetting_state():
|
||||||
|
current_vars = os.environ.copy()
|
||||||
|
python_specific_settings = \
|
||||||
|
[PYTHON_ROLLBACK_CWD_PATH,
|
||||||
|
PYTHON_THREADPOOL_THREAD_COUNT,
|
||||||
|
PYTHON_ISOLATE_WORKER_DEPENDENCIES,
|
||||||
|
PYTHON_ENABLE_DEBUG_LOGGING,
|
||||||
|
PYTHON_ENABLE_WORKER_EXTENSIONS,
|
||||||
|
FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED]
|
||||||
|
|
||||||
|
app_setting_states = "".join(
|
||||||
|
f"{app_setting}: {current_vars[app_setting]} "
|
||||||
|
for app_setting in python_specific_settings
|
||||||
|
if app_setting in current_vars
|
||||||
|
)
|
||||||
|
|
||||||
|
# Special case for extensions
|
||||||
|
if 'PYTHON_ENABLE_WORKER_EXTENSIONS' not in current_vars:
|
||||||
|
if sys.version_info.minor == 9:
|
||||||
|
app_setting_states += \
|
||||||
|
(f"{PYTHON_ENABLE_WORKER_EXTENSIONS}: "
|
||||||
|
f"{str(PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT_39)}")
|
||||||
|
else:
|
||||||
|
app_setting_states += \
|
||||||
|
(f"{PYTHON_ENABLE_WORKER_EXTENSIONS}: "
|
||||||
|
f"{str(PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT)} ")
|
||||||
|
|
||||||
|
return app_setting_states
|
|
@ -0,0 +1,93 @@
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
import collections as col
|
||||||
|
import os
|
||||||
|
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from tests.utils import testutils
|
||||||
|
from azure_functions_worker.utils.app_setting_manager import \
|
||||||
|
get_python_appsetting_state
|
||||||
|
from azure_functions_worker.constants import PYTHON_THREADPOOL_THREAD_COUNT, \
|
||||||
|
PYTHON_ENABLE_DEBUG_LOGGING
|
||||||
|
|
||||||
|
SysVersionInfo = col.namedtuple("VersionInfo", ["major", "minor", "micro",
|
||||||
|
"releaselevel", "serial"])
|
||||||
|
DISPATCHER_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / 'dispatcher_functions'
|
||||||
|
DISPATCHER_STEIN_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
|
||||||
|
'dispatcher_functions' / \
|
||||||
|
'dispatcher_functions_stein'
|
||||||
|
DISPATCHER_STEIN_INVALID_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
|
||||||
|
'broken_functions' / \
|
||||||
|
'invalid_stein'
|
||||||
|
|
||||||
|
|
||||||
|
class TestDefaultAppSettingsLogs(testutils.AsyncTestCase):
|
||||||
|
"""Tests for default app settings logs."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls._ctrl = testutils.start_mockhost(
|
||||||
|
script_root=DISPATCHER_FUNCTIONS_DIR)
|
||||||
|
os_environ = os.environ.copy()
|
||||||
|
cls._patch_environ = patch.dict('os.environ', os_environ)
|
||||||
|
cls._patch_environ.start()
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
super().tearDownClass()
|
||||||
|
cls._patch_environ.stop()
|
||||||
|
|
||||||
|
async def test_initialize_worker_logging(self):
|
||||||
|
"""Test if the dispatcher's log can be flushed out during worker
|
||||||
|
initialization
|
||||||
|
"""
|
||||||
|
async with self._ctrl as host:
|
||||||
|
r = await host.init_worker('3.0.12345')
|
||||||
|
self.assertTrue('App Settings state: ' in log for log in r.logs)
|
||||||
|
self.assertTrue('PYTHON_ENABLE_WORKER_EXTENSIONS: '
|
||||||
|
in log for log in r.logs)
|
||||||
|
|
||||||
|
def test_get_python_appsetting_state(self):
|
||||||
|
app_setting_state = get_python_appsetting_state()
|
||||||
|
expected_string = "PYTHON_ENABLE_WORKER_EXTENSIONS: "
|
||||||
|
self.assertIn(expected_string, app_setting_state)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNonDefaultAppSettingsLogs(testutils.AsyncTestCase):
|
||||||
|
"""Tests for non-default app settings logs."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls._ctrl = testutils.start_mockhost(
|
||||||
|
script_root=DISPATCHER_FUNCTIONS_DIR)
|
||||||
|
os_environ = os.environ.copy()
|
||||||
|
os_environ[PYTHON_THREADPOOL_THREAD_COUNT] = '20'
|
||||||
|
os_environ[PYTHON_ENABLE_DEBUG_LOGGING] = '1'
|
||||||
|
cls._patch_environ = patch.dict('os.environ', os_environ)
|
||||||
|
cls._patch_environ.start()
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
super().tearDownClass()
|
||||||
|
cls._patch_environ.stop()
|
||||||
|
|
||||||
|
async def test_initialize_worker_logging(self):
|
||||||
|
"""Test if the dispatcher's log can be flushed out during worker
|
||||||
|
initialization
|
||||||
|
"""
|
||||||
|
async with self._ctrl as host:
|
||||||
|
r = await host.init_worker('3.0.12345')
|
||||||
|
self.assertTrue('App Settings state: ' in log for log in r.logs)
|
||||||
|
self.assertTrue('PYTHON_THREADPOOL_THREAD_COUNT: '
|
||||||
|
in log for log in r.logs)
|
||||||
|
self.assertTrue('PYTHON_ENABLE_DEBUG_LOGGING: '
|
||||||
|
in log for log in r.logs)
|
||||||
|
|
||||||
|
def test_get_python_appsetting_state(self):
|
||||||
|
app_setting_state = get_python_appsetting_state()
|
||||||
|
self.assertIn("PYTHON_THREADPOOL_THREAD_COUNT: 20 ", app_setting_state)
|
||||||
|
self.assertIn("PYTHON_ENABLE_DEBUG_LOGGING: 1 ", app_setting_state)
|
||||||
|
self.assertIn("PYTHON_ENABLE_WORKER_EXTENSIONS: ", app_setting_state)
|
|
@ -98,6 +98,15 @@ class TestThreadPoolSettingsPython37(testutils.AsyncTestCase):
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_dispatcher_initialize_worker_settings_logs(self):
|
||||||
|
"""Test if the dispatcher's log can be flushed out during worker
|
||||||
|
initialization
|
||||||
|
"""
|
||||||
|
async with self._ctrl as host:
|
||||||
|
r = await host.init_worker('3.0.12345')
|
||||||
|
self.assertTrue('PYTHON_ENABLE_WORKER_EXTENSIONS: '
|
||||||
|
in log for log in r.logs)
|
||||||
|
|
||||||
async def test_dispatcher_environment_reload_logging(self):
|
async def test_dispatcher_environment_reload_logging(self):
|
||||||
"""Test if the sync threadpool will pick up app setting in placeholder
|
"""Test if the sync threadpool will pick up app setting in placeholder
|
||||||
mode (Linux Consumption)
|
mode (Linux Consumption)
|
||||||
|
@ -115,6 +124,19 @@ class TestThreadPoolSettingsPython37(testutils.AsyncTestCase):
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_dispatcher_environment_reload_settings_logs(self):
|
||||||
|
"""Test if the sync threadpool will pick up app setting in placeholder
|
||||||
|
mode (Linux Consumption)
|
||||||
|
"""
|
||||||
|
async with self._ctrl as host:
|
||||||
|
await host.init_worker()
|
||||||
|
await self._check_if_function_is_ok(host)
|
||||||
|
|
||||||
|
# Reload environment variable on specialization
|
||||||
|
r = await host.reload_environment(environment={})
|
||||||
|
self.assertTrue('PYTHON_ENABLE_WORKER_EXTENSIONS: '
|
||||||
|
in log for log in r.logs)
|
||||||
|
|
||||||
async def test_dispatcher_send_worker_request(self):
|
async def test_dispatcher_send_worker_request(self):
|
||||||
"""Test if the worker status response will be sent correctly when
|
"""Test if the worker status response will be sent correctly when
|
||||||
a worker status request is received
|
a worker status request is received
|
||||||
|
|
Загрузка…
Ссылка в новой задаче