Repository URL to install this package:
|
Version:
0.8.1 ▾
|
from __future__ import absolute_import
try:
from typing import Any
except ImportError:
pass
from supertenant.consts import (
INTEGRATION_MODULE_PYTHON_PROCESSTASK,
RESOURCE_TYPE_PROCESSTASK,
SPAN_TYPE_SERVER_REQUEST,
)
from supertenant.supermeter.logger import IntegrationModuleLog
_log = IntegrationModuleLog(INTEGRATION_MODULE_PYTHON_PROCESSTASK)
try:
import atexit
import os
import signal
import sys
from supertenant.supermeter import _get_brain
from supertenant.supermeter.data.base import new_base_data
from supertenant.supermeter.managers.processtask.process_name import get_process_name
from supertenant.supermeter.scope_manager import scope_manager
_log.instrumentation_success("")
SIGTERM_STRATEGY_DEFAULT = 0
SIGTERM_STRATEGY_FORCE = 1
SIGTERM_STRATEGY_DISABLE = 2
sigterm_strategy_var = os.environ.get("SUPERTENANT_SUPERMETER_SIGTERM_STRATEGY", "default").lower()
sigterm_strategy = SIGTERM_STRATEGY_DEFAULT
if sigterm_strategy_var in ("y", "yes", "true", "force", "1", "t"):
sigterm_strategy = SIGTERM_STRATEGY_FORCE
elif sigterm_strategy_var in ("n", "no", "false", "f", "2", "disable"):
sigterm_strategy = SIGTERM_STRATEGY_DISABLE
elif sigterm_strategy_var in ("default", "d", "def"):
sigterm_strategy = SIGTERM_STRATEGY_DEFAULT
else:
_log.error(
"SUPERTENANT_SUPERMETER_SIGTERM_STRATEGY environment variable has an unsupported value, using default"
)
data = new_base_data(RESOURCE_TYPE_PROCESSTASK, INTEGRATION_MODULE_PYTHON_PROCESSTASK, dict())
data.set_span_type(SPAN_TYPE_SERVER_REQUEST)
data.set_integration_module_resource_id(get_process_name())
span_id, _d, _ = scope_manager.open_span(SPAN_TYPE_SERVER_REQUEST, data.get_tags())
if span_id is not None:
# set up exit hooks only if we managed to open a span (which means brain is working, etc.)
def _close_span_and_shutdown():
# type: () -> None
global span_id
# if span_id is None it means we're shutting down.
if span_id is not None:
result = scope_manager.close_span(span_id, dict())
span_id = None
_log.debug("_close_span_and_shutdown hook", {"result": result})
brain = _get_brain()
if brain is not None:
brain.shutdown()
atexit.register(_close_span_and_shutdown)
_log.debug("registered atexit hook")
# signal handling is always tricky. since we're in "serverless" mode we're the first ones (hopefully) to be
# registering a signal handler, so we'll catch SIGTERM if happens and the application didn't register its own
# handler, and then we're responsible for calling the previous handler, but since the previous handler can be
# None, we need to re-raise the signal so the process's status code will show that it died from SIGTERM.
# If the application registers its own handler, the problem is split into two: if it wants to call the
# previous handler, then it'll call us and then we need to transparently call the original handler (if exists).
# If it doesn't call the previous handler then it's ok, as long as the application will exit gracefully and then
# our atexit handler will get called (from Python or Brain).
_sigterm_default_handler = signal.getsignal(signal.SIGTERM)
if sigterm_strategy == SIGTERM_STRATEGY_FORCE or (
sigterm_strategy == SIGTERM_STRATEGY_DEFAULT and _sigterm_default_handler in (None, signal.SIG_DFL)
):
def _sigterm_handler(*args, **kwargs):
# type: (Any, Any) -> None
global span_id, _sigterm_default_handler
we_should_handle_it = signal.getsignal(signal.SIGTERM) == _sigterm_handler
_close_span_and_shutdown()
if we_should_handle_it:
# restore the original sigterm handler. note that someone can send another signal while we're at it.
signal.signal(signal.SIGTERM, _sigterm_default_handler)
# re-raise the signal so the previous handler can catch it.
os.kill(os.getpid(), signal.SIGTERM) # py2.7 can't use signal.raise_signal (available from py3.3)
else:
if callable(_sigterm_default_handler):
_sigterm_default_handler(*args, **kwargs)
return
if _sigterm_default_handler == signal.SIG_IGN:
return
sys.exit(0)
signal.signal(signal.SIGTERM, _sigterm_handler)
_log.debug("registered SIGTERM handler")
else:
_log.warn("failed to open span")
except Exception as e:
_log.instrumentation_failed("", {"exc": e})