├── tracepointdebug ├── probe │ ├── __init__.py │ ├── condition │ │ ├── __init__.py │ │ ├── operand │ │ │ ├── __init__.py │ │ │ ├── boolean_operand.py │ │ │ ├── string_operand.py │ │ │ ├── null_operand.py │ │ │ ├── operand.py │ │ │ ├── number_operand.py │ │ │ ├── object_operand.py │ │ │ ├── typed_operand.py │ │ │ └── variable_operand.py │ │ ├── antlr4parser │ │ │ ├── __init__.py │ │ │ ├── python2_runtime │ │ │ │ ├── __init__.py │ │ │ │ ├── Condition.tokens │ │ │ │ ├── ConditionLexer.tokens │ │ │ │ ├── Condition.g4 │ │ │ │ ├── Condition.interp │ │ │ │ └── ConditionListener.py │ │ │ └── python3_runtime │ │ │ │ ├── __init__.py │ │ │ │ ├── Condition.tokens │ │ │ │ ├── ConditionLexer.tokens │ │ │ │ ├── Condition.g4 │ │ │ │ ├── Condition.interp │ │ │ │ └── ConditionListener.py │ │ ├── binary_operator.py │ │ ├── condition.py │ │ ├── value_provider.py │ │ ├── constant_value_provider.py │ │ ├── variable_value_provider.py │ │ ├── comparison_operator.py │ │ ├── condition_context.py │ │ ├── composite_condition.py │ │ └── single_condition.py │ ├── event │ │ ├── __init__.py │ │ ├── logpoint │ │ │ ├── __init__.py │ │ │ ├── log_point_rate_limit_event.py │ │ │ ├── log_point_failed_event.py │ │ │ ├── put_logpoint_failed_event.py │ │ │ └── log_point_event.py │ │ ├── errorstack │ │ │ ├── __init__.py │ │ │ ├── error_stack_rate_limit_event.py │ │ │ ├── error_stack_snapshot_failed_event.py │ │ │ └── error_stack_snapshot_event.py │ │ └── tracepoint │ │ │ ├── __init__.py │ │ │ ├── trace_point_rate_limit_event.py │ │ │ ├── put_tracepoint_failed_event.py │ │ │ ├── tracepoint_snapshot_failed_event.py │ │ │ └── trace_point_snapshot_event.py │ ├── ratelimit │ │ ├── __init__.py │ │ ├── rate_limit_result.py │ │ └── rate_limiter.py │ ├── request │ │ ├── __init__.py │ │ ├── tag │ │ │ ├── __init__.py │ │ │ ├── enable_probe_tag_requests.py │ │ │ ├── remove_probe_tag_requests.py │ │ │ └── disable_probe_tag_requests.py │ │ ├── logPoint │ │ │ ├── __init__.py │ │ │ ├── enable_log_point_request.py │ │ │ ├── remove_log_point_request.py │ │ │ ├── disable_log_point_request.py │ │ │ ├── update_log_point_request.py │ │ │ └── put_log_point_request.py │ │ ├── tracePoint │ │ │ ├── __init__.py │ │ │ ├── enable_trace_point_request.py │ │ │ ├── remove_trace_point_request.py │ │ │ ├── disable_trace_point_request.py │ │ │ ├── update_trace_point_request.py │ │ │ └── put_trace_point_request.py │ │ └── dynamicConfig │ │ │ ├── __init__.py │ │ │ ├── attach_request.py │ │ │ ├── detach_request.py │ │ │ └── update_config_request.py │ ├── response │ │ ├── __init__.py │ │ ├── tag │ │ │ ├── __init__.py │ │ │ ├── enable_probe_tag_response.py │ │ │ ├── remove_probe_tag_response.py │ │ │ └── disable_probe_tag_response.py │ │ ├── logPoint │ │ │ ├── __init__.py │ │ │ ├── put_log_point_response.py │ │ │ ├── enable_log_point_response.py │ │ │ ├── update_log_point_response.py │ │ │ ├── remove_log_point_response.py │ │ │ ├── disable_log_point_response.py │ │ │ └── filter_logpoints_response.py │ │ ├── tracePoint │ │ │ ├── __init__.py │ │ │ ├── put_trace_point_response.py │ │ │ ├── enable_trace_point_response.py │ │ │ ├── update_trace_point_response.py │ │ │ ├── remove_trace_point_response.py │ │ │ ├── disable_trace_point_response.py │ │ │ └── filter_tracepoints_response.py │ │ └── dynamicConfig │ │ │ ├── __init__.py │ │ │ ├── detach_response.py │ │ │ ├── update_config_response.py │ │ │ ├── attach_response.py │ │ │ └── get_config_response.py │ ├── application │ │ ├── __init__.py │ │ └── application_status_tracepoint_provider.py │ ├── breakpoints │ │ ├── __init__.py │ │ ├── tracepoint │ │ │ ├── __init__.py │ │ │ └── trace_point_config.py │ │ └── logpoint │ │ │ ├── __init__.py │ │ │ └── log_point_config.py │ ├── dynamicConfig │ │ ├── __init__.py │ │ └── dynamic_config_manager.py │ ├── handler │ │ ├── __init__.py │ │ ├── request │ │ │ ├── __init__.py │ │ │ ├── dynamicConfig │ │ │ │ ├── __init__.py │ │ │ │ ├── attach_request_handler.py │ │ │ │ ├── detach_request_handler.py │ │ │ │ └── update_config_request_handler.py │ │ │ ├── tag │ │ │ │ ├── __init__.py │ │ │ │ ├── enable_probe_tag_request_handler.py │ │ │ │ ├── remove_probe_tag_request_handler.py │ │ │ │ └── disable_probe_tag_request_handler.py │ │ │ ├── logPoint │ │ │ │ ├── __init__.py │ │ │ │ ├── enable_log_point_request_handler.py │ │ │ │ ├── remove_log_point_request_handler.py │ │ │ │ ├── disable_log_point_request_handler.py │ │ │ │ ├── update_log_point_request_handler.py │ │ │ │ └── put_log_point_request_handler.py │ │ │ └── tracePoint │ │ │ │ ├── __init__.py │ │ │ │ ├── enable_trace_point_request_handler.py │ │ │ │ ├── remove_trace_point_request_handler.py │ │ │ │ ├── disable_trace_point_request_handler.py │ │ │ │ ├── update_trace_point_request_handler.py │ │ │ │ └── put_trace_point_request_handler.py │ │ └── response │ │ │ ├── __init__.py │ │ │ ├── get_config_response_handler.py │ │ │ ├── filter_tracepoints_response_handler.py │ │ │ └── filter_logpoints_response_handler.py │ ├── snapshot │ │ ├── __init__.py │ │ ├── snapshot.py │ │ ├── variables.py │ │ ├── value.py │ │ ├── variable.py │ │ └── snapshot_collector_config_manager.py │ ├── coded_exception.py │ ├── coded_error.py │ ├── constants.py │ ├── encoder.py │ ├── frame.py │ ├── tag_manager.py │ └── source_code_helper.py ├── broker │ ├── __init__.py │ ├── event │ │ ├── __init__.py │ │ ├── event.py │ │ ├── application_status_event.py │ │ └── base_event.py │ ├── handler │ │ ├── __init__.py │ │ ├── request │ │ │ ├── __init__.py │ │ │ └── request_handler.py │ │ └── response │ │ │ ├── __init__.py │ │ │ └── response_handler.py │ ├── request │ │ ├── __init__.py │ │ ├── base_request.py │ │ ├── request.py │ │ ├── get_config_request.py │ │ ├── filter_logpoints_request.py │ │ └── filter_tracepoints_request.py │ ├── response │ │ ├── __init__.py │ │ ├── response.py │ │ └── base_response.py │ ├── application │ │ ├── __init__.py │ │ ├── application_status_provider.py │ │ ├── application_filter.py │ │ └── application_status.py │ ├── broker_credentials.py │ └── broker_message_callback.py ├── config │ ├── __init__.py │ ├── config_names.py │ └── config_metadata.py ├── external │ ├── __init__.py │ └── googleclouddebugger │ │ ├── __init__.py │ │ ├── version.py │ │ ├── native_module.h │ │ ├── python_callback.h │ │ ├── rate_limit.h │ │ ├── python_callback.cc │ │ ├── nullable.h │ │ ├── module_utils2.py │ │ ├── conditional_breakpoint.h │ │ ├── module_search2.py │ │ ├── rate_limit.cc │ │ └── leaky_bucket.cc ├── application │ ├── __init__.py │ ├── utils.py │ ├── application.py │ ├── application_info_provider.py │ └── config_aware_application_info_provider.py ├── trace │ ├── __init__.py │ ├── trace_context.py │ └── trace_support.py ├── utils │ ├── log │ │ ├── __init__.py │ │ └── logger.py │ ├── __init__.py │ └── validation │ │ ├── __init__.py │ │ └── validate_broker_request.py └── __init__.py ├── Pipfile ├── Pipfile.lock ├── .github └── workflows │ ├── build.yml │ └── release.yml └── .gitignore /tracepointdebug/probe/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/external/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/application/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/event/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/handler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/request/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/response/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/ratelimit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/application/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/application/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/breakpoints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/dynamicConfig/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/logpoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tag/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tag/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/handler/request/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/broker/handler/response/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/errorstack/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/tracepoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/dynamicConfig/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/dynamicConfig/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tracepointdebug/trace/__init__.py: -------------------------------------------------------------------------------- 1 | from .trace_support import TraceSupport -------------------------------------------------------------------------------- /tracepointdebug/utils/log/__init__.py: -------------------------------------------------------------------------------- 1 | from .logger import debug_logger -------------------------------------------------------------------------------- /tracepointdebug/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .log import * 2 | from .validation import * -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/__init__.py: -------------------------------------------------------------------------------- 1 | from .request import * 2 | from .response import * -------------------------------------------------------------------------------- /tracepointdebug/utils/validation/__init__.py: -------------------------------------------------------------------------------- 1 | from .validate_broker_request import validate_file_name_and_line_no -------------------------------------------------------------------------------- /tracepointdebug/probe/breakpoints/tracepoint/__init__.py: -------------------------------------------------------------------------------- 1 | from .trace_point_config import * 2 | from .trace_point_manager import * -------------------------------------------------------------------------------- /tracepointdebug/probe/breakpoints/logpoint/__init__.py: -------------------------------------------------------------------------------- 1 | from .log_point_config import * 2 | from .log_point_manager import * 3 | from .log_point import * -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/binary_operator.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class BinaryOperator(Enum): 5 | AND = 1 6 | OR = 2 7 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/__init__.py: -------------------------------------------------------------------------------- 1 | from .tracePoint import * 2 | from .logPoint import * 3 | from .tag import * 4 | from .dynamicConfig import * -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/__init__.py: -------------------------------------------------------------------------------- 1 | from .snapshot import * 2 | from .snapshot_collector import * 3 | from .snapshot_collector_config_manager import SnapshotCollectorConfigManager -------------------------------------------------------------------------------- /tracepointdebug/probe/ratelimit/rate_limit_result.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class RateLimitResult(Enum): 5 | OK = "OK" 6 | HIT = "HIT" 7 | EXCEEDED = "EXCEEDED" 8 | -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/snapshot.py: -------------------------------------------------------------------------------- 1 | class Snapshot(object): 2 | def __init__(self, frames, method_name, file): 3 | self.frames = frames 4 | self.method_name = method_name 5 | self.file = file 6 | 7 | -------------------------------------------------------------------------------- /tracepointdebug/probe/coded_exception.py: -------------------------------------------------------------------------------- 1 | class CodedException(Exception): 2 | def __init__(self, coded_error, args): 3 | super(CodedException, self).__init__(coded_error.format_message(args)) 4 | self.code = coded_error.code 5 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/condition.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class Condition(ABC): 7 | 8 | @abc.abstractmethod 9 | def evaluate(self, condition_context): 10 | pass 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/variables.py: -------------------------------------------------------------------------------- 1 | class Variables(object): 2 | def __init__(self, variables): 3 | self.variables = variables 4 | 5 | def to_json(self): 6 | return {var.name: var.value for var in self.variables} 7 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/dynamicConfig/__init__.py: -------------------------------------------------------------------------------- 1 | from .attach_request_handler import AttachRequestHandler 2 | from .detach_request_handler import DetachRequestHandler 3 | from .update_config_request_handler import UpdateConfigRequestHandler -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/value_provider.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class ValueProvider(ABC): 7 | 8 | @abc.abstractmethod 9 | def get_value(self, condition_context): 10 | pass 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/coded_error.py: -------------------------------------------------------------------------------- 1 | class CodedError: 2 | def __init__(self, code, msg_template): 3 | self.code = code 4 | self.msg_template = msg_template 5 | 6 | def format_message(self, args): 7 | return self.msg_template.format(*args) 8 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/response/__init__.py: -------------------------------------------------------------------------------- 1 | from .filter_tracepoints_response_handler import FilterTracePointsResponseHandler 2 | from .filter_logpoints_response_handler import FilterLogPointsResponseHandler 3 | from .get_config_response_handler import GetConfigResponseHandler -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | six = "*" 8 | websocket-client = "*" 9 | pystache = "*" 10 | cachetools= "*" 11 | 12 | [dev-packages] 13 | 14 | [requires] 15 | python_version = "3.6" 16 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tag/__init__.py: -------------------------------------------------------------------------------- 1 | from .disable_probe_tag_request_handler import DisableProbeTagRequestHandler 2 | from .enable_probe_tag_request_handler import EnableProbeTagRequestHandler 3 | from .remove_probe_tag_request_handler import RemoveProbeTagRequestHandler -------------------------------------------------------------------------------- /tracepointdebug/broker/application/application_status_provider.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class ApplicationStatusProvider(ABC): 7 | 8 | @abc.abstractmethod 9 | def provide(self, application_status, client): 10 | pass 11 | -------------------------------------------------------------------------------- /tracepointdebug/application/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def get_from_environment_variables(config_name, default, type): 5 | env_variables = os.environ 6 | 7 | for var_name in env_variables: 8 | if var_name.upper() == config_name: 9 | return type(env_variables.get(var_name).strip()) 10 | return default 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/constant_value_provider.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.value_provider import ValueProvider 2 | 3 | 4 | class ConstantValueProvider(ValueProvider): 5 | 6 | def __init__(self, value): 7 | self.value = value 8 | 9 | def get_value(self, condition_context): 10 | return self.value 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/constants.py: -------------------------------------------------------------------------------- 1 | TRACEPOINT_DEFAULT_EXPIRY_SECS = 1800 2 | TRACEPOINT_DEFAULT_EXPIRY_COUNT = 50 3 | TRACEPOINT_MAX_EXPIRY_SECS = 86400 4 | TRACEPOINT_MAX_EXPIRY_COUNT = 1000 5 | 6 | 7 | LOGPOINT_DEFAULT_EXPIRY_SECS=1800 8 | LOGPOINT_DEFAULT_EXPIRY_COUNT= 50 9 | LOGPOINT_MAX_EXPIRY_SECS= 86400 10 | LOGPOINT_MAX_EXPIRY_COUNT= 1000 -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/version.py: -------------------------------------------------------------------------------- 1 | """Version of the Google Python Cloud Debugger.""" 2 | 3 | # Versioning scheme: MAJOR.MINOR 4 | # The major version should only change on breaking changes. Minor version 5 | # changes go between regular updates. Instances running debuggers with 6 | # different major versions will show up as two different debuggees. 7 | __version__ = '2.15' 8 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/variable_value_provider.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.value_provider import ValueProvider 2 | 3 | 4 | class VariableValueProvider(ValueProvider): 5 | 6 | def __init__(self, var_name): 7 | self.var_name = var_name 8 | 9 | def get_value(self, condition_context): 10 | return condition_context.get_variable_value(self.var_name) 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/comparison_operator.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ComparisonOperator(Enum): 5 | EQ = "==" 6 | NE = "!=" 7 | 8 | LT = "<" 9 | LE = "<=" 10 | GT = ">" 11 | GE = ">=" 12 | 13 | @staticmethod 14 | def from_expression(expression): 15 | for op in ComparisonOperator: 16 | if op == expression: 17 | return op 18 | -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/value.py: -------------------------------------------------------------------------------- 1 | class Value(object): 2 | def __init__(self, var_type, value): 3 | self.type = var_type 4 | self.value = value 5 | 6 | def __repr__(self): 7 | return str( 8 | self.value 9 | ) 10 | 11 | def to_json(self): 12 | return { 13 | "@type": str(self.type), 14 | "@value": self.value 15 | } 16 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/__init__.py: -------------------------------------------------------------------------------- 1 | from .put_log_point_request_handler import PutLogPointRequestHandler 2 | from .remove_log_point_request_handler import RemoveLogPointRequestHandler 3 | from .enable_log_point_request_handler import EnableLogPointRequestHandler 4 | from .disable_log_point_request_handler import DisableLogPointRequestHandler 5 | from .update_log_point_request_handler import UpdateLogPointRequestHandler -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/__init__.py: -------------------------------------------------------------------------------- 1 | from .put_trace_point_request_handler import PutTracePointRequestHandler 2 | from .remove_trace_point_request_handler import RemoveTracePointRequestHandler 3 | from .enable_trace_point_request_handler import EnableTracePointRequestHandler 4 | from .disable_trace_point_request_handler import DisableTracePointRequestHandler 5 | from .update_trace_point_request_handler import UpdateTracePointRequestHandler -------------------------------------------------------------------------------- /tracepointdebug/broker/request/base_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.request import Request 2 | 3 | 4 | class BaseRequest(Request): 5 | 6 | def __init__(self, id, client=None): 7 | self.id = id 8 | self.client = client 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_name(self): 14 | return self.__class__.__name__ 15 | 16 | def get_client(self): 17 | return self.client 18 | -------------------------------------------------------------------------------- /tracepointdebug/broker/request/request.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class Request(ABC): 7 | 8 | @staticmethod 9 | def get_type(): 10 | return "Request" 11 | 12 | @abc.abstractmethod 13 | def get_id(self): 14 | pass 15 | 16 | @abc.abstractmethod 17 | def get_name(self): 18 | pass 19 | 20 | @abc.abstractmethod 21 | def get_client(self): 22 | pass 23 | -------------------------------------------------------------------------------- /tracepointdebug/utils/validation/validate_broker_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.coded_exception import CodedException 2 | from tracepointdebug.probe.errors import FILE_NAME_IS_MANDATORY, LINE_NUMBER_IS_MANDATORY 3 | 4 | def validate_file_name_and_line_no(file_name, line_no): 5 | if not file_name or len(file_name) <= 0: 6 | raise CodedException(FILE_NAME_IS_MANDATORY) 7 | if not line_no or line_no <= 0: 8 | raise CodedException(LINE_NUMBER_IS_MANDATORY) -------------------------------------------------------------------------------- /tracepointdebug/trace/trace_context.py: -------------------------------------------------------------------------------- 1 | class TraceContext: 2 | 3 | def __init__(self, trace_id=None, transaction_id=None, span_id=None): 4 | self.trace_id = trace_id 5 | self.transaction_id = transaction_id 6 | self.span_id = span_id 7 | 8 | def get_trace_id(self): 9 | return self.trace_id 10 | 11 | def get_transaction_id(self): 12 | return self.transaction_id 13 | 14 | def get_span_id(self): 15 | return self.span_id -------------------------------------------------------------------------------- /tracepointdebug/broker/handler/request/request_handler.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class RequestHandler(ABC): 7 | 8 | @staticmethod 9 | @abc.abstractmethod 10 | def get_request_name(): 11 | pass 12 | 13 | @staticmethod 14 | @abc.abstractmethod 15 | def get_request_cls(): 16 | pass 17 | 18 | @staticmethod 19 | @abc.abstractmethod 20 | def handle_request(request): 21 | pass 22 | -------------------------------------------------------------------------------- /tracepointdebug/broker/handler/response/response_handler.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class ResponseHandler(ABC): 7 | 8 | @staticmethod 9 | @abc.abstractmethod 10 | def get_response_name(): 11 | pass 12 | 13 | @staticmethod 14 | @abc.abstractmethod 15 | def get_response_cls(): 16 | pass 17 | 18 | @staticmethod 19 | @abc.abstractmethod 20 | def handle_response(response): 21 | pass 22 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/Condition.tokens: -------------------------------------------------------------------------------- 1 | BOOLEAN=1 2 | AND=2 3 | OR=3 4 | NOT=4 5 | TRUE=5 6 | FALSE=6 7 | NULL=7 8 | GT=8 9 | GE=9 10 | LT=10 11 | LE=11 12 | EQ=12 13 | NE=13 14 | LPAREN=14 15 | RPAREN=15 16 | CHARACTER=16 17 | NUMBER=17 18 | STRING=18 19 | VARIABLE=19 20 | PLACEHOLDER=20 21 | WS=21 22 | 'NOT'=4 23 | 'true'=5 24 | 'false'=6 25 | 'null'=7 26 | '>'=8 27 | '>='=9 28 | '<'=10 29 | '<='=11 30 | '=='=12 31 | '!='=13 32 | '('=14 33 | ')'=15 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/Condition.tokens: -------------------------------------------------------------------------------- 1 | BOOLEAN=1 2 | AND=2 3 | OR=3 4 | NOT=4 5 | TRUE=5 6 | FALSE=6 7 | NULL=7 8 | GT=8 9 | GE=9 10 | LT=10 11 | LE=11 12 | EQ=12 13 | NE=13 14 | LPAREN=14 15 | RPAREN=15 16 | CHARACTER=16 17 | NUMBER=17 18 | STRING=18 19 | VARIABLE=19 20 | PLACEHOLDER=20 21 | WS=21 22 | 'NOT'=4 23 | 'true'=5 24 | 'false'=6 25 | 'null'=7 26 | '>'=8 27 | '>='=9 28 | '<'=10 29 | '<='=11 30 | '=='=12 31 | '!='=13 32 | '('=14 33 | ')'=15 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/ConditionLexer.tokens: -------------------------------------------------------------------------------- 1 | BOOLEAN=1 2 | AND=2 3 | OR=3 4 | NOT=4 5 | TRUE=5 6 | FALSE=6 7 | NULL=7 8 | GT=8 9 | GE=9 10 | LT=10 11 | LE=11 12 | EQ=12 13 | NE=13 14 | LPAREN=14 15 | RPAREN=15 16 | CHARACTER=16 17 | NUMBER=17 18 | STRING=18 19 | VARIABLE=19 20 | PLACEHOLDER=20 21 | WS=21 22 | 'NOT'=4 23 | 'true'=5 24 | 'false'=6 25 | 'null'=7 26 | '>'=8 27 | '>='=9 28 | '<'=10 29 | '<='=11 30 | '=='=12 31 | '!='=13 32 | '('=14 33 | ')'=15 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/ConditionLexer.tokens: -------------------------------------------------------------------------------- 1 | BOOLEAN=1 2 | AND=2 3 | OR=3 4 | NOT=4 5 | TRUE=5 6 | FALSE=6 7 | NULL=7 8 | GT=8 9 | GE=9 10 | LT=10 11 | LE=11 12 | EQ=12 13 | NE=13 14 | LPAREN=14 15 | RPAREN=15 16 | CHARACTER=16 17 | NUMBER=17 18 | STRING=18 19 | VARIABLE=19 20 | PLACEHOLDER=20 21 | WS=21 22 | 'NOT'=4 23 | 'true'=5 24 | 'false'=6 25 | 'null'=7 26 | '>'=8 27 | '>='=9 28 | '<'=10 29 | '<='=11 30 | '=='=12 31 | '!='=13 32 | '('=14 33 | ')'=15 34 | -------------------------------------------------------------------------------- /tracepointdebug/broker/broker_credentials.py: -------------------------------------------------------------------------------- 1 | class BrokerCredentials(object): 2 | def __init__(self, api_key=None, app_instance_id=None, app_name=None, app_stage=None, app_version=None, 3 | hostname=None, runtime=None): 4 | self.api_key = api_key 5 | self.app_instance_id = app_instance_id 6 | self.app_name = app_name 7 | self.app_stage = app_stage 8 | self.app_version = app_version 9 | self.hostname = hostname 10 | self.runtime = runtime 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/dynamicConfig/attach_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class AttachRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(AttachRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | 9 | def get_id(self): 10 | return self.id 11 | 12 | def get_name(self): 13 | return self.__class__.__name__ 14 | 15 | def get_client(self): 16 | return self.client 17 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/dynamicConfig/detach_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class DetachRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(DetachRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | 9 | def get_id(self): 10 | return self.id 11 | 12 | def get_name(self): 13 | return self.__class__.__name__ 14 | 15 | def get_client(self): 16 | return self.client 17 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/dynamicConfig/detach_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | class DetachResponse(BaseResponse): 4 | 5 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 6 | error_type=None, error_message=None): 7 | super(DetachResponse, self).__init__(request_id, client, application_instance_id, erroneous, 8 | error_code, error_type, error_message) -------------------------------------------------------------------------------- /tracepointdebug/probe/response/dynamicConfig/update_config_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | class UpdateConfigResponse(BaseResponse): 4 | 5 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 6 | error_type=None, error_message=None): 7 | super(UpdateConfigResponse, self).__init__(request_id, client, application_instance_id, erroneous, 8 | error_code, error_type, error_message) -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tag/enable_probe_tag_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class EnableProbeTagResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(EnableProbeTagResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tag/remove_probe_tag_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class RemoveProbeTagResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(RemoveProbeTagResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tag/disable_probe_tag_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class DisableProbeTagResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(DisableProbeTagResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/put_log_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class PutLogPointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(PutLogPointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/put_trace_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class PutTracePointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(PutTracePointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/enable_log_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class EnableLogPointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(EnableLogPointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/update_log_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class UpdateLogPointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(UpdateLogPointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/variable.py: -------------------------------------------------------------------------------- 1 | class Variable(object): 2 | def __init__(self, name, var_type, value): 3 | self.name = name 4 | self.type = var_type 5 | self.value = value 6 | 7 | def __repr__(self): 8 | return str( 9 | { 10 | "name": self.name, 11 | "type": self.type, 12 | "value": self.value 13 | } 14 | ) 15 | 16 | def to_json(self): 17 | return { 18 | "@type": str(self.type), 19 | "@value": self.value 20 | } 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/remove_log_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class RemoveLogPointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(RemoveLogPointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/disable_log_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class DisableLogPointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(DisableLogPointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/enable_trace_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class EnableTracePointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(EnableTracePointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/update_trace_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class UpdateTracePointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(UpdateTracePointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/remove_trace_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class RemoveTracePointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(RemoveTracePointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/condition_context.py: -------------------------------------------------------------------------------- 1 | class ConditionContext(object): 2 | def __init__(self, variables): 3 | self.variables = variables 4 | 5 | def get_variable_value(self, var_name): 6 | attr_lst = var_name.split(".") 7 | cur = self.variables 8 | for attr in attr_lst: 9 | if hasattr(cur, attr): 10 | cur = getattr(cur, attr) 11 | elif isinstance(cur, dict) and cur.get(attr) is not None: 12 | cur = cur.get(attr) 13 | else: 14 | return None 15 | 16 | return cur 17 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/disable_trace_point_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | 4 | class DisableTracePointResponse(BaseResponse): 5 | 6 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 7 | error_type=None, error_message=None): 8 | super(DisableTracePointResponse, self).__init__(request_id, client, application_instance_id, erroneous, 9 | error_code, error_type, error_message) 10 | 11 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/boolean_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.typed_operand import TypedOperand 2 | 3 | 4 | class BooleanOperand(TypedOperand): 5 | 6 | def __init__(self, value_provider): 7 | super(BooleanOperand, self).__init__(bool, value_provider) 8 | 9 | def is_eq(self, value, condition_context): 10 | cur_val = self.get_value(condition_context) 11 | return cur_val == value 12 | 13 | def is_ne(self, value, condition_context): 14 | cur_val = self.get_value(condition_context) 15 | return cur_val != value 16 | 17 | 18 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tag/enable_probe_tag_requests.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class EnableProbeTagRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(EnableProbeTagRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.tag = request.get("tag") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_tag(self): 14 | return self.tag 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tag/remove_probe_tag_requests.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class RemoveProbeTagRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(RemoveProbeTagRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.tag = request.get("tag") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_tag(self): 14 | return self.tag 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tag/disable_probe_tag_requests.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class DisableProbeTagRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(DisableProbeTagRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.tag = request.get("tag") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_tag(self): 14 | return self.tag 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/encoder.py: -------------------------------------------------------------------------------- 1 | import json 2 | from tracepointdebug.utils import debug_logger 3 | 4 | class JSONEncoder(json.JSONEncoder): 5 | def default(self, z): 6 | try: 7 | if "to_json" in dir(z): 8 | return z.to_json() 9 | elif isinstance(z, bytes): 10 | return z.decode('utf-8', errors='ignore') 11 | else: 12 | return super(JSONEncoder, self).default(z) 13 | except Exception as e: 14 | debug_logger(e) 15 | 16 | 17 | def to_json(data, separators=None): 18 | return json.dumps(data, separators=separators, cls=JSONEncoder) 19 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/dynamicConfig/update_config_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class UpdateConfigRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(UpdateConfigRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.config = request.get("config", {}) 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_config(self): 14 | return self.config 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/enable_log_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class EnableLogPointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(EnableLogPointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.log_point_id = request.get("logPointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_log_point_id(self): 14 | return self.log_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/remove_log_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class RemoveLogPointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(RemoveLogPointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.log_point_id = request.get("logPointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_log_point_id(self): 14 | return self.log_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/disable_log_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class DisableLogPointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(DisableLogPointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.log_point_id = request.get("logPointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_log_point_id(self): 14 | return self.log_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/dynamicConfig/attach_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | class AttachResponse(BaseResponse): 4 | 5 | def __init__(self, requestId=None, 6 | source=None, applicationInstanceId=None, 7 | erroneous=False, errorCode=None, 8 | errorType=None, errorMessage=None, **opts): 9 | super(AttachResponse, self).__init__(request_id=requestId, 10 | client=source, application_instance_id=applicationInstanceId, 11 | erroneous=erroneous, error_code=errorCode, 12 | error_type=errorType, error_message=errorMessage) -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/enable_trace_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class EnableTracePointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(EnableTracePointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.trace_point_id = request.get("tracePointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_trace_point_id(self): 14 | return self.trace_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/remove_trace_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class RemoveTracePointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(RemoveTracePointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.trace_point_id = request.get("tracePointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_trace_point_id(self): 14 | return self.trace_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/disable_trace_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | 4 | class DisableTracePointRequest(BaseRequest): 5 | 6 | def __init__(self, request): 7 | super(DisableTracePointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 8 | self.trace_point_id = request.get("tracePointId") 9 | 10 | def get_id(self): 11 | return self.id 12 | 13 | def get_trace_point_id(self): 14 | return self.trace_point_id 15 | 16 | def get_name(self): 17 | return self.__class__.__name__ 18 | 19 | def get_client(self): 20 | return self.client 21 | -------------------------------------------------------------------------------- /tracepointdebug/application/application.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.config_aware_application_info_provider import ConfigAwareApplicationInfoProvider 2 | 3 | 4 | class Application(object): 5 | application_info_provider = ConfigAwareApplicationInfoProvider() 6 | 7 | @staticmethod 8 | def get_application_info(): 9 | return Application.application_info_provider.get_application_info() 10 | 11 | @staticmethod 12 | def get_application_info_provider(): 13 | return Application.application_info_provider 14 | 15 | @staticmethod 16 | def set_application_info_provider(application_info_provider): 17 | Application.application_info_provider = application_info_provider 18 | -------------------------------------------------------------------------------- /tracepointdebug/probe/application/application_status_tracepoint_provider.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 4 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 5 | from tracepointdebug.broker.application.application_status_provider import ApplicationStatusProvider 6 | 7 | ABC = abc.ABCMeta('ABC', (object,), {}) 8 | 9 | 10 | class ApplicationStatusTracePointProvider(ApplicationStatusProvider): 11 | 12 | def provide(self, application_status, client=None): 13 | application_status.trace_points = TracePointManager.instance().list_trace_points(client) 14 | application_status.log_points = LogPointManager.instance().list_log_points(client) 15 | -------------------------------------------------------------------------------- /tracepointdebug/probe/frame.py: -------------------------------------------------------------------------------- 1 | class Frame(object): 2 | def __init__(self, line_no, variables, path, method_name): 3 | self.line_no = line_no 4 | self.variables = variables 5 | self.path = path 6 | self.method_name = method_name 7 | 8 | def __repr__(self): 9 | return str({ 10 | "line": self.line_no, 11 | "locals": self.variables, 12 | "path": self.path, 13 | "methodName": self.method_name, 14 | }) 15 | 16 | def to_json(self): 17 | return { 18 | "lineNo": self.line_no, 19 | "variables": self.variables, 20 | "fileName": self.path, 21 | "methodName": self.method_name 22 | } 23 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/string_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.typed_operand import TypedOperand 2 | import sys 3 | 4 | class StringOperand(TypedOperand): 5 | 6 | def __init__(self, value_provider): 7 | if sys.version_info[0] >= 3: 8 | super(StringOperand, self).__init__(str, value_provider) 9 | else: 10 | super(StringOperand, self).__init__((str, unicode), value_provider) 11 | 12 | def is_eq(self, value, condition_context): 13 | cur_val = self.get_value(condition_context) 14 | return cur_val == value 15 | 16 | def is_ne(self, value, condition_context): 17 | cur_val = self.get_value(condition_context) 18 | return cur_val != value 19 | -------------------------------------------------------------------------------- /tracepointdebug/broker/response/response.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class Response(ABC): 7 | 8 | @abc.abstractmethod 9 | def get_request_id(self): 10 | pass 11 | 12 | @abc.abstractmethod 13 | def get_name(self): 14 | pass 15 | 16 | @abc.abstractmethod 17 | def get_client(self): 18 | pass 19 | 20 | @staticmethod 21 | def get_type(): 22 | return "Response" 23 | 24 | @staticmethod 25 | def get_source(): 26 | return "Agent" 27 | 28 | @abc.abstractmethod 29 | def is_erroneous(self): 30 | pass 31 | 32 | @abc.abstractmethod 33 | def get_error_code(self): 34 | pass 35 | 36 | @abc.abstractmethod 37 | def get_error_type(self): 38 | pass 39 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/null_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.operand import Operand 2 | 3 | 4 | class NullOperand(Operand): 5 | 6 | def get_value(self, condition_context): 7 | return None 8 | 9 | def eq(self, operand, condition_context): 10 | return operand.get_value(condition_context) is None 11 | 12 | def ne(self, operand, condition_context): 13 | return operand.get_value(condition_context) is not None 14 | 15 | def lt(self, operand, condition_context): 16 | return False 17 | 18 | def le(self, operand, condition_context): 19 | return False 20 | 21 | def gt(self, operand, condition_context): 22 | return False 23 | 24 | def ge(self, operand, condition_context): 25 | return False 26 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/operand.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class Operand(ABC): 7 | 8 | @abc.abstractmethod 9 | def get_value(self, condition_context): 10 | pass 11 | 12 | @abc.abstractmethod 13 | def eq(self, operand, condition_context): 14 | return False 15 | 16 | @abc.abstractmethod 17 | def ne(self, operand, condition_context): 18 | return False 19 | 20 | @abc.abstractmethod 21 | def lt(self, operand, condition_context): 22 | return False 23 | 24 | @abc.abstractmethod 25 | def le(self, operand, condition_context): 26 | return False 27 | 28 | @abc.abstractmethod 29 | def gt(self, operand, condition_context): 30 | return False 31 | 32 | @abc.abstractmethod 33 | def ge(self, operand, condition_context): 34 | return False 35 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/errorstack/error_stack_rate_limit_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class ErrorStackRateLimitEvent(BaseEvent): 5 | EVENT_NAME = "ErrorStackRateLimitEvent" 6 | 7 | def __init__(self, file, line_no): 8 | super(ErrorStackRateLimitEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | 12 | def to_json(self): 13 | return { 14 | "name": self.name, 15 | "type": self.get_type(), 16 | "id": self.id, 17 | "fileName": self.file, 18 | "lineNo": self.line_no, 19 | "sendAck": self.send_ack, 20 | "applicationInstanceId": self.application_instance_id, 21 | "applicationName": self.application_name, 22 | "time": self.time, 23 | "hostName": self.hostname 24 | } -------------------------------------------------------------------------------- /tracepointdebug/probe/event/logpoint/log_point_rate_limit_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class LogPointRateLimitEvent(BaseEvent): 5 | EVENT_NAME = "LogPointRateLimitEvent" 6 | 7 | def __init__(self, file, line_no): 8 | super(LogPointRateLimitEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | 12 | def to_json(self): 13 | return { 14 | "name": self.name, 15 | "type": self.get_type(), 16 | "id": self.id, 17 | "fileName": self.file, 18 | "lineNo": self.line_no, 19 | "sendAck": self.send_ack, 20 | "applicationInstanceId": self.application_instance_id, 21 | "applicationName": self.application_name, 22 | "client": self.client, 23 | "time": self.time, 24 | "hostName": self.hostname 25 | } 26 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/tracepoint/trace_point_rate_limit_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class TracePointRateLimitEvent(BaseEvent): 5 | EVENT_NAME = "TracePointRateLimitEvent" 6 | 7 | def __init__(self, file, line_no): 8 | super(TracePointRateLimitEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | 12 | def to_json(self): 13 | return { 14 | "name": self.name, 15 | "type": self.get_type(), 16 | "id": self.id, 17 | "fileName": self.file, 18 | "lineNo": self.line_no, 19 | "sendAck": self.send_ack, 20 | "applicationInstanceId": self.application_instance_id, 21 | "applicationName": self.application_name, 22 | "client": self.client, 23 | "time": self.time, 24 | "hostName": self.hostname 25 | } 26 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/dynamicConfig/get_config_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | class GetConfigResponse(BaseResponse): 4 | 5 | def __init__(self, config=None, requestId=None, 6 | source=None, applicationInstanceId=None, 7 | erroneous=False, errorCode=None, 8 | errorType=None, errorMessage=None, **opts): 9 | super(GetConfigResponse, self).__init__(request_id=requestId, 10 | client=source, application_instance_id=applicationInstanceId, 11 | erroneous=erroneous, error_code=errorCode, 12 | error_type=errorType, error_message=errorMessage) 13 | 14 | self._config = config 15 | 16 | 17 | @property 18 | def config(self): 19 | return self._config 20 | 21 | 22 | @config.setter 23 | def config(self, config): 24 | self._config = config -------------------------------------------------------------------------------- /tracepointdebug/broker/event/event.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | ABC = abc.ABCMeta('ABC', (object,), {}) 4 | 5 | 6 | class Event(ABC): 7 | 8 | def get_type(self): 9 | return "Event" 10 | 11 | @property 12 | @abc.abstractmethod 13 | def name(self): 14 | pass 15 | 16 | @property 17 | @abc.abstractmethod 18 | def id(self): 19 | pass 20 | 21 | @property 22 | @abc.abstractmethod 23 | def send_ack(self): 24 | pass 25 | 26 | @property 27 | @abc.abstractmethod 28 | def client(self): 29 | pass 30 | 31 | @property 32 | @abc.abstractmethod 33 | def time(self): 34 | pass 35 | 36 | @property 37 | @abc.abstractmethod 38 | def hostname(self): 39 | pass 40 | 41 | @property 42 | @abc.abstractmethod 43 | def application_name(self): 44 | pass 45 | 46 | @property 47 | @abc.abstractmethod 48 | def application_instance_id(self): 49 | pass 50 | -------------------------------------------------------------------------------- /tracepointdebug/application/application_info_provider.py: -------------------------------------------------------------------------------- 1 | import abc, sys 2 | 3 | from tracepointdebug.config import config_names 4 | from tracepointdebug.config.config_provider import ConfigProvider 5 | 6 | ABC = abc.ABCMeta('ABC', (object,), {}) 7 | 8 | 9 | class ApplicationInfoProvider(ABC): 10 | 11 | APPLICATION_RUNTIME = "python" 12 | APPLICATION_RUNTIME_VERSION = str(sys.version_info[0]) 13 | 14 | @abc.abstractmethod 15 | def get_application_info(self): 16 | pass 17 | 18 | @staticmethod 19 | def parse_application_tags(): 20 | application_tags = {} 21 | prefix_length = len(config_names.SIDEKICK_APPLICATION_TAG_PREFIX) 22 | for key in ConfigProvider.configs: 23 | if key.startswith(config_names.SIDEKICK_APPLICATION_TAG_PREFIX): 24 | app_tag_key = key[prefix_length:] 25 | val = ConfigProvider.get(key) 26 | application_tags[app_tag_key] = val 27 | return application_tags 28 | -------------------------------------------------------------------------------- /tracepointdebug/probe/response/logPoint/filter_logpoints_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | from typing import List 4 | 5 | class FilterLogPointsResponse(BaseResponse): 6 | 7 | def __init__(self, logPoints=None, requestId=None, 8 | source=None, applicationInstanceId=None, 9 | erroneous=False, errorCode=None, 10 | errorType=None, errorMessage=None, **opts): 11 | super(FilterLogPointsResponse, self).__init__(request_id=requestId, 12 | client=source, application_instance_id=applicationInstanceId, 13 | erroneous=erroneous, error_code=errorCode, 14 | error_type=errorType, error_message=errorMessage) 15 | 16 | self._log_points = logPoints 17 | 18 | 19 | @property 20 | def log_points(self): 21 | return self._log_points 22 | 23 | 24 | @log_points.setter 25 | def log_points(self, log_points): 26 | self._log_points = log_points -------------------------------------------------------------------------------- /tracepointdebug/config/config_names.py: -------------------------------------------------------------------------------- 1 | SIDEKICK_APIKEY = 'sidekick.apikey' 2 | 3 | SIDEKICK_DEBUG_ENABLE = 'sidekick.debug.enable' 4 | 5 | ############################################################################# 6 | 7 | SIDEKICK_APPLICATION_ID = 'sidekick.application.id' 8 | SIDEKICK_APPLICATION_INSTANCE_ID = 'sidekick.application.instanceid' 9 | SIDEKICK_APPLICATION_NAME = 'sidekick.application.name' 10 | SIDEKICK_APPLICATION_STAGE = 'sidekick.application.stage' 11 | SIDEKICK_APPLICATION_DOMAIN_NAME = 'sidekick.application.domainname' 12 | SIDEKICK_APPLICATION_CLASS_NAME = 'sidekick.application.classname' 13 | SIDEKICK_APPLICATION_VERSION = 'sidekick.application.version' 14 | SIDEKICK_APPLICATION_TAG_PREFIX = 'sidekick.application.tag.prefix' 15 | SIDEKICK_APPLICATION_REGION = 'sidekick.application.region' 16 | SIDEKICK_ERROR_STACK_ENABLE = 'sidekick.error.stack.enable' 17 | SIDEKICK_ERROR_COLLECTION_ENABLE_CAPTURE_FRAME = 'sidekick.error.collection.enable.capture.frame' 18 | SIDEKICK_PRINT_CLOSED_SOCKET_DATA = 'sidekick.print.closed.socket.data' -------------------------------------------------------------------------------- /tracepointdebug/probe/response/tracePoint/filter_tracepoints_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.base_response import BaseResponse 2 | 3 | from typing import List 4 | 5 | class FilterTracePointsResponse(BaseResponse): 6 | 7 | def __init__(self, tracePoints=None, requestId=None, 8 | source=None, applicationInstanceId=None, 9 | erroneous=False, errorCode=None, 10 | errorType=None, errorMessage=None, **opts): 11 | super(FilterTracePointsResponse, self).__init__(request_id=requestId, 12 | client=source, application_instance_id=applicationInstanceId, 13 | erroneous=erroneous, error_code=errorCode, 14 | error_type=errorType, error_message=errorMessage) 15 | 16 | self._trace_points = tracePoints 17 | 18 | 19 | @property 20 | def trace_points(self): 21 | return self._trace_points 22 | 23 | 24 | @trace_points.setter 25 | def trace_points(self, trace_points): 26 | self._trace_points = trace_points -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/composite_condition.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.binary_operator import BinaryOperator 2 | from tracepointdebug.probe.condition.condition import Condition 3 | 4 | 5 | class CompositeCondition(Condition): 6 | 7 | def __init__(self, conditions, operators): 8 | self.conditions = conditions 9 | self.operators = operators 10 | 11 | def evaluate(self, condition_context): 12 | result = None 13 | for i in range(len(self.conditions)): 14 | condition = self.conditions[i] 15 | evaluation_result = condition.evaluate(condition_context) 16 | if result is None: 17 | result = evaluation_result 18 | else: 19 | operator = self.operators[i-1] 20 | if operator == BinaryOperator.AND: 21 | result = result and evaluation_result 22 | elif operator == BinaryOperator.OR: 23 | result = result or evaluation_result 24 | 25 | if result is not None: 26 | return result 27 | return False 28 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/response/get_config_response_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.handler.response.response_handler import ResponseHandler 2 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 3 | from tracepointdebug.probe.response.dynamicConfig.get_config_response import GetConfigResponse 4 | 5 | import logging 6 | logger = logging.getLogger(__name__) 7 | 8 | class GetConfigResponseHandler(ResponseHandler): 9 | RESPONSE_NAME = "GetConfigResponse" 10 | 11 | 12 | @staticmethod 13 | def get_response_name(): 14 | return GetConfigResponseHandler.RESPONSE_NAME 15 | 16 | 17 | @staticmethod 18 | def get_response_cls(): 19 | return GetConfigResponse 20 | 21 | 22 | @staticmethod 23 | def handle_response(response): 24 | try: 25 | config = response.config 26 | dynamic_config_manager = DynamicConfigManager.instance() 27 | dynamic_config_manager.update_config(config) 28 | except Exception as e: 29 | logger.error("Error on connection, msg: {}".format(response.config)) -------------------------------------------------------------------------------- /tracepointdebug/broker/application/application_filter.py: -------------------------------------------------------------------------------- 1 | class ApplicationFilter: 2 | 3 | @property 4 | def name(self): 5 | return self._name 6 | 7 | 8 | @name.setter 9 | def name(self, name): 10 | self._name = name 11 | 12 | 13 | @property 14 | def stage(self): 15 | return self._stage 16 | 17 | 18 | @stage.setter 19 | def stage(self, stage): 20 | self._stage = stage 21 | 22 | 23 | @property 24 | def version(self): 25 | return self._version 26 | 27 | 28 | @version.setter 29 | def version(self, version): 30 | self._version = version 31 | 32 | 33 | @property 34 | def custom_tags(self): 35 | return self._custom_tags 36 | 37 | 38 | @custom_tags.setter 39 | def custom_tags(self, custom_tags): 40 | self._custom_tags = custom_tags 41 | 42 | 43 | def to_json(self): 44 | return { 45 | "name": self.name, 46 | "stage": self.stage, 47 | "version": self.version, 48 | "customTags": self.custom_tags 49 | } -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/native_module.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NATIVE_MODULE_H_ 18 | #define DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NATIVE_MODULE_H_ 19 | 20 | namespace devtools { 21 | namespace cdbg { 22 | 23 | // Python Cloud Debugger native module entry point 24 | void InitDebuggerNativeModule(); 25 | 26 | } // namespace cdbg 27 | } // namespace devtools 28 | 29 | #endif // DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NATIVE_MODULE_H_ 30 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/errorstack/error_stack_snapshot_failed_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class ErrorStackSnapshotFailedEvent(BaseEvent): 5 | EVENT_NAME = "ErrorStackSnapshotFailedEvent" 6 | 7 | def __init__(self, file, line_no, error_code, error_message): 8 | super(ErrorStackSnapshotFailedEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | self.error_code = error_code 12 | self.error_message = error_message 13 | 14 | def to_json(self): 15 | return { 16 | "name": self.name, 17 | "type": self.get_type(), 18 | "id": self.id, 19 | "fileName": self.file, 20 | "lineNo": self.line_no, 21 | "sendAck": self.send_ack, 22 | "applicationInstanceId": self.application_instance_id, 23 | "applicationName": self.application_name, 24 | "time": self.time, 25 | "hostName": self.hostname, 26 | "errorCode": self.error_code, 27 | "errorMessage": self.error_message 28 | } -------------------------------------------------------------------------------- /tracepointdebug/probe/event/logpoint/log_point_failed_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class LogPointFailedEvent(BaseEvent): 5 | EVENT_NAME = "LogPointFailedEvent" 6 | 7 | def __init__(self, file, line_no, error_code, error_message): 8 | super(LogPointFailedEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | self.error_code = error_code 12 | self.error_message = error_message 13 | 14 | def to_json(self): 15 | return { 16 | "name": self.name, 17 | "type": self.get_type(), 18 | "id": self.id, 19 | "fileName": self.file, 20 | "lineNo": self.line_no, 21 | "sendAck": self.send_ack, 22 | "applicationInstanceId": self.application_instance_id, 23 | "applicationName": self.application_name, 24 | "client": self.client, 25 | "time": self.time, 26 | "hostName": self.hostname, 27 | "errorCode": self.error_code, 28 | "errorMessage": self.error_message 29 | } 30 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/logpoint/put_logpoint_failed_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class PutLogPointFailedEvent(BaseEvent): 5 | EVENT_NAME = "PutLogPointFailedEvent" 6 | 7 | def __init__(self, file, line_no, error_code, error_message): 8 | super(PutLogPointFailedEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | self.error_code = error_code 12 | self.error_message = error_message 13 | 14 | def to_json(self): 15 | return { 16 | "name": self.name, 17 | "type": self.get_type(), 18 | "id": self.id, 19 | "fileName": self.file, 20 | "lineNo": self.line_no, 21 | "sendAck": self.send_ack, 22 | "applicationInstanceId": self.application_instance_id, 23 | "applicationName": self.application_name, 24 | "client": self.client, 25 | "time": self.time, 26 | "hostName": self.hostname, 27 | "errorCode": self.error_code, 28 | "errorMessage": self.error_message 29 | } 30 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/tracepoint/put_tracepoint_failed_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class PutTracePointFailedEvent(BaseEvent): 5 | EVENT_NAME = "PutTracePointFailedEvent" 6 | 7 | def __init__(self, file, line_no, error_code, error_message): 8 | super(PutTracePointFailedEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | self.error_code = error_code 12 | self.error_message = error_message 13 | 14 | def to_json(self): 15 | return { 16 | "name": self.name, 17 | "type": self.get_type(), 18 | "id": self.id, 19 | "fileName": self.file, 20 | "lineNo": self.line_no, 21 | "sendAck": self.send_ack, 22 | "applicationInstanceId": self.application_instance_id, 23 | "applicationName": self.application_name, 24 | "client": self.client, 25 | "time": self.time, 26 | "hostName": self.hostname, 27 | "errorCode": self.error_code, 28 | "errorMessage": self.error_message 29 | } 30 | -------------------------------------------------------------------------------- /tracepointdebug/broker/event/application_status_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class ApplicationStatusEvent(BaseEvent): 5 | EVENT_NAME = "ApplicationStatusEvent" 6 | 7 | def __init__(self, client=None, application=None): 8 | super(ApplicationStatusEvent, self).__init__(client=client) 9 | self._application = application 10 | 11 | @property 12 | def application(self): 13 | return self._application 14 | 15 | @application.setter 16 | def application(self, value): 17 | self._application = value 18 | 19 | def to_json(self): 20 | return { 21 | "name": self.name, 22 | "type": self.get_type(), 23 | "application": self.application, 24 | "id": self.id, 25 | "sendAck": self.send_ack, 26 | "applicationInstanceId": self.application.instance_id, 27 | "applicationName": self.application.name, 28 | "client": self.client, 29 | "time": self.time, 30 | "hostName": self.application.hostname, 31 | "runtime": self.application.runtime, 32 | } 33 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/tracepoint/tracepoint_snapshot_failed_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class TracePointSnapshotFailedEvent(BaseEvent): 5 | EVENT_NAME = "TracePointSnapshotFailedEvent" 6 | 7 | def __init__(self, file, line_no, error_code, error_message): 8 | super(TracePointSnapshotFailedEvent, self).__init__() 9 | self.file = file 10 | self.line_no = line_no 11 | self.error_code = error_code 12 | self.error_message = error_message 13 | 14 | def to_json(self): 15 | return { 16 | "name": self.name, 17 | "type": self.get_type(), 18 | "id": self.id, 19 | "fileName": self.file, 20 | "lineNo": self.line_no, 21 | "sendAck": self.send_ack, 22 | "applicationInstanceId": self.application_instance_id, 23 | "applicationName": self.application_name, 24 | "client": self.client, 25 | "time": self.time, 26 | "hostName": self.hostname, 27 | "errorCode": self.error_code, 28 | "errorMessage": self.error_message 29 | } 30 | -------------------------------------------------------------------------------- /tracepointdebug/broker/application/application_status.py: -------------------------------------------------------------------------------- 1 | class ApplicationStatus(object): 2 | 3 | def __init__(self, instance_id=None, name=None, stage=None, version=None, ip=None, hostname=None, 4 | trace_points=None, log_points=None, runtime=None): 5 | self.instance_id = instance_id 6 | self.name = name 7 | self.stage = stage 8 | self.version = version 9 | self.ip = ip 10 | self.hostname = hostname 11 | self.trace_points = trace_points 12 | if self.trace_points is None: 13 | self.trace_points = [] 14 | self.log_points = log_points 15 | if self.log_points is None: 16 | self.log_points = [] 17 | self.runtime = runtime 18 | 19 | def to_json(self): 20 | return { 21 | "name": self.name, 22 | "instanceId": self.instance_id, 23 | "stage": self.stage, 24 | "version": self.version, 25 | "ip": self.ip, 26 | "hostName": self.hostname, 27 | "tracePoints": self.trace_points, 28 | "logPoints": self.log_points, 29 | "runtime": self.runtime 30 | } 31 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/number_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.typed_operand import TypedOperand 2 | 3 | 4 | class NumberOperand(TypedOperand): 5 | 6 | def __init__(self, value_provider): 7 | super(NumberOperand, self).__init__((float, int), value_provider) 8 | 9 | def is_eq(self, value, condition_context): 10 | cur_val = self.get_value(condition_context) 11 | return cur_val == value 12 | 13 | def is_ne(self, value, condition_context): 14 | cur_val = self.get_value(condition_context) 15 | return cur_val != value 16 | 17 | def is_lt(self, value, condition_context): 18 | cur_val = self.get_value(condition_context) 19 | return cur_val < value 20 | 21 | def is_le(self, value, condition_context): 22 | cur_val = self.get_value(condition_context) 23 | return cur_val <= value 24 | 25 | def is_gt(self, value, condition_context): 26 | cur_val = self.get_value(condition_context) 27 | return cur_val > value 28 | 29 | def is_ge(self, value, condition_context): 30 | cur_val = self.get_value(condition_context) 31 | return cur_val >= value 32 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/Condition.g4: -------------------------------------------------------------------------------- 1 | grammar Condition; 2 | 3 | parse 4 | : expression EOF 5 | ; 6 | 7 | expression 8 | : LPAREN expression RPAREN #parenExpression 9 | | left=expression op=binary right=expression #binaryExpression 10 | | left=operand op=comparator right=operand #comparatorExpression 11 | ; 12 | 13 | comparator 14 | : GT | GE | LT | LE | EQ | NE 15 | ; 16 | 17 | binary 18 | : AND | OR 19 | ; 20 | 21 | BOOLEAN 22 | : TRUE | FALSE 23 | ; 24 | 25 | operand 26 | : BOOLEAN | CHARACTER | NUMBER | STRING | NULL | VARIABLE | PLACEHOLDER 27 | ; 28 | 29 | AND : 'AND' | '&&'; 30 | OR : 'OR' | '||'; 31 | NOT : 'NOT' ; 32 | TRUE : 'true' ; 33 | FALSE : 'false' ; 34 | NULL : 'null' ; 35 | GT : '>' ; 36 | GE : '>=' ; 37 | LT : '<' ; 38 | LE : '<=' ; 39 | EQ : '==' ; 40 | NE : '!=' ; 41 | LPAREN : '(' ; 42 | RPAREN : ')' ; 43 | CHARACTER : '\'' . '\'' ; 44 | NUMBER : '-'? [0-9]+ ( '.' [0-9]+ )? ; 45 | STRING : '"' (~('"' | '\\' | '\r' | '\n') | '\\' ('"' | '\\'))* '"' ; 46 | VARIABLE : [a-zA-Z_][a-zA-Z0-9_.]* ; 47 | PLACEHOLDER : '$' '{' [a-zA-Z0-9_.]+ '}' ; 48 | WS : [ \r\t\u000C\n]+ -> skip ; 49 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/Condition.g4: -------------------------------------------------------------------------------- 1 | grammar Condition; 2 | 3 | parse 4 | : expression EOF 5 | ; 6 | 7 | expression 8 | : LPAREN expression RPAREN #parenExpression 9 | | left=expression op=binary right=expression #binaryExpression 10 | | left=operand op=comparator right=operand #comparatorExpression 11 | ; 12 | 13 | comparator 14 | : GT | GE | LT | LE | EQ | NE 15 | ; 16 | 17 | binary 18 | : AND | OR 19 | ; 20 | 21 | BOOLEAN 22 | : TRUE | FALSE 23 | ; 24 | 25 | operand 26 | : BOOLEAN | CHARACTER | NUMBER | STRING | NULL | VARIABLE | PLACEHOLDER 27 | ; 28 | 29 | AND : 'AND' | '&&'; 30 | OR : 'OR' | '||'; 31 | NOT : 'NOT' ; 32 | TRUE : 'true' ; 33 | FALSE : 'false' ; 34 | NULL : 'null' ; 35 | GT : '>' ; 36 | GE : '>=' ; 37 | LT : '<' ; 38 | LE : '<=' ; 39 | EQ : '==' ; 40 | NE : '!=' ; 41 | LPAREN : '(' ; 42 | RPAREN : ')' ; 43 | CHARACTER : '\'' . '\'' ; 44 | NUMBER : '-'? [0-9]+ ( '.' [0-9]+ )? ; 45 | STRING : '"' (~('"' | '\\' | '\r' | '\n') | '\\' ('"' | '\\'))* '"' ; 46 | VARIABLE : [a-zA-Z_][a-zA-Z0-9_.]* ; 47 | PLACEHOLDER : '$' '{' [a-zA-Z0-9_.]+ '}' ; 48 | WS : [ \r\t\u000C\n]+ -> skip ; 49 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/logpoint/log_point_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class LogPointEvent(BaseEvent): 5 | EVENT_NAME = "LogPointEvent" 6 | 7 | def __init__(self, log_point_id, file, line_no, method_name, log_message, created_at): 8 | super(LogPointEvent, self).__init__() 9 | self.log_point_id = log_point_id 10 | self.file = file 11 | self.line_no = line_no 12 | self.method_name = method_name 13 | self.log_message = log_message 14 | self.created_at = created_at 15 | 16 | def to_json(self): 17 | return { 18 | "logPointId": self.log_point_id, 19 | "name": self.name, 20 | "type": self.get_type(), 21 | "id": self.id, 22 | "fileName": self.file, 23 | "lineNo": self.line_no, 24 | "methodName": self.method_name, 25 | "logMessage": self.log_message, 26 | "sendAck": self.send_ack, 27 | "applicationInstanceId": self.application_instance_id, 28 | "applicationName": self.application_name, 29 | "client": self.client, 30 | "time": self.time, 31 | "hostName": self.hostname, 32 | "createdAt": self.created_at 33 | } 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/errorstack/error_stack_snapshot_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class ErrorStackSnapshotEvent(BaseEvent): 5 | EVENT_NAME = "ErrorStackSnapshotEvent" 6 | 7 | def __init__(self, error_stack_id, file, line_no, method_name, error, frames): 8 | super(ErrorStackSnapshotEvent, self).__init__() 9 | self.error_stack_id = error_stack_id 10 | self.file = file 11 | self.line_no = line_no 12 | self.method_name = method_name 13 | self.error = error 14 | self.frames = frames 15 | 16 | def to_json(self): 17 | return { 18 | "id": self.id, 19 | "name": self.name, 20 | "sendAck": self.send_ack, 21 | "fileName": self.file, 22 | "className": self.file, 23 | "lineNo": self.line_no, 24 | "type": self.get_type(), 25 | "methodName": self.method_name, 26 | "errorStackId": self.error_stack_id, 27 | "applicationInstanceId": self.application_instance_id, 28 | "applicationName": self.application_name, 29 | "time": self.time, 30 | "hostName": self.hostname, 31 | "frames": self.frames, 32 | "error": self.error 33 | } 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/update_trace_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | from tracepointdebug.probe import constants 3 | 4 | 5 | class UpdateTracePointRequest(BaseRequest): 6 | 7 | def __init__(self, request): 8 | super(UpdateTracePointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 9 | self.trace_point_id = request.get("tracePointId") 10 | self.enable_tracing = request.get("enableTracing") 11 | self.condition = request.get("conditionExpression") 12 | self.disable = request.get("disable") 13 | self.tags = request.get("tags", set()) 14 | self.expire_secs = min(int(request.get("expireSecs", constants.TRACEPOINT_DEFAULT_EXPIRY_SECS)), 15 | constants.TRACEPOINT_MAX_EXPIRY_SECS) 16 | self.expire_count = min(int(request.get("expireCount", constants.TRACEPOINT_DEFAULT_EXPIRY_COUNT)), 17 | constants.TRACEPOINT_MAX_EXPIRY_COUNT) 18 | 19 | def get_id(self): 20 | return self.id 21 | 22 | def get_trace_point_id(self): 23 | return self.trace_point_id 24 | 25 | def get_name(self): 26 | return self.__class__.__name__ 27 | 28 | def get_client(self): 29 | return self.client 30 | -------------------------------------------------------------------------------- /tracepointdebug/__init__.py: -------------------------------------------------------------------------------- 1 | import atexit 2 | 3 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 4 | 5 | from . import cdbg_native 6 | from .broker.broker_manager import BrokerManager 7 | from .probe.breakpoints.tracepoint import TracePointManager 8 | from .probe.breakpoints.logpoint import LogPointManager 9 | from .probe.error_stack_manager import ErrorStackManager 10 | 11 | ''' 12 | After importing ConfigProvider for the first time, the __init__.py has been run by interpreter and 13 | whole configuration is reflected to configs. 14 | ''' 15 | 16 | 17 | tracepoint_data_redaction_callback = None 18 | log_data_redaction_callback = None 19 | 20 | import logging 21 | logger = logging.getLogger(__name__) 22 | 23 | def start(tracepoint_data_redaction_callback=None, log_data_redaction_callback=None): 24 | cdbg_native.InitializeModule(None) 25 | _broker_manager = BrokerManager().instance() 26 | TracePointManager(broker_manager=_broker_manager, data_redaction_callback=tracepoint_data_redaction_callback) 27 | LogPointManager(broker_manager=_broker_manager, data_redaction_callback=log_data_redaction_callback) 28 | esm = ErrorStackManager(broker_manager=_broker_manager) 29 | dcm = DynamicConfigManager(broker_manager=_broker_manager) 30 | _broker_manager.initialize() 31 | esm.start() 32 | atexit.register(dcm.handle_detach) -------------------------------------------------------------------------------- /tracepointdebug/probe/request/tracePoint/put_trace_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | from tracepointdebug.probe import constants 3 | 4 | 5 | class PutTracePointRequest(BaseRequest): 6 | 7 | def __init__(self, request): 8 | super(PutTracePointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 9 | self.trace_point_id = request.get("tracePointId") 10 | self.file = request.get("fileName", None) 11 | self.file_hash = request.get("fileHash") 12 | self.line_no = request.get("lineNo", -1) 13 | self.enable_tracing = request.get("enableTracing") 14 | self.condition = request.get("conditionExpression") 15 | self.tags = request.get("tags", set()) 16 | self.expire_secs = min(int(request.get("expireSecs", constants.TRACEPOINT_DEFAULT_EXPIRY_SECS)), 17 | constants.TRACEPOINT_MAX_EXPIRY_SECS) 18 | self.expire_count = min(int(request.get("expireCount", constants.TRACEPOINT_DEFAULT_EXPIRY_COUNT)), 19 | constants.TRACEPOINT_MAX_EXPIRY_COUNT) 20 | 21 | def get_id(self): 22 | return self.id 23 | 24 | def get_trace_point_id(self): 25 | return self.trace_point_id 26 | 27 | def get_name(self): 28 | return self.__class__.__name__ 29 | 30 | def get_client(self): 31 | return self.client 32 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/update_log_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | from tracepointdebug.probe import constants 3 | 4 | 5 | class UpdateLogPointRequest(BaseRequest): 6 | 7 | def __init__(self, request): 8 | super(UpdateLogPointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 9 | self.log_point_id = request.get("logPointId") 10 | self.log_expression = request.get("logExpression") 11 | self.condition = request.get("conditionExpression") 12 | self.disable = request.get("disable") 13 | self.tags = request.get("tags", set()) 14 | self.expire_secs = min(int(request.get("expireSecs", constants.LOGPOINT_DEFAULT_EXPIRY_SECS)), 15 | constants.LOGPOINT_MAX_EXPIRY_SECS) 16 | self.expire_count = min(int(request.get("expireCount", constants.LOGPOINT_DEFAULT_EXPIRY_COUNT)), 17 | constants.LOGPOINT_MAX_EXPIRY_COUNT) 18 | 19 | self.log_level = request.get("logLevel", "INFO") 20 | self.stdout_enabled = request.get("stdoutEnabled", False) 21 | 22 | def get_id(self): 23 | return self.id 24 | 25 | def get_log_point_id(self): 26 | return self.log_point_id 27 | 28 | def get_name(self): 29 | return self.__class__.__name__ 30 | 31 | def get_client(self): 32 | return self.client 33 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/object_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.operand import Operand 2 | 3 | 4 | class ObjectOperand(Operand): 5 | 6 | def __init__(self, value_provider): 7 | self.value_provider = value_provider 8 | 9 | def get_value(self, condition_context): 10 | return self.value_provider.get_value(condition_context) 11 | 12 | def eq(self, operand, condition_context): 13 | cur_val = self.get_value(condition_context) 14 | return cur_val == operand.get_value(condition_context) 15 | 16 | def ne(self, operand, condition_context): 17 | cur_val = self.get_value(condition_context) 18 | return cur_val != operand.get_value(condition_context) 19 | 20 | def lt(self, operand, condition_context): 21 | cur_val = self.get_value(condition_context) 22 | return cur_val < operand.get_value(condition_context) 23 | 24 | def le(self, operand, condition_context): 25 | cur_val = self.get_value(condition_context) 26 | return cur_val <= operand.get_value(condition_context) 27 | 28 | def gt(self, operand, condition_context): 29 | cur_val = self.get_value(condition_context) 30 | return cur_val > operand.get_value(condition_context) 31 | 32 | def ge(self, operand, condition_context): 33 | cur_val = self.get_value(condition_context) 34 | return cur_val >= operand.get_value(condition_context) 35 | -------------------------------------------------------------------------------- /tracepointdebug/probe/breakpoints/tracepoint/trace_point_config.py: -------------------------------------------------------------------------------- 1 | class TracePointConfig(object): 2 | 3 | def __init__(self, trace_point_id, file=None, file_ref=None, line=None, client=None, cond=None, expire_duration=None, expire_hit_count=None, 4 | file_hash=None, disabled=False, tracing_enabled=False, tags=set()): 5 | self.trace_point_id = trace_point_id 6 | self.file = file 7 | self.file_ref = file_ref 8 | self.file_hash = file_hash 9 | self.line = line 10 | self.client = client 11 | self.cond = cond 12 | self.expire_duration = expire_duration 13 | self.expire_hit_count = expire_hit_count 14 | self.disabled = disabled 15 | self.tracing_enabled = tracing_enabled 16 | self.tags = tags 17 | 18 | def get_file_name(self): 19 | return self.file if not self.file_ref else '{0}?ref={1}'.format(self.file, self.file_ref) 20 | 21 | def to_json(self): 22 | return { 23 | "id": self.trace_point_id, 24 | "fileName": self.get_file_name(), 25 | "lineNo": self.line, 26 | "expireSecs": self.expire_duration, 27 | "client": self.client, 28 | "expireCount": self.expire_hit_count, 29 | "disabled": self.disabled, 30 | "tracingEnabled": self.tracing_enabled, 31 | "conditionExpression": self.cond, 32 | "tags": list(self.tags) 33 | } 34 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "715038acfbbf0a1a053d7df5ba95e50b45e4e7a6c5edfc04d5f1830acdab20d9" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.6" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "pystache": { 20 | "hashes": [ 21 | "sha256:93bf92b2149a4c4b58d12142e2c4c6dd5c08d89e4c95afccd4b6efe2ee1d470d" 22 | ], 23 | "index": "pypi", 24 | "version": "==0.6.0" 25 | }, 26 | "six": { 27 | "hashes": [ 28 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 29 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 30 | ], 31 | "index": "pypi", 32 | "version": "==1.16.0" 33 | }, 34 | "websocket-client": { 35 | "hashes": [ 36 | "sha256:074e2ed575e7c822fc0940d31c3ac9bb2b1142c303eafcf3e304e6ce035522e8", 37 | "sha256:6278a75065395418283f887de7c3beafb3aa68dada5cacbe4b214e8d26da499b" 38 | ], 39 | "index": "pypi", 40 | "version": "==1.3.1" 41 | } 42 | }, 43 | "develop": {} 44 | } 45 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/single_condition.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.comparison_operator import ComparisonOperator 2 | from tracepointdebug.probe.condition.condition import Condition 3 | 4 | 5 | class SingleCondition(Condition): 6 | 7 | def __init__(self, left_operand, right_operand, comparison_operator): 8 | self.left_operand = left_operand 9 | self.right_operand = right_operand 10 | self.comparison_operator = comparison_operator 11 | 12 | def evaluate(self, condition_context): 13 | if self.comparison_operator == ComparisonOperator.EQ: 14 | return self.left_operand.eq(self.right_operand, condition_context=condition_context) 15 | if self.comparison_operator == ComparisonOperator.NE: 16 | return self.left_operand.ne(self.right_operand, condition_context=condition_context) 17 | if self.comparison_operator == ComparisonOperator.GE: 18 | return self.left_operand.ge(None, self.right_operand) 19 | if self.comparison_operator == ComparisonOperator.LE: 20 | return self.left_operand.le(self.right_operand, condition_context=condition_context) 21 | if self.comparison_operator == ComparisonOperator.GT: 22 | return self.left_operand.gt(self.right_operand, condition_context=condition_context) 23 | if self.comparison_operator == ComparisonOperator.LT: 24 | return self.left_operand.lt(self.right_operand, condition_context=condition_context) 25 | return False 26 | -------------------------------------------------------------------------------- /tracepointdebug/probe/event/tracepoint/trace_point_snapshot_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.base_event import BaseEvent 2 | 3 | 4 | class TracePointSnapshotEvent(BaseEvent): 5 | EVENT_NAME = "TracePointSnapshotEvent" 6 | 7 | def __init__(self, tracepoint_id, file, line_no, method_name, frames, trace_id=None, transaction_id=None, span_id=None): 8 | super(TracePointSnapshotEvent, self).__init__() 9 | self.tracepoint_id = tracepoint_id 10 | self.file = file 11 | self.line_no = line_no 12 | self.method_name = method_name 13 | self.frames = frames 14 | self.trace_id = trace_id 15 | self.transaction_id = transaction_id 16 | self.span_id = span_id 17 | 18 | def to_json(self): 19 | return { 20 | "name": self.name, 21 | "tracePointId": self.tracepoint_id, 22 | "type": self.get_type(), 23 | "id": self.id, 24 | "fileName": self.file, 25 | "lineNo": self.line_no, 26 | "methodName": self.method_name, 27 | "frames": self.frames, 28 | "traceId": self.trace_id, 29 | "transactionId": self.transaction_id, 30 | "spanId": self.span_id, 31 | "sendAck": self.send_ack, 32 | "applicationInstanceId": self.application_instance_id, 33 | "applicationName": self.application_name, 34 | "client": self.client, 35 | "time": self.time, 36 | "hostName": self.hostname 37 | } 38 | -------------------------------------------------------------------------------- /tracepointdebug/probe/request/logPoint/put_log_point_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | from tracepointdebug.probe import constants 3 | 4 | 5 | class PutLogPointRequest(BaseRequest): 6 | 7 | def __init__(self, request): 8 | super(PutLogPointRequest, self).__init__(id=request.get("id"), client=request.get("client")) 9 | self.log_point_id = request.get("logPointId") 10 | self.file = request.get("fileName", None) 11 | self.file_hash = request.get("fileHash") 12 | self.line_no = request.get("lineNo", -1) 13 | self.condition = request.get("conditionExpression") 14 | self.log_expression = request.get("logExpression") 15 | self.tags = request.get("tags", set()) 16 | self.expire_secs = min(int(request.get("expireSecs", constants.LOGPOINT_DEFAULT_EXPIRY_SECS)), 17 | constants.LOGPOINT_MAX_EXPIRY_SECS) 18 | self.expire_count = min(int(request.get("expireCount", constants.LOGPOINT_DEFAULT_EXPIRY_COUNT)), 19 | constants.LOGPOINT_MAX_EXPIRY_COUNT) 20 | 21 | self.log_level = request.get("logLevel", "INFO") 22 | self.stdout_enabled = request.get("stdoutEnabled", False) 23 | 24 | def get_id(self): 25 | return self.id 26 | 27 | def get_log_point_id(self): 28 | return self.log_point_id 29 | 30 | def get_name(self): 31 | return self.__class__.__name__ 32 | 33 | def get_client(self): 34 | return self.client 35 | -------------------------------------------------------------------------------- /tracepointdebug/config/config_metadata.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.config import config_names 2 | 3 | CONFIG_METADATA = { 4 | config_names.SIDEKICK_APIKEY: { 5 | 'type': 'string', 6 | }, 7 | config_names.SIDEKICK_DEBUG_ENABLE: { 8 | 'type': 'boolean', 9 | 'defaultValue': False, 10 | }, 11 | config_names.SIDEKICK_ERROR_STACK_ENABLE: { 12 | 'type': 'boolean', 13 | 'defaultValue': False, 14 | }, 15 | config_names.SIDEKICK_ERROR_COLLECTION_ENABLE_CAPTURE_FRAME: { 16 | 'type': 'boolean', 17 | 'defaultValue': False, 18 | }, 19 | config_names.SIDEKICK_PRINT_CLOSED_SOCKET_DATA: { 20 | 'type': 'boolean', 21 | 'defaultValue': False, 22 | }, 23 | config_names.SIDEKICK_APPLICATION_ID: { 24 | 'type': 'string', 25 | }, 26 | config_names.SIDEKICK_APPLICATION_INSTANCE_ID: { 27 | 'type': 'string', 28 | }, 29 | config_names.SIDEKICK_APPLICATION_NAME: { 30 | 'type': 'string', 31 | }, 32 | config_names.SIDEKICK_APPLICATION_STAGE: { 33 | 'type': 'string', 34 | }, 35 | config_names.SIDEKICK_APPLICATION_DOMAIN_NAME: { 36 | 'type': 'string', 37 | 'defaultValue': 'API', 38 | }, 39 | config_names.SIDEKICK_APPLICATION_CLASS_NAME: { 40 | 'type': 'string', 41 | 'defaultValue': 'AWS-Lambda', 42 | }, 43 | config_names.SIDEKICK_APPLICATION_VERSION: { 44 | 'type': 'string', 45 | }, 46 | config_names.SIDEKICK_APPLICATION_TAG_PREFIX: { 47 | 'type': 'any', 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /tracepointdebug/probe/tag_manager.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 2 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 3 | import logging 4 | 5 | logger = logging.getLogger(__name__) 6 | 7 | class TagManager(object): 8 | __instance = None 9 | 10 | def __init__(self): 11 | self.trace_point_manager = TracePointManager.instance() 12 | self.log_point_manager = LogPointManager.instance() 13 | TagManager.__instance = self 14 | 15 | @staticmethod 16 | def instance(*args, **kwargs): 17 | return TagManager(*args,**kwargs) if TagManager.__instance is None else TagManager.__instance 18 | 19 | def enable_tag(self, tag, client): 20 | self.trace_point_manager.enable_tag(tag, client) 21 | self.log_point_manager.enable_tag(tag, client) 22 | self._publish_status(client) 23 | 24 | def disable_tag(self, tag, client): 25 | self.trace_point_manager.disable_tag(tag, client) 26 | self.log_point_manager.disable_tag(tag, client) 27 | self._publish_status(client) 28 | 29 | def remove_tag(self, tag, client): 30 | self.trace_point_manager.remove_tag(tag, client) 31 | self.log_point_manager.remove_tag(tag, client) 32 | self._publish_status(client) 33 | 34 | def _publish_status(self, client): 35 | self.trace_point_manager.publish_application_status() 36 | self.log_point_manager.publish_application_status() 37 | if client: 38 | self.trace_point_manager.publish_application_status(client) 39 | self.log_point_manager.publish_application_status(client) 40 | -------------------------------------------------------------------------------- /tracepointdebug/probe/breakpoints/logpoint/log_point_config.py: -------------------------------------------------------------------------------- 1 | class LogPointConfig(object): 2 | 3 | def __init__(self, log_point_id, file=None, file_ref=None, line=None, client=None, log_expression=None, cond=None, expire_duration=None, expire_hit_count=None, 4 | file_hash=None, disabled=False, log_level="INFO", stdout_enabled=False, tags=set()): 5 | self.log_point_id = log_point_id 6 | self.file = file 7 | self.file_ref = file_ref 8 | self.file_hash = file_hash 9 | self.line = line 10 | self.client = client 11 | self.cond = cond 12 | self.expire_duration = expire_duration 13 | self.expire_hit_count = expire_hit_count 14 | self.disabled = disabled 15 | self.log_expression = log_expression 16 | self.log_level = log_level 17 | self.stdout_enabled = stdout_enabled 18 | self.tags = tags 19 | 20 | def get_file_name(self): 21 | return self.file if not self.file_ref else '{0}?ref={1}'.format(self.file, self.file_ref) 22 | 23 | def to_json(self): 24 | return { 25 | "id": self.log_point_id, 26 | "fileName": self.get_file_name(), 27 | "lineNo": self.line, 28 | "expireSecs": self.expire_duration, 29 | "client": self.client, 30 | "expireCount": self.expire_hit_count, 31 | "disabled": self.disabled, 32 | "logExpression": self.log_expression, 33 | "logLevel": self.log_level, 34 | "stdoutEnabled": self.stdout_enabled, 35 | "conditionExpression": self.cond, 36 | "tags": list(self.tags) 37 | } 38 | -------------------------------------------------------------------------------- /tracepointdebug/broker/request/get_config_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | from uuid import uuid4 4 | from tracepointdebug.broker.application.application_filter import ApplicationFilter 5 | 6 | class GetConfigRequest(BaseRequest): 7 | 8 | 9 | def __init__(self, name, version, stage, customTags): 10 | super(GetConfigRequest, self).__init__(str(uuid4())) 11 | self._application_filter = ApplicationFilter() 12 | self._application_filter.name = name 13 | self._application_filter.version = version 14 | self._application_filter.stage = stage 15 | self._application_filter.custom_tags = customTags 16 | 17 | def get_id(self): 18 | return self.id 19 | 20 | 21 | def get_name(self): 22 | return self.__class__.__name__ 23 | 24 | 25 | @property 26 | def application_filter(self): 27 | return self._application_filter 28 | 29 | 30 | @application_filter.setter 31 | def application_filter(self, application_filter): 32 | self._application_filter = application_filter 33 | 34 | 35 | def to_json(self): 36 | return { 37 | "type": self.get_type(), 38 | "name": self.get_name(), 39 | "id": self.id, 40 | "applicationFilter": self.application_filter, 41 | "applicationFilterName": self.application_filter.name, 42 | "applicationFilterStage": self.application_filter.stage, 43 | "applicationFilterVersion": self.application_filter.version, 44 | "applicationFilterCustomTags": self.application_filter.custom_tags, 45 | } -------------------------------------------------------------------------------- /tracepointdebug/probe/source_code_helper.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from functools import wraps 3 | 4 | import six 5 | from tracepointdebug.utils import debug_logger 6 | 7 | 8 | def memoize(function): 9 | memo = {} 10 | 11 | @wraps(function) 12 | def wrapper(*args): 13 | try: 14 | return memo[args] 15 | except KeyError: 16 | rv = function(*args) 17 | memo[args] = rv 18 | return rv 19 | 20 | return wrapper 21 | 22 | 23 | def get_source_code(file_path): 24 | if file_path is None or file_path.endswith('.pyc'): 25 | return None 26 | try: 27 | with open(file_path, 'rb') as f: 28 | file_content = f.read() 29 | return file_content 30 | except IOError as e: 31 | debug_logger('Error reading file from file path: ' + file_path + ' err:', e) 32 | return None 33 | 34 | 35 | @memoize 36 | def get_source_code_hash(file_path): 37 | source_code = get_source_code(file_path) 38 | if source_code is None: 39 | return None 40 | 41 | if six.PY2: 42 | source_code = source_code.replace('\r\n', '\n') \ 43 | .replace('\r\x00\n\x00', '\n\x00') \ 44 | .replace('\r', '\n') 45 | else: 46 | source_code = source_code.decode().replace('\r\n', '\n') \ 47 | .replace('\r\x00\n\x00', '\n\x00') \ 48 | .replace('\r', '\n').encode('UTF8') 49 | 50 | try: 51 | source_hash = hashlib.sha256(source_code).hexdigest() 52 | return source_hash 53 | except Exception as e: 54 | debug_logger('Unable to calculate hash of source code from file %s error: %s' % (file_path, e)) 55 | 56 | return None 57 | -------------------------------------------------------------------------------- /tracepointdebug/broker/request/filter_logpoints_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | from uuid import uuid4 4 | from tracepointdebug.broker.application.application_filter import ApplicationFilter 5 | 6 | class FilterLogPointsRequest(BaseRequest): 7 | 8 | 9 | def __init__(self, name, version, stage, customTags): 10 | super(FilterLogPointsRequest, self).__init__(str(uuid4())) 11 | self._application_filter = ApplicationFilter() 12 | self._application_filter.name = name 13 | self._application_filter.version = version 14 | self._application_filter.stage = stage 15 | self._application_filter.custom_tags = customTags 16 | 17 | def get_id(self): 18 | return self.id 19 | 20 | 21 | def get_name(self): 22 | return self.__class__.__name__ 23 | 24 | 25 | @property 26 | def application_filter(self): 27 | return self._application_filter 28 | 29 | 30 | @application_filter.setter 31 | def application_filter(self, application_filter): 32 | self._application_filter = application_filter 33 | 34 | 35 | def to_json(self): 36 | return { 37 | "type": self.get_type(), 38 | "name": self.get_name(), 39 | "id": self.id, 40 | "applicationFilter": self.application_filter, 41 | "applicationFilterName": self.application_filter.name, 42 | "applicationFilterStage": self.application_filter.stage, 43 | "applicationFilterVersion": self.application_filter.version, 44 | "applicationFilterCustomTags": self.application_filter.custom_tags, 45 | } -------------------------------------------------------------------------------- /tracepointdebug/broker/request/filter_tracepoints_request.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.request.base_request import BaseRequest 2 | 3 | from uuid import uuid4 4 | from tracepointdebug.broker.application.application_filter import ApplicationFilter 5 | 6 | class FilterTracePointsRequest(BaseRequest): 7 | 8 | 9 | def __init__(self, name, version, stage, customTags): 10 | super(FilterTracePointsRequest, self).__init__(str(uuid4())) 11 | self._application_filter = ApplicationFilter() 12 | self._application_filter.name = name 13 | self._application_filter.version = version 14 | self._application_filter.stage = stage 15 | self._application_filter.custom_tags = customTags 16 | 17 | def get_id(self): 18 | return self.id 19 | 20 | 21 | def get_name(self): 22 | return self.__class__.__name__ 23 | 24 | 25 | @property 26 | def application_filter(self): 27 | return self._application_filter 28 | 29 | 30 | @application_filter.setter 31 | def application_filter(self, application_filter): 32 | self._application_filter = application_filter 33 | 34 | 35 | def to_json(self): 36 | return { 37 | "type": self.get_type(), 38 | "name": self.get_name(), 39 | "id": self.id, 40 | "applicationFilter": self.application_filter, 41 | "applicationFilterName": self.application_filter.name, 42 | "applicationFilterStage": self.application_filter.stage, 43 | "applicationFilterVersion": self.application_filter.version, 44 | "applicationFilterCustomTags": self.application_filter.custom_tags, 45 | } -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tag/enable_probe_tag_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tag.enable_probe_tag_requests import EnableProbeTagRequest 4 | from tracepointdebug.probe.response.tag.enable_probe_tag_response import EnableProbeTagResponse 5 | from tracepointdebug.probe.tag_manager import TagManager 6 | 7 | class EnableProbeTagRequestHandler(RequestHandler): 8 | REQUEST_NAME = "EnableProbeTagRequest" 9 | 10 | @staticmethod 11 | def get_request_name(): 12 | return EnableProbeTagRequestHandler.REQUEST_NAME 13 | 14 | @staticmethod 15 | def get_request_cls(): 16 | return EnableProbeTagRequest 17 | 18 | @staticmethod 19 | def handle_request(request): 20 | application_info = Application.get_application_info() 21 | try: 22 | tag = request.get_tag() 23 | client=request.get_client() 24 | tag_manager=TagManager().instance() 25 | tag_manager.enable_tag(tag, client) 26 | return EnableProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 27 | application_instance_id=application_info.get('applicationInstanceId')) 28 | except Exception as e: 29 | tp = EnableProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 30 | application_instance_id=application_info.get('applicationInstanceId'), 31 | erroneous=True) 32 | tp.set_error(e) 33 | return tp 34 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tag/remove_probe_tag_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tag.remove_probe_tag_requests import RemoveProbeTagRequest 4 | from tracepointdebug.probe.response.tag.remove_probe_tag_response import RemoveProbeTagResponse 5 | from tracepointdebug.probe.tag_manager import TagManager 6 | 7 | 8 | class RemoveProbeTagRequestHandler(RequestHandler): 9 | REQUEST_NAME = "RemoveProbeTagRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return RemoveProbeTagRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return RemoveProbeTagRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | tag = request.get_tag() 24 | client = request.get_client() 25 | tag_manager = TagManager().instance() 26 | tag_manager.remove_tag(tag, client) 27 | return RemoveProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 28 | application_instance_id=application_info.get('applicationInstanceId')) 29 | except Exception as e: 30 | tp = RemoveProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId'), 32 | erroneous=True) 33 | tp.set_error(e) 34 | return tp 35 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tag/disable_probe_tag_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tag.disable_probe_tag_requests import DisableProbeTagRequest 4 | from tracepointdebug.probe.response.tag.disable_probe_tag_response import DisableProbeTagResponse 5 | from tracepointdebug.probe.tag_manager import TagManager 6 | 7 | 8 | class DisableProbeTagRequestHandler(RequestHandler): 9 | REQUEST_NAME = "DisableProbeTagRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return DisableProbeTagRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return DisableProbeTagRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | tag = request.get_tag() 24 | client = request.get_client() 25 | tag_manager = TagManager().instance() 26 | tag_manager.disable_tag(tag, client) 27 | return DisableProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 28 | application_instance_id=application_info.get('applicationInstanceId')) 29 | except Exception as e: 30 | tp = DisableProbeTagResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId'), 32 | erroneous=True) 33 | tp.set_error(e) 34 | return tp 35 | -------------------------------------------------------------------------------- /tracepointdebug/probe/ratelimit/rate_limiter.py: -------------------------------------------------------------------------------- 1 | from threading import Lock 2 | 3 | from tracepointdebug.probe.ratelimit.rate_limit_result import RateLimitResult 4 | 5 | SECONDS_IN_MINUTE = 60 6 | RATE_LIMIT_WINDOW = 4 7 | RATE_LIMIT_IDX_MASK = RATE_LIMIT_WINDOW - 1 8 | LIMIT_IN_MINUTE = 1000 9 | 10 | 11 | class RateLimitInfo(object): 12 | def __init__(self, minute): 13 | self._lock = Lock() 14 | self.minute = minute 15 | self.count = 0 16 | 17 | def increment_and_get(self): 18 | with self._lock: 19 | self.count += 1 20 | count = self.count 21 | return count 22 | 23 | 24 | class RateLimiter(object): 25 | def __init__(self): 26 | self._lock = Lock() 27 | self.rate_limit_infos = [None] * RATE_LIMIT_WINDOW 28 | 29 | def check_rate_limit(self, current_time): 30 | current_min = int(current_time / SECONDS_IN_MINUTE) 31 | rate_limit_info_idx = current_min & RATE_LIMIT_IDX_MASK 32 | with self._lock: 33 | rate_limit_info = self.rate_limit_infos[rate_limit_info_idx] 34 | if rate_limit_info is None or rate_limit_info.minute < current_min: 35 | rate_limit_info = RateLimitInfo(current_min) 36 | self.rate_limit_infos[rate_limit_info_idx] = rate_limit_info 37 | elif rate_limit_info.minute > current_min: 38 | return RateLimitResult.OK 39 | 40 | count = rate_limit_info.increment_and_get() 41 | if count < LIMIT_IN_MINUTE: 42 | return RateLimitResult.OK 43 | elif count == LIMIT_IN_MINUTE: 44 | return RateLimitResult.HIT 45 | else: 46 | return RateLimitResult.EXCEEDED 47 | 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Sidekick Agent 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build_wheels_linux: 14 | name: Build wheels on ${{ matrix.os }} 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ubuntu-latest] 19 | python-version: [3.8] 20 | env: 21 | CIBW_ARCHS_LINUX: x86_64 22 | CIBW_BUILD: "cp27-* cp36-* cp37-* cp38-* cp39-*" 23 | steps: 24 | - uses: actions/checkout@v2 25 | 26 | - name: Setup Python 27 | uses: actions/setup-python@v2 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | - name: Build wheels 31 | uses: pypa/cibuildwheel@v1.12.0 32 | env: 33 | CIBW_BEFORE_ALL: bash build.sh 34 | - uses: actions/upload-artifact@v2 35 | with: 36 | path: ./wheelhouse/*.whl 37 | 38 | build_wheels_macos: 39 | name: Build wheel on ${{ matrix.os }} 40 | runs-on: ${{ matrix.os }} 41 | strategy: 42 | fail-fast: true 43 | matrix: 44 | os: [macos-latest] 45 | python-version: [3.8] 46 | env: 47 | CIBW_ARCHS_MACOS: x86_64 48 | CIBW_BUILD: "cp27-* cp36-* cp37-* cp38-* cp39-*" 49 | steps: 50 | - uses: actions/checkout@v2 51 | 52 | - name: Setup Python 53 | uses: actions/setup-python@v2 54 | with: 55 | python-version: ${{ matrix.python-version }} 56 | - name: Build wheels 57 | uses: pypa/cibuildwheel@v1.12.0 58 | env: 59 | CIBW_BEFORE_ALL: bash build.sh 60 | - uses: actions/upload-artifact@v2 61 | with: 62 | path: ./wheelhouse/*.whl 63 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/Condition.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | null 4 | null 5 | null 6 | 'NOT' 7 | 'true' 8 | 'false' 9 | 'null' 10 | '>' 11 | '>=' 12 | '<' 13 | '<=' 14 | '==' 15 | '!=' 16 | '(' 17 | ')' 18 | null 19 | null 20 | null 21 | null 22 | null 23 | null 24 | 25 | token symbolic names: 26 | null 27 | BOOLEAN 28 | AND 29 | OR 30 | NOT 31 | TRUE 32 | FALSE 33 | NULL 34 | GT 35 | GE 36 | LT 37 | LE 38 | EQ 39 | NE 40 | LPAREN 41 | RPAREN 42 | CHARACTER 43 | NUMBER 44 | STRING 45 | VARIABLE 46 | PLACEHOLDER 47 | WS 48 | 49 | rule names: 50 | parse 51 | expression 52 | comparator 53 | binary 54 | operand 55 | 56 | 57 | atn: 58 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 23, 42, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 25, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 31, 10, 3, 12, 3, 14, 3, 34, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 2, 3, 4, 7, 2, 4, 6, 8, 10, 2, 5, 3, 2, 10, 15, 3, 2, 4, 5, 5, 2, 3, 3, 9, 9, 18, 22, 2, 38, 2, 12, 3, 2, 2, 2, 4, 24, 3, 2, 2, 2, 6, 35, 3, 2, 2, 2, 8, 37, 3, 2, 2, 2, 10, 39, 3, 2, 2, 2, 12, 13, 5, 4, 3, 2, 13, 14, 7, 2, 2, 3, 14, 3, 3, 2, 2, 2, 15, 16, 8, 3, 1, 2, 16, 17, 7, 16, 2, 2, 17, 18, 5, 4, 3, 2, 18, 19, 7, 17, 2, 2, 19, 25, 3, 2, 2, 2, 20, 21, 5, 10, 6, 2, 21, 22, 5, 6, 4, 2, 22, 23, 5, 10, 6, 2, 23, 25, 3, 2, 2, 2, 24, 15, 3, 2, 2, 2, 24, 20, 3, 2, 2, 2, 25, 32, 3, 2, 2, 2, 26, 27, 12, 4, 2, 2, 27, 28, 5, 8, 5, 2, 28, 29, 5, 4, 3, 5, 29, 31, 3, 2, 2, 2, 30, 26, 3, 2, 2, 2, 31, 34, 3, 2, 2, 2, 32, 30, 3, 2, 2, 2, 32, 33, 3, 2, 2, 2, 33, 5, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 35, 36, 9, 2, 2, 2, 36, 7, 3, 2, 2, 2, 37, 38, 9, 3, 2, 2, 38, 9, 3, 2, 2, 2, 39, 40, 9, 4, 2, 2, 40, 11, 3, 2, 2, 2, 4, 24, 32] -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/Condition.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | null 4 | null 5 | null 6 | 'NOT' 7 | 'true' 8 | 'false' 9 | 'null' 10 | '>' 11 | '>=' 12 | '<' 13 | '<=' 14 | '==' 15 | '!=' 16 | '(' 17 | ')' 18 | null 19 | null 20 | null 21 | null 22 | null 23 | null 24 | 25 | token symbolic names: 26 | null 27 | BOOLEAN 28 | AND 29 | OR 30 | NOT 31 | TRUE 32 | FALSE 33 | NULL 34 | GT 35 | GE 36 | LT 37 | LE 38 | EQ 39 | NE 40 | LPAREN 41 | RPAREN 42 | CHARACTER 43 | NUMBER 44 | STRING 45 | VARIABLE 46 | PLACEHOLDER 47 | WS 48 | 49 | rule names: 50 | parse 51 | expression 52 | comparator 53 | binary 54 | operand 55 | 56 | 57 | atn: 58 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 23, 42, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 25, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 31, 10, 3, 12, 3, 14, 3, 34, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 2, 3, 4, 7, 2, 4, 6, 8, 10, 2, 5, 3, 2, 10, 15, 3, 2, 4, 5, 5, 2, 3, 3, 9, 9, 18, 22, 2, 38, 2, 12, 3, 2, 2, 2, 4, 24, 3, 2, 2, 2, 6, 35, 3, 2, 2, 2, 8, 37, 3, 2, 2, 2, 10, 39, 3, 2, 2, 2, 12, 13, 5, 4, 3, 2, 13, 14, 7, 2, 2, 3, 14, 3, 3, 2, 2, 2, 15, 16, 8, 3, 1, 2, 16, 17, 7, 16, 2, 2, 17, 18, 5, 4, 3, 2, 18, 19, 7, 17, 2, 2, 19, 25, 3, 2, 2, 2, 20, 21, 5, 10, 6, 2, 21, 22, 5, 6, 4, 2, 22, 23, 5, 10, 6, 2, 23, 25, 3, 2, 2, 2, 24, 15, 3, 2, 2, 2, 24, 20, 3, 2, 2, 2, 25, 32, 3, 2, 2, 2, 26, 27, 12, 4, 2, 2, 27, 28, 5, 8, 5, 2, 28, 29, 5, 4, 3, 5, 29, 31, 3, 2, 2, 2, 30, 26, 3, 2, 2, 2, 31, 34, 3, 2, 2, 2, 32, 30, 3, 2, 2, 2, 32, 33, 3, 2, 2, 2, 33, 5, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 35, 36, 9, 2, 2, 2, 36, 7, 3, 2, 2, 2, 37, 38, 9, 3, 2, 2, 38, 9, 3, 2, 2, 2, 39, 40, 9, 4, 2, 2, 40, 11, 3, 2, 2, 2, 4, 24, 32] -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/dynamicConfig/attach_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 4 | from tracepointdebug.probe.request.dynamicConfig.attach_request import AttachRequest 5 | from tracepointdebug.probe.response.dynamicConfig.attach_response import AttachResponse 6 | 7 | 8 | class AttachRequestHandler(RequestHandler): 9 | REQUEST_NAME = "AttachRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return AttachRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return AttachRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | dynamic_config_manager = DynamicConfigManager.instance() 24 | 25 | dynamic_config_manager.handle_attach() 26 | 27 | dynamic_config_manager.publish_application_status() 28 | if request.get_client() is not None: 29 | dynamic_config_manager.publish_application_status(request.get_client()) 30 | 31 | return AttachResponse(request_id=request.get_id(), client=request.get_client(), 32 | application_instance_id=application_info.get('applicationInstanceId')) 33 | except Exception as e: 34 | ar = AttachResponse(request_id=request.get_id(), client=request.get_client(), 35 | application_instance_id=application_info.get('applicationInstanceId'), 36 | erroneous=True) 37 | ar.set_error(e) 38 | return ar 39 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/dynamicConfig/detach_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 4 | from tracepointdebug.probe.request.dynamicConfig.detach_request import DetachRequest 5 | from tracepointdebug.probe.response.dynamicConfig.detach_response import DetachResponse 6 | 7 | 8 | class DetachRequestHandler(RequestHandler): 9 | REQUEST_NAME = "DetachRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return DetachRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return DetachRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | dynamic_config_manager = DynamicConfigManager.instance() 24 | 25 | dynamic_config_manager.handle_detach() 26 | 27 | dynamic_config_manager.publish_application_status() 28 | if request.get_client() is not None: 29 | dynamic_config_manager.publish_application_status(request.get_client()) 30 | 31 | return DetachResponse(request_id=request.get_id(), client=request.get_client(), 32 | application_instance_id=application_info.get('applicationInstanceId')) 33 | except Exception as e: 34 | dr = DetachResponse(request_id=request.get_id(), client=request.get_client(), 35 | application_instance_id=application_info.get('applicationInstanceId'), 36 | erroneous=True) 37 | dr.set_error(e) 38 | return dr 39 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/enable_log_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.logPoint.enable_log_point_request import EnableLogPointRequest 4 | from tracepointdebug.probe.response.logPoint.enable_log_point_response import EnableLogPointResponse 5 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 6 | 7 | 8 | class EnableLogPointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "EnableLogPointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return EnableLogPointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return EnableLogPointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | log_point_manager = LogPointManager.instance() 24 | log_point_manager.enable_log_point(request.log_point_id, request.get_client()) 25 | 26 | log_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | log_point_manager.publish_application_status(request.get_client()) 29 | 30 | return EnableLogPointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = EnableLogPointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/remove_log_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.logPoint.remove_log_point_request import RemoveLogPointRequest 4 | from tracepointdebug.probe.response.logPoint.remove_log_point_response import RemoveLogPointResponse 5 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 6 | 7 | 8 | class RemoveLogPointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "RemoveLogPointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return RemoveLogPointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return RemoveLogPointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | log_point_manager = LogPointManager.instance() 24 | log_point_manager.remove_log_point(request.log_point_id, request.get_client()) 25 | 26 | log_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | log_point_manager.publish_application_status(request.get_client()) 29 | 30 | return RemoveLogPointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = RemoveLogPointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/disable_log_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 4 | from tracepointdebug.probe.request.logPoint.disable_log_point_request import DisableLogPointRequest 5 | from tracepointdebug.probe.response.logPoint.disable_log_point_response import DisableLogPointResponse 6 | 7 | 8 | class DisableLogPointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "DisableLogPointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return DisableLogPointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return DisableLogPointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | log_point_manager = LogPointManager.instance() 24 | log_point_manager.disable_log_point(request.log_point_id, request.get_client()) 25 | 26 | log_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | log_point_manager.publish_application_status(request.get_client()) 29 | 30 | return DisableLogPointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = DisableLogPointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/dynamicConfig/update_config_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 4 | from tracepointdebug.probe.request.dynamicConfig.update_config_request import UpdateConfigRequest 5 | from tracepointdebug.probe.response.dynamicConfig.update_config_response import UpdateConfigResponse 6 | 7 | 8 | class UpdateConfigRequestHandler(RequestHandler): 9 | REQUEST_NAME = "UpdateConfigRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return UpdateConfigRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return UpdateConfigRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | dynamic_config_manager = DynamicConfigManager.instance() 24 | 25 | dynamic_config_manager.update_config(request.config) 26 | 27 | dynamic_config_manager.publish_application_status() 28 | if request.get_client() is not None: 29 | dynamic_config_manager.publish_application_status(request.get_client()) 30 | 31 | return UpdateConfigResponse(request_id=request.get_id(), client=request.get_client(), 32 | application_instance_id=application_info.get('applicationInstanceId')) 33 | except Exception as e: 34 | ucr = UpdateConfigResponse(request_id=request.get_id(), client=request.get_client(), 35 | application_instance_id=application_info.get('applicationInstanceId'), 36 | erroneous=True) 37 | ucr.set_error(e) 38 | return ucr 39 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/enable_trace_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tracePoint.enable_trace_point_request import EnableTracePointRequest 4 | from tracepointdebug.probe.response.tracePoint.enable_trace_point_response import EnableTracePointResponse 5 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 6 | 7 | 8 | class EnableTracePointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "EnableTracePointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return EnableTracePointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return EnableTracePointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | trace_point_manager = TracePointManager.instance() 24 | trace_point_manager.enable_trace_point(request.trace_point_id, request.get_client()) 25 | 26 | trace_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | trace_point_manager.publish_application_status(request.get_client()) 29 | 30 | return EnableTracePointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = EnableTracePointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/remove_trace_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tracePoint.remove_trace_point_request import RemoveTracePointRequest 4 | from tracepointdebug.probe.response.tracePoint.remove_trace_point_response import RemoveTracePointResponse 5 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 6 | 7 | 8 | class RemoveTracePointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "RemoveTracePointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return RemoveTracePointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return RemoveTracePointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | trace_point_manager = TracePointManager.instance() 24 | trace_point_manager.remove_trace_point(request.trace_point_id, request.get_client()) 25 | 26 | trace_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | trace_point_manager.publish_application_status(request.get_client()) 29 | 30 | return RemoveTracePointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = RemoveTracePointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/python_callback.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVTOOLS_CDBG_DEBUGLETS_PYTHON_PYTHON_CALLBACK_H_ 18 | #define DEVTOOLS_CDBG_DEBUGLETS_PYTHON_PYTHON_CALLBACK_H_ 19 | 20 | #include 21 | 22 | #include "common.h" 23 | #include "python_util.h" 24 | 25 | namespace devtools { 26 | namespace cdbg { 27 | 28 | // Wraps std::function in a zero arguments Python callable. 29 | class PythonCallback { 30 | public: 31 | PythonCallback() {} 32 | 33 | // Creates a zero argument Python callable that will delegate to "callback" 34 | // when invoked. The callback returns will always return None. 35 | static ScopedPyObject Wrap(std::function callback); 36 | 37 | // Disables any futher invocations of "callback_". The "method" is the 38 | // return value of "Wrap". 39 | static void Disable(PyObject* method); 40 | 41 | static PyTypeObject python_type_; 42 | 43 | private: 44 | static PyObject* Run(PyObject* self); 45 | 46 | private: 47 | // Callback to invoke or nullptr if the callback was cancelled. 48 | std::function callback_; 49 | 50 | static PyMethodDef callback_method_def_; 51 | 52 | DISALLOW_COPY_AND_ASSIGN(PythonCallback); 53 | }; 54 | 55 | } // namespace cdbg 56 | } // namespace devtools 57 | 58 | #endif // DEVTOOLS_CDBG_DEBUGLETS_PYTHON_PYTHON_CALLBACK_H_ 59 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/disable_trace_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tracePoint.disable_trace_point_request import DisableTracePointRequest 4 | from tracepointdebug.probe.response.tracePoint.disable_trace_point_response import DisableTracePointResponse 5 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 6 | 7 | 8 | class DisableTracePointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "DisableTracePointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return DisableTracePointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return DisableTracePointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | trace_point_manager = TracePointManager.instance() 24 | trace_point_manager.disable_trace_point(request.trace_point_id, request.get_client()) 25 | 26 | trace_point_manager.publish_application_status() 27 | if request.get_client() is not None: 28 | trace_point_manager.publish_application_status(request.get_client()) 29 | 30 | return DisableTracePointResponse(request_id=request.get_id(), client=request.get_client(), 31 | application_instance_id=application_info.get('applicationInstanceId')) 32 | except Exception as e: 33 | tp = DisableTracePointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId'), 35 | erroneous=True) 36 | tp.set_error(e) 37 | return tp 38 | -------------------------------------------------------------------------------- /tracepointdebug/utils/log/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from tracepointdebug.config import config_names 4 | from tracepointdebug.config.config_provider import ConfigProvider 5 | 6 | loggers = {} 7 | 8 | def get_logger(name): 9 | global loggers 10 | if loggers.get(name): 11 | return loggers.get(name) 12 | else: 13 | format = "%(asctime)s - %(levelname)s - %(name)s - %(message)s" 14 | if name is None: 15 | logger = logging.getLogger(__name__) 16 | else: 17 | logger = logging.getLogger(name) 18 | logger.setLevel(logging.DEBUG) 19 | console_handler = logging.StreamHandler() 20 | console_handler.setLevel(logging.DEBUG) 21 | ch_format = logging.Formatter(format) 22 | console_handler.setFormatter(ch_format) 23 | logger.addHandler(console_handler) 24 | loggers[name] = logger 25 | return logger 26 | 27 | 28 | def log_to_console(message, handler): 29 | logger = get_logger(handler) 30 | logging.getLogger().handlers = [] 31 | logger.debug(message) 32 | 33 | 34 | def debug_logger(msg, handler=None): 35 | if ConfigProvider.get(config_names.SIDEKICK_DEBUG_ENABLE): 36 | if hasattr(msg, '__dict__'): 37 | log_to_console(msg, handler) 38 | display = vars(msg) 39 | log_to_console(display, handler) 40 | for key, _ in display.items(): 41 | debug_logger_helper(getattr(msg, key), handler) 42 | else: 43 | log_to_console(msg, handler) 44 | 45 | 46 | def debug_logger_helper(msg, handler): 47 | if hasattr(msg, '__dict__'): 48 | log_to_console(msg, handler) 49 | display = vars(msg) 50 | log_to_console(display, handler) 51 | for key, _ in display.items(): 52 | debug_logger_helper(getattr(msg, key), handler) 53 | 54 | 55 | def print_log_event_message(created_at, log_level, log_message): 56 | print("{created_at} [{log_level}] {log_message}".format(created_at=created_at, log_level=log_level, log_message=log_message)) -------------------------------------------------------------------------------- /tracepointdebug/broker/response/base_response.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.response.response import Response 2 | from tracepointdebug.probe.coded_exception import CodedException 3 | 4 | 5 | class BaseResponse(Response): 6 | 7 | def __init__(self, request_id=None, client=None, application_instance_id=None, erroneous=False, error_code=None, 8 | error_type=None, error_message=None): 9 | self.request_id = request_id 10 | self.client = client 11 | self.application_instance_id = application_instance_id 12 | self.erroneous = erroneous 13 | self.error_code = error_code 14 | self.error_type = error_type 15 | self.name = self.__class__.__name__ 16 | self.error_message = error_message 17 | 18 | def get_request_id(self): 19 | return self.request_id 20 | 21 | def get_name(self): 22 | return self.name 23 | 24 | def get_client(self): 25 | return self.client 26 | 27 | def get_application_instance_id(self): 28 | return self.application_instance_id 29 | 30 | def is_erroneous(self): 31 | return self.erroneous 32 | 33 | def get_error_code(self): 34 | return self.error_code 35 | 36 | def get_error_type(self): 37 | return self.error_type 38 | 39 | def set_error(self, exception): 40 | if isinstance(exception, CodedException): 41 | self.error_code = exception.code 42 | 43 | self.erroneous = True 44 | self.error_type = exception.__class__.__name__ 45 | self.error_message = str(exception) 46 | 47 | def to_json(self): 48 | return { 49 | "name": self.get_name(), 50 | "requestId": self.request_id, 51 | "applicationInstanceId": self.application_instance_id, 52 | "client": self.client, 53 | "erroneous": self.erroneous, 54 | "errorCode": self.error_code, 55 | "errorMessage": self.error_message, 56 | "source": self.get_source(), 57 | "type": self.get_type() 58 | } 59 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Sidekick Agent 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build_wheels_linux: 8 | name: Build wheels on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] 13 | python-version: [3.8] 14 | env: 15 | CIBW_ARCHS_LINUX: x86_64 16 | CIBW_BUILD: "cp27-* cp36-* cp37-* cp38-* cp39-*" 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Setup Python 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Build wheels 25 | uses: pypa/cibuildwheel@v1.12.0 26 | env: 27 | CIBW_BEFORE_ALL: bash build.sh 28 | - uses: actions/upload-artifact@v2 29 | with: 30 | path: ./wheelhouse/*.whl 31 | 32 | build_wheels_macos: 33 | name: Build wheel on ${{ matrix.os }} 34 | runs-on: ${{ matrix.os }} 35 | strategy: 36 | fail-fast: true 37 | matrix: 38 | os: [macos-latest] 39 | python-version: [3.8] 40 | env: 41 | CIBW_ARCHS_MACOS: x86_64 42 | CIBW_BUILD: "cp27-* cp36-* cp37-* cp38-* cp39-*" 43 | steps: 44 | - uses: actions/checkout@v2 45 | 46 | - name: Setup Python 47 | uses: actions/setup-python@v2 48 | with: 49 | python-version: ${{ matrix.python-version }} 50 | - name: Build wheels 51 | uses: pypa/cibuildwheel@v1.12.0 52 | env: 53 | CIBW_BEFORE_ALL: bash build.sh 54 | - uses: actions/upload-artifact@v2 55 | with: 56 | path: ./wheelhouse/*.whl 57 | 58 | upload_pypi: 59 | needs: [build_wheels_linux, build_wheels_macos] 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/download-artifact@v2 63 | with: 64 | name: artifact 65 | path: wheelhouse 66 | - uses: pypa/gh-action-pypi-publish@release/v1 67 | with: 68 | user: ${{ secrets.SIDEKICK_PYPI_USERNAME }} 69 | password: ${{ secrets.SIDEKICK_PYPI_PASSWORD }} 70 | packages_dir: wheelhouse 71 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python2_runtime/ConditionListener.py: -------------------------------------------------------------------------------- 1 | # Generated from Condition.g4 by ANTLR 4.9 2 | from antlr4 import * 3 | 4 | # This class defines a complete listener for a parse tree produced by ConditionParser. 5 | class ConditionListener(ParseTreeListener): 6 | 7 | # Enter a parse tree produced by ConditionParser#parse. 8 | def enterParse(self, ctx): 9 | pass 10 | 11 | # Exit a parse tree produced by ConditionParser#parse. 12 | def exitParse(self, ctx): 13 | pass 14 | 15 | 16 | # Enter a parse tree produced by ConditionParser#binaryExpression. 17 | def enterBinaryExpression(self, ctx): 18 | pass 19 | 20 | # Exit a parse tree produced by ConditionParser#binaryExpression. 21 | def exitBinaryExpression(self, ctx): 22 | pass 23 | 24 | 25 | # Enter a parse tree produced by ConditionParser#parenExpression. 26 | def enterParenExpression(self, ctx): 27 | pass 28 | 29 | # Exit a parse tree produced by ConditionParser#parenExpression. 30 | def exitParenExpression(self, ctx): 31 | pass 32 | 33 | 34 | # Enter a parse tree produced by ConditionParser#comparatorExpression. 35 | def enterComparatorExpression(self, ctx): 36 | pass 37 | 38 | # Exit a parse tree produced by ConditionParser#comparatorExpression. 39 | def exitComparatorExpression(self, ctx): 40 | pass 41 | 42 | 43 | # Enter a parse tree produced by ConditionParser#comparator. 44 | def enterComparator(self, ctx): 45 | pass 46 | 47 | # Exit a parse tree produced by ConditionParser#comparator. 48 | def exitComparator(self, ctx): 49 | pass 50 | 51 | 52 | # Enter a parse tree produced by ConditionParser#binary. 53 | def enterBinary(self, ctx): 54 | pass 55 | 56 | # Exit a parse tree produced by ConditionParser#binary. 57 | def exitBinary(self, ctx): 58 | pass 59 | 60 | 61 | # Enter a parse tree produced by ConditionParser#operand. 62 | def enterOperand(self, ctx): 63 | pass 64 | 65 | # Exit a parse tree produced by ConditionParser#operand. 66 | def exitOperand(self, ctx): 67 | pass 68 | 69 | 70 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/update_trace_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tracePoint.update_trace_point_request import UpdateTracePointRequest 4 | from tracepointdebug.probe.response.tracePoint.update_trace_point_response import UpdateTracePointResponse 5 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 6 | 7 | 8 | class UpdateTracePointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "UpdateTracePointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return UpdateTracePointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return UpdateTracePointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | trace_point_manager = TracePointManager.instance() 24 | trace_point_manager.update_trace_point(request.trace_point_id, 25 | request.get_client(), request.expire_secs, 26 | request.expire_count, request.enable_tracing, request.condition, 27 | disable=request.disable, tags=request.tags) 28 | 29 | trace_point_manager.publish_application_status() 30 | if request.get_client() is not None: 31 | trace_point_manager.publish_application_status(request.get_client()) 32 | 33 | return UpdateTracePointResponse(request_id=request.get_id(), client=request.get_client(), 34 | application_instance_id=application_info.get('applicationInstanceId')) 35 | except Exception as e: 36 | tp = UpdateTracePointResponse(request_id=request.get_id(), client=request.get_client(), 37 | application_instance_id=application_info.get('applicationInstanceId'), 38 | erroneous=True) 39 | tp.set_error(e) 40 | return tp 41 | -------------------------------------------------------------------------------- /tracepointdebug/broker/event/base_event.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.broker.event.event import Event 2 | 3 | 4 | class BaseEvent(Event): 5 | 6 | def __init__(self, send_ack=False, client=None, time=None, hostname=None, 7 | application_name=None, application_instance_id=None): 8 | self._name = self.__class__.__name__ 9 | self._id = None 10 | self._send_ack = send_ack 11 | self._client = client 12 | self._time = time 13 | self._hostname = hostname 14 | self._application_name = application_name 15 | self._application_instance_id = application_instance_id 16 | 17 | @property 18 | def name(self): 19 | return self._name 20 | 21 | @name.setter 22 | def name(self, _name): 23 | self._name = _name 24 | 25 | @property 26 | def id(self): 27 | return self._id 28 | 29 | @id.setter 30 | def id(self, _id): 31 | self._id = _id 32 | 33 | @property 34 | def send_ack(self): 35 | return self._send_ack 36 | 37 | @send_ack.setter 38 | def send_ack(self, value): 39 | self._send_ack = value 40 | 41 | @property 42 | def client(self): 43 | return self._client 44 | 45 | @client.setter 46 | def client(self, value): 47 | self._client = value 48 | 49 | @property 50 | def time(self): 51 | return self._time 52 | 53 | @time.setter 54 | def time(self, value): 55 | self._time = value 56 | 57 | @property 58 | def hostname(self): 59 | return self._hostname 60 | 61 | @hostname.setter 62 | def hostname(self, value): 63 | self._hostname = value 64 | 65 | @property 66 | def application_name(self): 67 | return self._application_name 68 | 69 | @application_name.setter 70 | def application_name(self, value): 71 | self._application_name = value 72 | 73 | @property 74 | def application_instance_id(self): 75 | return self._application_instance_id 76 | 77 | @application_instance_id.setter 78 | def application_instance_id(self, value): 79 | self._application_instance_id = value 80 | 81 | def get_type(self): 82 | return "Event" 83 | 84 | def get_name(self): 85 | return self.__class__.__name__ 86 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/update_log_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.logPoint.update_log_point_request import UpdateLogPointRequest 4 | from tracepointdebug.probe.response.logPoint.update_log_point_response import UpdateLogPointResponse 5 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 6 | 7 | 8 | class UpdateLogPointRequestHandler(RequestHandler): 9 | REQUEST_NAME = "UpdateLogPointRequest" 10 | 11 | @staticmethod 12 | def get_request_name(): 13 | return UpdateLogPointRequestHandler.REQUEST_NAME 14 | 15 | @staticmethod 16 | def get_request_cls(): 17 | return UpdateLogPointRequest 18 | 19 | @staticmethod 20 | def handle_request(request): 21 | application_info = Application.get_application_info() 22 | try: 23 | log_point_manager = LogPointManager.instance() 24 | log_point_manager.update_log_point(request.log_point_id, 25 | request.get_client(), request.expire_secs, 26 | request.expire_count, request.log_expression, request.condition, 27 | disabled=request.disable, log_level=request.log_level, 28 | stdout_enabled=request.stdout_enabled, tags=request.tags) 29 | 30 | log_point_manager.publish_application_status() 31 | if request.get_client() is not None: 32 | log_point_manager.publish_application_status(request.get_client()) 33 | 34 | return UpdateLogPointResponse(request_id=request.get_id(), client=request.get_client(), 35 | application_instance_id=application_info.get('applicationInstanceId')) 36 | except Exception as e: 37 | tp = UpdateLogPointResponse(request_id=request.get_id(), client=request.get_client(), 38 | application_instance_id=application_info.get('applicationInstanceId'), 39 | erroneous=True) 40 | tp.set_error(e) 41 | return tp 42 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/rate_limit.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVTOOLS_CDBG_DEBUGLETS_PYTHON_RATE_LIMIT_H_ 18 | #define DEVTOOLS_CDBG_DEBUGLETS_PYTHON_RATE_LIMIT_H_ 19 | 20 | #include 21 | 22 | #include "leaky_bucket.h" 23 | #include "common.h" 24 | 25 | namespace devtools { 26 | namespace cdbg { 27 | 28 | // Initializes quota objects if not initialized yet. 29 | void LazyInitializeRateLimit(); 30 | 31 | // Release quota objects. 32 | void CleanupRateLimit(); 33 | 34 | // Condition and dynamic logging rate limits are defined as the maximum 35 | // number of lines of Python code per second to execute. These rate are enforced 36 | // as following: 37 | // 1. If a single breakpoint contributes to half the maximum rate, that 38 | // breakpoint will be deactivated. 39 | // 2. If all breakpoints combined hit the maximum rate, any breakpoint to 40 | // exceed the limit gets disabled. 41 | // 42 | // The first rule ensures that in vast majority of scenarios expensive 43 | // breakpoints will get deactivated. The second rule guarantees that in edge 44 | // case scenarios the total amount of time spent in condition evaluation will 45 | // not exceed the alotted limit. 46 | // 47 | // While the actual cost of Python lines is not uniform, we only care about the 48 | // average. All limits ignore the number of CPUs since Python is inherently 49 | // single threaded. 50 | LeakyBucket* GetGlobalConditionQuota(); 51 | std::unique_ptr CreatePerBreakpointConditionQuota(); 52 | LeakyBucket* GetGlobalDynamicLogQuota(); 53 | LeakyBucket* GetGlobalDynamicLogBytesQuota(); 54 | } // namespace cdbg 55 | } // namespace devtools 56 | 57 | #endif // DEVTOOLS_CDBG_DEBUGLETS_PYTHON_RATE_LIMIT_H_ 58 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/python_callback.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Ensure that Python.h is included before any other header. 18 | #include "common.h" 19 | 20 | #include "python_callback.h" 21 | 22 | namespace devtools { 23 | namespace cdbg { 24 | 25 | PyTypeObject PythonCallback::python_type_ = 26 | DefaultTypeDefinition(CDBG_SCOPED_NAME("_Callback")); 27 | 28 | PyMethodDef PythonCallback::callback_method_def_ = { 29 | const_cast("Callback"), // ml_name 30 | reinterpret_cast(PythonCallback::Run), // ml_meth 31 | METH_NOARGS, // ml_flags 32 | const_cast("") // ml_doc 33 | }; 34 | 35 | ScopedPyObject PythonCallback::Wrap(std::function callback) { 36 | ScopedPyObject callback_obj = NewNativePythonObject(); 37 | py_object_cast(callback_obj.get())->callback_ = callback; 38 | 39 | ScopedPyObject callback_method(PyCFunction_NewEx( 40 | &callback_method_def_, 41 | callback_obj.get(), 42 | GetDebugletModule())); 43 | 44 | return callback_method; 45 | } 46 | 47 | 48 | void PythonCallback::Disable(PyObject* method) { 49 | DCHECK(PyCFunction_Check(method)); 50 | 51 | auto instance = py_object_cast(PyCFunction_GET_SELF(method)); 52 | DCHECK(instance); 53 | 54 | instance->callback_ = nullptr; 55 | } 56 | 57 | 58 | PyObject* PythonCallback::Run(PyObject* self) { 59 | auto instance = py_object_cast(self); 60 | 61 | if (instance->callback_ != nullptr) { 62 | instance->callback_(); 63 | } 64 | 65 | Py_RETURN_NONE; 66 | } 67 | 68 | } // namespace cdbg 69 | } // namespace devtools 70 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/tracePoint/put_trace_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.tracePoint.put_trace_point_request import PutTracePointRequest 4 | from tracepointdebug.probe.response.tracePoint.put_trace_point_response import PutTracePointResponse 5 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 6 | from tracepointdebug.utils.validation import validate_file_name_and_line_no 7 | 8 | 9 | class PutTracePointRequestHandler(RequestHandler): 10 | REQUEST_NAME = "PutTracePointRequest" 11 | 12 | @staticmethod 13 | def get_request_name(): 14 | return PutTracePointRequestHandler.REQUEST_NAME 15 | 16 | @staticmethod 17 | def get_request_cls(): 18 | return PutTracePointRequest 19 | 20 | @staticmethod 21 | def handle_request(request): 22 | application_info = Application.get_application_info() 23 | try: 24 | validate_file_name_and_line_no(request.file, request.line_no) 25 | trace_point_manager = TracePointManager.instance() 26 | trace_point_manager.put_trace_point(request.trace_point_id, request.file, request.file_hash, 27 | request.line_no, 28 | request.get_client(), request.expire_secs, 29 | request.expire_count, request.enable_tracing, request.condition, 30 | request.tags) 31 | 32 | trace_point_manager.publish_application_status() 33 | if request.get_client() is not None: 34 | trace_point_manager.publish_application_status(request.get_client()) 35 | 36 | return PutTracePointResponse(request_id=request.get_id(), client=request.get_client(), 37 | application_instance_id=application_info.get('applicationInstanceId')) 38 | except Exception as e: 39 | tp = PutTracePointResponse(request_id=request.get_id(), client=request.get_client(), 40 | application_instance_id=application_info.get('applicationInstanceId'), 41 | erroneous=True) 42 | tp.set_error(e) 43 | return tp 44 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/request/logPoint/put_log_point_request_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.application.application import Application 2 | from tracepointdebug.broker.handler.request.request_handler import RequestHandler 3 | from tracepointdebug.probe.request.logPoint.put_log_point_request import PutLogPointRequest 4 | from tracepointdebug.probe.response.logPoint.put_log_point_response import PutLogPointResponse 5 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 6 | from tracepointdebug.utils.validation import validate_file_name_and_line_no 7 | 8 | 9 | class PutLogPointRequestHandler(RequestHandler): 10 | REQUEST_NAME = "PutLogPointRequest" 11 | 12 | @staticmethod 13 | def get_request_name(): 14 | return PutLogPointRequestHandler.REQUEST_NAME 15 | 16 | @staticmethod 17 | def get_request_cls(): 18 | return PutLogPointRequest 19 | 20 | @staticmethod 21 | def handle_request(request): 22 | application_info = Application.get_application_info() 23 | try: 24 | validate_file_name_and_line_no(request.file, request.line_no) 25 | log_point_manager = LogPointManager.instance() 26 | log_point_manager.put_log_point(request.log_point_id, request.file, request.file_hash, 27 | request.line_no, 28 | request.get_client(), request.expire_secs, 29 | request.expire_count, False, 30 | request.log_expression, request.condition, 31 | request.log_level, request.stdout_enabled, request.tags) 32 | 33 | log_point_manager.publish_application_status() 34 | if request.get_client() is not None: 35 | log_point_manager.publish_application_status(request.get_client()) 36 | 37 | return PutLogPointResponse(request_id=request.get_id(), client=request.get_client(), 38 | application_instance_id=application_info.get('applicationInstanceId')) 39 | except Exception as e: 40 | tp = PutLogPointResponse(request_id=request.get_id(), client=request.get_client(), 41 | application_instance_id=application_info.get('applicationInstanceId'), 42 | erroneous=True) 43 | tp.set_error(e) 44 | return tp 45 | -------------------------------------------------------------------------------- /tracepointdebug/trace/trace_support.py: -------------------------------------------------------------------------------- 1 | from inspect import trace 2 | import logging 3 | from .trace_context import TraceContext 4 | logger = logging.getLogger(__name__) 5 | 6 | class TraceSupport: 7 | 8 | TRACEPOINT_SNAPSHOT_EXIST_TAG = "tracepoint.snapshot.exist" 9 | THUNDRA_CHECK_DISABLED = False 10 | OPENTRACING_CHECK_DISABLED = False 11 | 12 | @classmethod 13 | def get_trace_context(cls): 14 | trace_context = cls.get_trace_context_from_thundra() 15 | if not trace_context: 16 | trace_context = cls.get_trace_context_from_opentracing() 17 | return trace_context 18 | 19 | @classmethod 20 | def get_trace_context_from_thundra(cls): 21 | if cls.THUNDRA_CHECK_DISABLED: 22 | return 23 | try: 24 | from thundra.opentracing.tracer import ThundraTracer 25 | from thundra.plugins.invocation import invocation_support 26 | active_span = ThundraTracer.get_instance().get_active_span() 27 | if active_span: 28 | invocation_support.set_agent_tag(cls.TRACEPOINT_SNAPSHOT_EXIST_TAG, True) 29 | return TraceContext( 30 | trace_id=active_span.trace_id, 31 | transaction_id=active_span.transaction_id, 32 | span_id=active_span.span_id) 33 | except (ImportError, AttributeError) as error: 34 | cls.THUNDRA_CHECK_DISABLED = True 35 | except Exception as e: 36 | logger.debug("Unable to get trace context from Thundra: {0}".format(e)) 37 | return 38 | 39 | @classmethod 40 | def get_trace_context_from_opentracing(cls): 41 | if cls.OPENTRACING_CHECK_DISABLED: 42 | return 43 | try: 44 | import opentracing 45 | tracer = opentracing.global_tracer() 46 | if tracer: 47 | span = tracer.active_span 48 | if span: 49 | span_context = span.context 50 | if span_context: 51 | return TraceContext( 52 | trace_id=span_context.trace_id, 53 | transaction_id=None, 54 | span_id=span_context.span_id) 55 | except (ImportError, AttributeError) as error: 56 | cls.OPENTRACING_CHECK_DISABLED = True 57 | except Exception as e: 58 | logger.debug("Unable to get trace context from Opentracing: {0}".format(e)) 59 | return -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | setup.cfg -------------------------------------------------------------------------------- /tracepointdebug/probe/dynamicConfig/dynamic_config_manager.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 2 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 3 | from tracepointdebug.probe.error_stack_manager import ErrorStackManager 4 | from tracepointdebug.probe.snapshot import SnapshotCollectorConfigManager 5 | from tracepointdebug.config import config_names 6 | from tracepointdebug.config.config_provider import ConfigProvider 7 | 8 | _ERROR_COLLECTION_ENABLE_KEY = "errorCollectionEnable" 9 | _ERROR_COLLECTION_ENABLE_CAPTURE_FRAME = "errorCollectionEnableCaptureFrame" 10 | 11 | class DynamicConfigManager(): 12 | __instance = None 13 | 14 | def __init__(self, broker_manager): 15 | self.attached = True 16 | self.trace_point_manager = TracePointManager.instance() 17 | self.log_point_manager = LogPointManager.instance() 18 | self.error_stack_manager = ErrorStackManager.instance() 19 | self.broker_manager = broker_manager 20 | DynamicConfigManager.__instance = self 21 | 22 | @staticmethod 23 | def instance(*args, **kwargs): 24 | return DynamicConfigManager(*args, 25 | **kwargs) if DynamicConfigManager.__instance is None else DynamicConfigManager.__instance 26 | 27 | def handle_attach(self): 28 | self.attached = True 29 | self.broker_manager.publish_request() 30 | self.broker_manager.send_get_config() 31 | 32 | 33 | def handle_detach(self): 34 | self.attached = False 35 | self.trace_point_manager.remove_all_trace_points() 36 | self.log_point_manager.remove_all_log_points() 37 | self.error_stack_manager.shutdown() 38 | 39 | def update_config(self, config): 40 | SnapshotCollectorConfigManager.update_snapshot_config(config) 41 | ConfigProvider.set(config_names.SIDEKICK_ERROR_STACK_ENABLE, config.get(_ERROR_COLLECTION_ENABLE_KEY, False)) 42 | self._update_set_trace_hooks(ConfigProvider.get(config_names.SIDEKICK_ERROR_STACK_ENABLE, False)) 43 | ConfigProvider.set(config_names.SIDEKICK_ERROR_COLLECTION_ENABLE_CAPTURE_FRAME, config.get(_ERROR_COLLECTION_ENABLE_CAPTURE_FRAME, False)) 44 | 45 | def publish_application_status(self, client=None): 46 | self.broker_manager.publish_application_status(client=client) 47 | 48 | def _update_set_trace_hooks(self, error_stack_enable): 49 | if error_stack_enable: 50 | self.error_stack_manager.start() 51 | else: 52 | self.error_stack_manager.shutdown() -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/response/filter_tracepoints_response_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.coded_exception import CodedException 2 | from tracepointdebug.probe.errors import TRACEPOINT_ALREADY_EXIST 3 | from tracepointdebug.probe.breakpoints.tracepoint import TracePointManager 4 | from tracepointdebug.broker.handler.response.response_handler import ResponseHandler 5 | from tracepointdebug.probe.response.tracePoint.filter_tracepoints_response import FilterTracePointsResponse 6 | 7 | from tracepointdebug.utils.validation import validate_file_name_and_line_no 8 | 9 | import logging 10 | logger = logging.getLogger(__name__) 11 | 12 | def _applyTracePoint(trace_point): 13 | try: 14 | validate_file_name_and_line_no(trace_point.get("fileName"), trace_point.get("lineNo")) 15 | condition = trace_point.get("condition", None) 16 | client = trace_point.get("client", None) 17 | file_name = trace_point.get("fileName", None) 18 | trace_point_manager = TracePointManager.instance() 19 | trace_point_manager.put_trace_point(trace_point.get("id", None), file_name, 20 | trace_point.get("fileHash", None), trace_point.get("lineNo",None), 21 | client, trace_point.get("expireDuration", None), trace_point.get("expireCount", None), 22 | trace_point.get("disabled", None), condition = condition, 23 | tags=trace_point.get("tags", set())) 24 | 25 | trace_point_manager.publish_application_status() 26 | if client is not None: 27 | trace_point_manager.publish_application_status(client) 28 | 29 | except Exception as e: 30 | skip_logging = False 31 | if isinstance(e, CodedException): 32 | skip_logging = True if e.code == TRACEPOINT_ALREADY_EXIST.code else False 33 | if not skip_logging: 34 | logger.error("Unable to apply tracepoint %s" % e) 35 | 36 | class FilterTracePointsResponseHandler(ResponseHandler): 37 | RESPONSE_NAME = "FilterTracePointsResponse" 38 | 39 | 40 | @staticmethod 41 | def get_response_name(): 42 | return FilterTracePointsResponseHandler.RESPONSE_NAME 43 | 44 | 45 | @staticmethod 46 | def get_response_cls(): 47 | return FilterTracePointsResponse 48 | 49 | 50 | @staticmethod 51 | def handle_response(response): 52 | trace_points = response.trace_points 53 | for trace_point in trace_points: 54 | _applyTracePoint(trace_point) 55 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/typed_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.operand import Operand 2 | 3 | 4 | class TypedOperand(Operand): 5 | 6 | def __init__(self, value_type, value_provider): 7 | self.value_type = value_type 8 | self.value_provider = value_provider 9 | 10 | def get_value(self, condition_context): 11 | value = self.value_provider.get_value(condition_context) 12 | if value is None or isinstance(value, self.value_type): 13 | return value 14 | return None 15 | 16 | def is_eq(self, value, condition_context): 17 | return False 18 | 19 | def eq(self, operand, condition_context): 20 | value = operand.get_value(condition_context) 21 | if value is None or isinstance(value, self.value_type): 22 | return self.is_eq(value, condition_context) 23 | return False 24 | 25 | def is_ne(self, value, condition_context): 26 | return False 27 | 28 | def ne(self, operand, condition_context): 29 | value = operand.get_value(condition_context) 30 | if value is None or isinstance(value, self.value_type): 31 | return self.is_ne(value, condition_context) 32 | return False 33 | 34 | def is_lt(self, value, condition_context): 35 | return False 36 | 37 | def lt(self, operand, condition_context): 38 | value = operand.get_value(condition_context) 39 | if value is None or isinstance(value, self.value_type): 40 | return self.is_lt(value, condition_context) 41 | return False 42 | 43 | def is_le(self, value, condition_context): 44 | return False 45 | 46 | def le(self, operand, condition_context): 47 | value = operand.get_value(condition_context) 48 | if value is None or isinstance(value, self.value_type): 49 | return self.is_le(value, condition_context) 50 | return False 51 | 52 | def is_gt(self, value, condition_context): 53 | return False 54 | 55 | def gt(self, operand, condition_context): 56 | value = operand.get_value(condition_context) 57 | if value is None or isinstance(value, self.value_type): 58 | return self.is_gt(value, condition_context) 59 | return False 60 | 61 | def is_ge(self, value, condition_context): 62 | return False 63 | 64 | def ge(self, operand, condition_context): 65 | value = operand.get_value(condition_context) 66 | if value is None or isinstance(value, self.value_type): 67 | return self.is_ge(value, condition_context) 68 | return False 69 | -------------------------------------------------------------------------------- /tracepointdebug/application/config_aware_application_info_provider.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | import uuid 4 | 5 | from tracepointdebug.application.application_info_provider import ApplicationInfoProvider 6 | from tracepointdebug.config import config_names 7 | from tracepointdebug.config.config_provider import ConfigProvider 8 | 9 | 10 | class ConfigAwareApplicationInfoProvider(ApplicationInfoProvider): 11 | def __init__(self): 12 | self.application_info = ConfigAwareApplicationInfoProvider.get_application_info_from_config() 13 | if self.application_info.get('applicationId') is None: 14 | self.application_info['applicationId'] = ConfigAwareApplicationInfoProvider.get_default_application_id( 15 | self.application_info['applicationName']) 16 | if self.application_info.get('applicationInstanceId') is None: 17 | self.application_info[ 18 | 'applicationInstanceId'] = ConfigAwareApplicationInfoProvider.get_default_application_instance_id( 19 | self.application_info['applicationName']) 20 | 21 | def get_application_info(self): 22 | return self.application_info 23 | 24 | @staticmethod 25 | def get_application_info_from_config(): 26 | return { 27 | 'applicationId': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_ID), 28 | 'applicationInstanceId': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_INSTANCE_ID), 29 | 'applicationDomainName': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_DOMAIN_NAME, ''), 30 | 'applicationClassName': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_CLASS_NAME, ''), 31 | 'applicationName': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_NAME, ''), 32 | 'applicationVersion': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_VERSION, ''), 33 | 'applicationStage': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_STAGE, ''), 34 | 'applicationRegion': ConfigProvider.get(config_names.SIDEKICK_APPLICATION_REGION, ''), 35 | 'applicationRuntime': 'python', 36 | 'applicationRuntimeVersion': str(sys.version_info[0]), 37 | 'applicationTags': ApplicationInfoProvider.parse_application_tags() 38 | } 39 | 40 | @staticmethod 41 | def get_default_application_id(app_name): 42 | return "python:" + app_name 43 | 44 | @staticmethod 45 | def get_default_application_instance_id(app_name): 46 | hostname = socket.gethostname() 47 | return '{app_name}:{id}@{hostname}'.format(app_name=app_name, id=str(uuid.uuid4()), hostname=hostname) 48 | -------------------------------------------------------------------------------- /tracepointdebug/probe/snapshot/snapshot_collector_config_manager.py: -------------------------------------------------------------------------------- 1 | class DEFAULT_SNAPSHOT_CONFIGS: 2 | MAX_FRAMES = 10 3 | MAX_EXPAND_FRAMES = 1 4 | MAX_PROPERTIES = 10 5 | MAX_PARSE_DEPTH = 3 6 | MAX_VAR_LEN = 256 7 | MAX_SIZE = 32768 8 | 9 | class MAX_SNAPSHOT_CONFIGS: 10 | MAX_FRAMES = 20 11 | MAX_EXPAND_FRAMES = 5 12 | MAX_PROPERTIES = 50 13 | MAX_PARSE_DEPTH = 6 14 | 15 | snapshot_configs = { 16 | "maxFrames": DEFAULT_SNAPSHOT_CONFIGS.MAX_FRAMES, 17 | "maxExpandFrames": DEFAULT_SNAPSHOT_CONFIGS.MAX_EXPAND_FRAMES, 18 | "maxProperties": DEFAULT_SNAPSHOT_CONFIGS.MAX_PROPERTIES, 19 | "maxParseDepth": DEFAULT_SNAPSHOT_CONFIGS.MAX_PARSE_DEPTH, 20 | "maxVarLen": DEFAULT_SNAPSHOT_CONFIGS.MAX_VAR_LEN, 21 | "maxSize": DEFAULT_SNAPSHOT_CONFIGS.MAX_SIZE 22 | } 23 | 24 | class SnapshotCollectorConfigManager(): 25 | 26 | @staticmethod 27 | def get_max_size(): 28 | return snapshot_configs.get("maxSize") 29 | 30 | @staticmethod 31 | def get_max_var_len(): 32 | return snapshot_configs.get("maxVarLen") 33 | 34 | @staticmethod 35 | def get_max_frames(): 36 | return snapshot_configs.get("maxFrames") 37 | 38 | @staticmethod 39 | def get_max_expand_frames(): 40 | return snapshot_configs.get("maxExpandFrames") 41 | 42 | @staticmethod 43 | def get_parse_depth(): 44 | return snapshot_configs.get("maxParseDepth") 45 | 46 | @staticmethod 47 | def get_max_properties(): 48 | return snapshot_configs.get("maxProperties") 49 | 50 | @staticmethod 51 | def update_snapshot_config(update_configs): 52 | max_frames = update_configs.get("maxFrames", DEFAULT_SNAPSHOT_CONFIGS.MAX_FRAMES) 53 | max_expand_frames = update_configs.get("maxExpandFrames", DEFAULT_SNAPSHOT_CONFIGS.MAX_EXPAND_FRAMES) 54 | max_properties = update_configs.get("maxProperties", DEFAULT_SNAPSHOT_CONFIGS.MAX_PROPERTIES) 55 | max_parse_depth = update_configs.get("maxParseDepth", DEFAULT_SNAPSHOT_CONFIGS.MAX_PARSE_DEPTH) 56 | snapshot_configs["maxFrames"] = MAX_SNAPSHOT_CONFIGS.MAX_FRAMES if max_frames > MAX_SNAPSHOT_CONFIGS.MAX_FRAMES else max_frames 57 | snapshot_configs["maxExpandFrames"] = MAX_SNAPSHOT_CONFIGS.MAX_EXPAND_FRAMES if max_expand_frames > MAX_SNAPSHOT_CONFIGS.MAX_EXPAND_FRAMES else max_expand_frames 58 | snapshot_configs["maxProperties"] = MAX_SNAPSHOT_CONFIGS.MAX_PROPERTIES if max_properties > MAX_SNAPSHOT_CONFIGS.MAX_PROPERTIES else max_properties 59 | snapshot_configs["maxParseDepth"] = MAX_SNAPSHOT_CONFIGS.MAX_PARSE_DEPTH if max_parse_depth > MAX_SNAPSHOT_CONFIGS.MAX_PARSE_DEPTH else max_parse_depth -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/nullable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NULLABLE_H_ 18 | #define DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NULLABLE_H_ 19 | 20 | #include "common.h" 21 | 22 | namespace devtools { 23 | namespace cdbg { 24 | 25 | template 26 | class Nullable { 27 | public: 28 | Nullable() : has_value_(false) {} 29 | 30 | // Copy constructor. 31 | Nullable(const Nullable& other) 32 | : has_value_(other.has_value()) { 33 | if (other.has_value()) { 34 | value_ = other.value_; 35 | } 36 | } 37 | 38 | // Implicit initialization from the value of type T. 39 | explicit Nullable(const T& value) : has_value_(true), value_(value) {} 40 | 41 | // Assignment of the value of type Nullable. 42 | Nullable& operator= (const Nullable& other) { 43 | has_value_ = other.has_value(); 44 | if (has_value_) { 45 | value_ = other.value(); 46 | } 47 | 48 | return *this; 49 | } 50 | 51 | // Explicitly sets the value of type T. 52 | void set_value(const T& value) { 53 | has_value_ = true; 54 | value_ = value; 55 | } 56 | 57 | // Reset back to no value. 58 | void clear() { 59 | has_value_ = false; 60 | } 61 | 62 | // Returns true if value is initialized, false otherwise. 63 | bool has_value() const { 64 | return has_value_; 65 | } 66 | 67 | // Explicitly returns stored value. 68 | const T& value() const { 69 | DCHECK(has_value()); 70 | return value_; 71 | } 72 | 73 | bool operator== (const Nullable& other) const { 74 | return (!has_value_ && !other.has_value_) || 75 | (has_value_ && other.has_value_ && (value_ == other.value_)); 76 | } 77 | 78 | bool operator!= (const Nullable& other) const { 79 | return !(*this == other); 80 | } 81 | 82 | private: 83 | bool has_value_; 84 | T value_; 85 | 86 | // Intentionally copyable. 87 | }; 88 | 89 | } // namespace cdbg 90 | } // namespace devtools 91 | 92 | #endif // DEVTOOLS_CDBG_DEBUGLETS_PYTHON_NULLABLE_H_ 93 | -------------------------------------------------------------------------------- /tracepointdebug/probe/handler/response/filter_logpoints_response_handler.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.coded_exception import CodedException 2 | from tracepointdebug.probe.errors import LOGPOINT_ALREADY_EXIST 3 | from tracepointdebug.probe.breakpoints.logpoint import LogPointManager 4 | from tracepointdebug.broker.handler.response.response_handler import ResponseHandler 5 | from tracepointdebug.application.application import Application 6 | from tracepointdebug.probe.response.logPoint.filter_logpoints_response import FilterLogPointsResponse 7 | from tracepointdebug.utils.validation import validate_file_name_and_line_no 8 | 9 | import logging 10 | logger = logging.getLogger(__name__) 11 | 12 | def _applyLogPoint(log_point): 13 | try: 14 | validate_file_name_and_line_no(log_point.get("fileName"), log_point.get("lineNo")) 15 | condition = log_point.get("condition", None) 16 | client = log_point.get("client", None) 17 | file_name = log_point.get("fileName", None) 18 | log_expression = log_point.get("logExpression", "") 19 | log_level = log_point.get("logLevel", "INFO") 20 | stdout_enabled = log_point.get("stdoutEnabled", True) 21 | log_point_manager = LogPointManager.instance() 22 | log_point_manager.put_log_point(log_point.get("id", None), file_name, 23 | log_point.get("fileHash", None), log_point.get("lineNo",None), 24 | client, log_point.get("expireDuration", None), log_point.get("expireCount", None), 25 | log_point.get("disabled", False), log_expression=log_expression, condition=condition, 26 | log_level=log_level, stdout_enabled=stdout_enabled, tags=log_point.get("tags", set())) 27 | 28 | log_point_manager.publish_application_status() 29 | if client is not None: 30 | log_point_manager.publish_application_status(client) 31 | 32 | except Exception as e: 33 | skip_logging = False 34 | if isinstance(e, CodedException): 35 | skip_logging = True if e.code == LOGPOINT_ALREADY_EXIST.code else False 36 | if not skip_logging: 37 | logger.error("Unable to apply logpoint %s" % e) 38 | 39 | class FilterLogPointsResponseHandler(ResponseHandler): 40 | RESPONSE_NAME = "FilterLogPointsResponse" 41 | 42 | 43 | @staticmethod 44 | def get_response_name(): 45 | return FilterLogPointsResponseHandler.RESPONSE_NAME 46 | 47 | 48 | @staticmethod 49 | def get_response_cls(): 50 | return FilterLogPointsResponse 51 | 52 | 53 | @staticmethod 54 | def handle_response(response): 55 | log_points = response.log_points 56 | for log_point in log_points: 57 | _applyLogPoint(log_point) 58 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/antlr4parser/python3_runtime/ConditionListener.py: -------------------------------------------------------------------------------- 1 | # Generated from Condition.g4 by ANTLR 4.9 2 | from antlr4 import * 3 | if __name__ is not None and "." in __name__: 4 | from .ConditionParser import ConditionParser 5 | else: 6 | from ConditionParser import ConditionParser 7 | 8 | # This class defines a complete listener for a parse tree produced by ConditionParser. 9 | class ConditionListener(ParseTreeListener): 10 | 11 | # Enter a parse tree produced by ConditionParser#parse. 12 | def enterParse(self, ctx:ConditionParser.ParseContext): 13 | pass 14 | 15 | # Exit a parse tree produced by ConditionParser#parse. 16 | def exitParse(self, ctx:ConditionParser.ParseContext): 17 | pass 18 | 19 | 20 | # Enter a parse tree produced by ConditionParser#binaryExpression. 21 | def enterBinaryExpression(self, ctx:ConditionParser.BinaryExpressionContext): 22 | pass 23 | 24 | # Exit a parse tree produced by ConditionParser#binaryExpression. 25 | def exitBinaryExpression(self, ctx:ConditionParser.BinaryExpressionContext): 26 | pass 27 | 28 | 29 | # Enter a parse tree produced by ConditionParser#parenExpression. 30 | def enterParenExpression(self, ctx:ConditionParser.ParenExpressionContext): 31 | pass 32 | 33 | # Exit a parse tree produced by ConditionParser#parenExpression. 34 | def exitParenExpression(self, ctx:ConditionParser.ParenExpressionContext): 35 | pass 36 | 37 | 38 | # Enter a parse tree produced by ConditionParser#comparatorExpression. 39 | def enterComparatorExpression(self, ctx:ConditionParser.ComparatorExpressionContext): 40 | pass 41 | 42 | # Exit a parse tree produced by ConditionParser#comparatorExpression. 43 | def exitComparatorExpression(self, ctx:ConditionParser.ComparatorExpressionContext): 44 | pass 45 | 46 | 47 | # Enter a parse tree produced by ConditionParser#comparator. 48 | def enterComparator(self, ctx:ConditionParser.ComparatorContext): 49 | pass 50 | 51 | # Exit a parse tree produced by ConditionParser#comparator. 52 | def exitComparator(self, ctx:ConditionParser.ComparatorContext): 53 | pass 54 | 55 | 56 | # Enter a parse tree produced by ConditionParser#binary. 57 | def enterBinary(self, ctx:ConditionParser.BinaryContext): 58 | pass 59 | 60 | # Exit a parse tree produced by ConditionParser#binary. 61 | def exitBinary(self, ctx:ConditionParser.BinaryContext): 62 | pass 63 | 64 | 65 | # Enter a parse tree produced by ConditionParser#operand. 66 | def enterOperand(self, ctx:ConditionParser.OperandContext): 67 | pass 68 | 69 | # Exit a parse tree produced by ConditionParser#operand. 70 | def exitOperand(self, ctx:ConditionParser.OperandContext): 71 | pass 72 | 73 | 74 | 75 | del ConditionParser -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/module_utils2.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS-IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Provides utility functions for module path processing.""" 16 | 17 | import os 18 | import sys 19 | 20 | 21 | def IsPathSuffix(mod_path, path): 22 | """Checks whether path is a full path suffix of mod_path. 23 | 24 | Args: 25 | mod_path: Must be an absolute path to a source file. Must not have 26 | file extension. 27 | path: A relative path. Must not have file extension. 28 | 29 | Returns: 30 | True if path is a full path suffix of mod_path. False otherwise. 31 | """ 32 | return (mod_path.endswith(path) and 33 | (len(mod_path) == len(path) or 34 | mod_path[:-len(path)].endswith(os.sep))) 35 | 36 | 37 | def GetLoadedModuleBySuffix(path): 38 | """Searches sys.modules to find a module with the given file path. 39 | 40 | Args: 41 | path: Path to the source file. It can be relative or absolute, as suffix 42 | match can handle both. If absolute, it must have already been 43 | sanitized. 44 | 45 | Algorithm: 46 | The given path must be a full suffix of a loaded module to be a valid match. 47 | File extensions are ignored when performing suffix match. 48 | 49 | Example: 50 | path: 'a/b/c.py' 51 | modules: {'a': 'a.py', 'a.b': 'a/b.py', 'a.b.c': 'a/b/c.pyc'] 52 | returns: module('a.b.c') 53 | 54 | Returns: 55 | The module that corresponds to path, or None if such module was not 56 | found. 57 | """ 58 | root = os.path.splitext(path)[0] 59 | for module in sys.modules.values(): 60 | mod_root = os.path.splitext(getattr(module, '__file__', None) or '')[0] 61 | 62 | if not mod_root: 63 | continue 64 | 65 | # While mod_root can contain symlinks, we cannot eliminate them. This is 66 | # because, we must perform exactly the same transformations on mod_root and 67 | # path, yet path can be relative to an unknown directory which prevents 68 | # identifying and eliminating symbolic links. 69 | # 70 | # Therefore, we only convert relative to absolute path. 71 | if not os.path.isabs(mod_root): 72 | mod_root = os.path.join(os.getcwd(), mod_root) 73 | 74 | if IsPathSuffix(mod_root, root): 75 | return module 76 | 77 | return None 78 | -------------------------------------------------------------------------------- /tracepointdebug/probe/condition/operand/variable_operand.py: -------------------------------------------------------------------------------- 1 | from tracepointdebug.probe.condition.operand.boolean_operand import BooleanOperand 2 | from tracepointdebug.probe.condition.operand.null_operand import NullOperand 3 | from tracepointdebug.probe.condition.operand.number_operand import NumberOperand 4 | from tracepointdebug.probe.condition.operand.object_operand import ObjectOperand 5 | from tracepointdebug.probe.condition.operand.operand import Operand 6 | from tracepointdebug.probe.condition.operand.string_operand import StringOperand 7 | from tracepointdebug.probe.condition.variable_value_provider import VariableValueProvider 8 | 9 | 10 | class VariableOperand(Operand): 11 | 12 | def __init__(self, var_name): 13 | var_name = str(var_name) 14 | self.value_provider = VariableValueProvider(var_name) 15 | 16 | def create_variable_operand(self, var_value): 17 | if isinstance(var_value, bool): 18 | return BooleanOperand(self.value_provider) 19 | 20 | if isinstance(var_value, (int, float)): 21 | return NumberOperand(self.value_provider) 22 | 23 | if isinstance(var_value, str): 24 | return StringOperand(self.value_provider) 25 | 26 | import sys 27 | if sys.version_info[0] < 3: 28 | if isinstance(var_value, unicode): 29 | return StringOperand(self.value_provider) 30 | 31 | if isinstance(var_value, object): 32 | return ObjectOperand(self.value_provider) 33 | 34 | return None 35 | 36 | def get_variable_operand(self, condition_context): 37 | value = self.value_provider.get_value(condition_context) 38 | if value is None: 39 | return NullOperand() 40 | return self.create_variable_operand(value) 41 | 42 | def get_value(self, condition_context): 43 | self.value_provider.get_value(condition_context) 44 | 45 | def eq(self, operand, condition_context): 46 | cur_operand = self.get_variable_operand(condition_context) 47 | if cur_operand is None: 48 | return False 49 | return cur_operand.eq(operand, condition_context) 50 | 51 | def ne(self, operand, condition_context): 52 | cur_operand = self.get_variable_operand(condition_context) 53 | if cur_operand is None: 54 | return False 55 | return cur_operand.ne(operand, condition_context) 56 | 57 | def lt(self, operand, condition_context): 58 | cur_operand = self.get_variable_operand(condition_context) 59 | if cur_operand is None: 60 | return False 61 | return cur_operand.lt(operand, condition_context) 62 | 63 | def le(self, operand, condition_context): 64 | cur_operand = self.get_variable_operand(condition_context) 65 | if cur_operand is None: 66 | return False 67 | return cur_operand.le(operand, condition_context) 68 | 69 | def gt(self, operand, condition_context): 70 | cur_operand = self.get_variable_operand(condition_context) 71 | if cur_operand is None: 72 | return False 73 | return cur_operand.gt(operand, condition_context) 74 | 75 | def ge(self, operand, condition_context): 76 | cur_operand = self.get_variable_operand(condition_context) 77 | if cur_operand is None: 78 | return False 79 | return cur_operand.ge(operand, condition_context) 80 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/conditional_breakpoint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef DEVTOOLS_CDBG_DEBUGLETS_PYTHON_CONDITIONAL_BREAKPOINT_H_ 18 | #define DEVTOOLS_CDBG_DEBUGLETS_PYTHON_CONDITIONAL_BREAKPOINT_H_ 19 | 20 | #include "leaky_bucket.h" 21 | #include "common.h" 22 | #include "python_util.h" 23 | 24 | namespace devtools { 25 | namespace cdbg { 26 | 27 | // Breakpoints emulator will typically notify the next layer when a breakpoint 28 | // hits. However there are other situations that the next layer need to be 29 | // aware of. 30 | enum class BreakpointEvent { 31 | // The breakpoint was hit. 32 | Hit, 33 | 34 | // Error occurred (e.g. breakpoint could not be set). 35 | Error, 36 | 37 | // Evaluation of conditional expression is consuming too much resources. It is 38 | // a responsibility of the next layer to disable the offending breakpoint. 39 | GlobalConditionQuotaExceeded, 40 | BreakpointConditionQuotaExceeded, 41 | 42 | // The conditional expression changes state of the program and therefore not 43 | // allowed. 44 | ConditionExpressionMutable, 45 | }; 46 | 47 | 48 | // Implements breakpoint action to evaluate optional breakpoint condition. If 49 | // the condition matches, calls Python callable object. 50 | class ConditionalBreakpoint { 51 | public: 52 | ConditionalBreakpoint(ScopedPyCodeObject condition, ScopedPyObject callback); 53 | 54 | ~ConditionalBreakpoint(); 55 | 56 | void OnBreakpointHit(); 57 | 58 | void OnBreakpointError(); 59 | 60 | private: 61 | // Evaluates breakpoint condition within the context of the specified frame. 62 | // Returns true if the breakpoint doesn't have condition or if condition 63 | // was evaluated to True. Otherwise returns false. Raised exceptions are 64 | // considered as condition not matched. 65 | bool EvaluateCondition(PyFrameObject* frame); 66 | 67 | // Takes "time_ns" tokens from the quota for CPU consumption due to breakpoint 68 | // condition. If the quota is exceeded, this function clears the breakpoint 69 | // and reports "ConditionQuotaExceeded" breakpoint event. 70 | void ApplyConditionQuota(int time_ns); 71 | 72 | // Notifies the next layer through the callable object. 73 | void NotifyBreakpointEvent(BreakpointEvent event, PyFrameObject* frame); 74 | 75 | private: 76 | // Callable object representing the compiled conditional expression to 77 | // evaluate on each breakpoint hit. If the breakpoint has no condition, this 78 | // field will be nullptr. 79 | ScopedPyCodeObject condition_; 80 | 81 | // Python callable object to invoke on breakpoint events. 82 | ScopedPyObject python_callback_; 83 | 84 | // Per breakpoint quota on cost of evaluating breakpoint conditions. See 85 | // "rate_limit.h" file for detailed explanation. 86 | std::unique_ptr per_breakpoint_condition_quota_; 87 | 88 | DISALLOW_COPY_AND_ASSIGN(ConditionalBreakpoint); 89 | }; 90 | 91 | } // namespace cdbg 92 | } // namespace devtools 93 | 94 | #endif // DEVTOOLS_CDBG_DEBUGLETS_PYTHON_CONDITIONAL_BREAKPOINT_H_ 95 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/module_search2.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS-IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Inclusive search for module files.""" 16 | 17 | import os 18 | import sys 19 | 20 | 21 | def Search(path): 22 | """Search sys.path to find a source file that matches path. 23 | 24 | The provided input path may have an unknown number of irrelevant outer 25 | directories (e.g., /garbage1/garbage2/real1/real2/x.py'). This function 26 | does multiple search iterations until an actual Python module file that 27 | matches the input path is found. At each iteration, it strips one leading 28 | directory from the path and searches the directories at sys.path 29 | for a match. 30 | 31 | Examples: 32 | sys.path: ['/x1/x2', '/y1/y2'] 33 | Search order: [.pyo|.pyc|.py] 34 | /x1/x2/a/b/c 35 | /x1/x2/b/c 36 | /x1/x2/c 37 | /y1/y2/a/b/c 38 | /y1/y2/b/c 39 | /y1/y2/c 40 | Filesystem: ['/y1/y2/a/b/c.pyc'] 41 | 42 | 1) Search('a/b/c.py') 43 | Returns '/y1/y2/a/b/c.pyc' 44 | 2) Search('q/w/a/b/c.py') 45 | Returns '/y1/y2/a/b/c.pyc' 46 | 3) Search('q/w/c.py') 47 | Returns 'q/w/c.py' 48 | 49 | The provided input path may also be relative to an unknown directory. 50 | The path may include some or all outer package names. 51 | 52 | Examples (continued): 53 | 54 | 4) Search('c.py') 55 | Returns 'c.py' 56 | 5) Search('b/c.py') 57 | Returns 'b/c.py' 58 | 59 | Args: 60 | path: Path that describes a source file. Must contain .py file extension. 61 | Must not contain any leading os.sep character. 62 | 63 | Returns: 64 | Full path to the matched source file, if a match is found. Otherwise, 65 | returns the input path. 66 | 67 | Raises: 68 | AssertionError: if the provided path is an absolute path, or if it does not 69 | have a .py extension. 70 | """ 71 | def SearchCandidates(p): 72 | """Generates all candidates for the fuzzy search of p.""" 73 | while p: 74 | yield p 75 | (_, _, p) = p.partition(os.sep) 76 | 77 | # Verify that the os.sep is already stripped from the input. 78 | assert not path.startswith(os.sep) 79 | 80 | # Strip the file extension, it will not be needed. 81 | src_root, src_ext = os.path.splitext(path) 82 | assert src_ext == '.py' 83 | 84 | # Search longer suffixes first. Move to shorter suffixes only if longer 85 | # suffixes do not result in any matches. 86 | for src_part in SearchCandidates(src_root): 87 | # Search is done in sys.path order, which gives higher priority to earlier 88 | # entries in sys.path list. 89 | for sys_path in sys.path: 90 | f = os.path.join(sys_path, src_part) 91 | # The order in which we search the extensions does not matter. 92 | for ext in ('.pyo', '.pyc', '.py'): 93 | # The os.path.exists check internally follows symlinks and flattens 94 | # relative paths, so we don't have to deal with it. 95 | fext = f + ext 96 | if os.path.exists(fext): 97 | # Once we identify a matching file in the filesystem, we should 98 | # preserve the (1) potentially-symlinked and (2) 99 | # potentially-non-flattened file path (f+ext), because that's exactly 100 | # how we expect it to appear in sys.modules when we search the file 101 | # there. 102 | return fext 103 | 104 | # A matching file was not found in sys.path directories. 105 | return path 106 | 107 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/rate_limit.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Ensure that Python.h is included before any other header. 18 | #include "common.h" 19 | 20 | #include "rate_limit.h" 21 | 22 | DEFINE_int32( 23 | max_condition_lines_rate, 24 | 5000, 25 | "maximum number of Python lines/sec to spend on condition evaluation"); 26 | 27 | DEFINE_int32( 28 | max_dynamic_log_rate, 29 | 50, // maximum of 50 log entries per second on average 30 | "maximum rate of dynamic log entries in this process; short bursts are " 31 | "allowed to exceed this limit"); 32 | 33 | DEFINE_int32( 34 | max_dynamic_log_bytes_rate, 35 | 20480, // maximum of 20K bytes per second on average 36 | "maximum rate of dynamic log bytes in this process; short bursts are " 37 | "allowed to exceed this limit"); 38 | 39 | namespace devtools { 40 | namespace cdbg { 41 | 42 | // Define capacity of leaky bucket: 43 | // capacity = fill_rate * capacity_factor 44 | // 45 | // The capacity is conceptually unrelated to fill rate, but we don't want to 46 | // expose this knob to the developers. Defining it as a factor of a fill rate 47 | // is a convinient heuristics. 48 | // 49 | // Smaller factor values ensure that a burst of CPU consumption due to the 50 | // debugger wil not impact the service throughput. Longer values will allow the 51 | // burst, and will only disable the breakpoint if CPU consumption due to 52 | // debugger is continuous for a prolonged period of time. 53 | static const double kConditionCostCapacityFactor = 0.1; 54 | static const double kDynamicLogCapacityFactor = 5; 55 | static const double kDynamicLogBytesCapacityFactor = 2; 56 | 57 | static std::unique_ptr g_global_condition_quota; 58 | static std::unique_ptr g_global_dynamic_log_quota; 59 | static std::unique_ptr g_global_dynamic_log_bytes_quota; 60 | 61 | 62 | static int64 GetBaseConditionQuotaCapacity() { 63 | return FLAGS_max_condition_lines_rate * kConditionCostCapacityFactor; 64 | } 65 | 66 | void LazyInitializeRateLimit() { 67 | if (g_global_condition_quota == nullptr) { 68 | g_global_condition_quota.reset(new LeakyBucket( 69 | GetBaseConditionQuotaCapacity(), 70 | FLAGS_max_condition_lines_rate)); 71 | 72 | g_global_dynamic_log_quota.reset(new LeakyBucket( 73 | FLAGS_max_dynamic_log_rate * kDynamicLogCapacityFactor, 74 | FLAGS_max_dynamic_log_rate)); 75 | 76 | g_global_dynamic_log_bytes_quota.reset(new LeakyBucket( 77 | FLAGS_max_dynamic_log_bytes_rate * kDynamicLogBytesCapacityFactor, 78 | FLAGS_max_dynamic_log_bytes_rate)); 79 | } 80 | } 81 | 82 | 83 | void CleanupRateLimit() { 84 | g_global_condition_quota = nullptr; 85 | g_global_dynamic_log_quota = nullptr; 86 | g_global_dynamic_log_bytes_quota = nullptr; 87 | } 88 | 89 | 90 | LeakyBucket* GetGlobalConditionQuota() { 91 | return g_global_condition_quota.get(); 92 | } 93 | 94 | LeakyBucket* GetGlobalDynamicLogQuota() { 95 | return g_global_dynamic_log_quota.get(); 96 | } 97 | 98 | LeakyBucket* GetGlobalDynamicLogBytesQuota() { 99 | return g_global_dynamic_log_bytes_quota.get(); 100 | } 101 | 102 | std::unique_ptr CreatePerBreakpointConditionQuota() { 103 | return std::unique_ptr(new LeakyBucket( 104 | GetBaseConditionQuotaCapacity() / 2, 105 | FLAGS_max_condition_lines_rate / 2)); 106 | } 107 | 108 | } // namespace cdbg 109 | } // namespace devtools 110 | -------------------------------------------------------------------------------- /tracepointdebug/external/googleclouddebugger/leaky_bucket.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Ensure that Python.h is included before any other header in Python debuglet. 18 | #include "common.h" 19 | 20 | #include "leaky_bucket.h" 21 | 22 | #include 23 | #include 24 | 25 | namespace devtools { 26 | namespace cdbg { 27 | 28 | static int64 NowInNanoseconds() { 29 | timespec time; 30 | clock_gettime(CLOCK_MONOTONIC, &time); 31 | return 1000000000LL * time.tv_sec + time.tv_nsec; 32 | } 33 | 34 | 35 | LeakyBucket::LeakyBucket(int64 capacity, int64 fill_rate) 36 | : capacity_(capacity), 37 | fractional_tokens_(0.0), 38 | fill_rate_(fill_rate), 39 | fill_time_ns_(NowInNanoseconds()) { 40 | tokens_ = capacity; 41 | } 42 | 43 | 44 | bool LeakyBucket::RequestTokensSlow(int64 requested_tokens) { 45 | // Getting the time outside the lock is significantly faster (reduces 46 | // contention, etc.). 47 | const int64 current_time_ns = NowInNanoseconds(); 48 | 49 | std::lock_guard lock(mu_); 50 | 51 | const int64 cur_tokens = AtomicLoadTokens(); 52 | if (cur_tokens >= 0) { 53 | return true; 54 | } 55 | 56 | const int64 available_tokens = 57 | RefillBucket(requested_tokens + cur_tokens, current_time_ns); 58 | if (available_tokens >= 0) { 59 | return true; 60 | } 61 | 62 | // Since we were unable to satisfy the request, we need to restore the 63 | // requested tokens. 64 | AtomicIncrementTokens(requested_tokens); 65 | 66 | return false; 67 | } 68 | 69 | 70 | int64 LeakyBucket::RefillBucket( 71 | int64 available_tokens, 72 | int64 current_time_ns) { 73 | if (current_time_ns <= fill_time_ns_) { 74 | // We check to see if the bucket has been refilled after we checked the 75 | // current time but before we grabbed mu_. If it has there's nothing to do. 76 | return AtomicLoadTokens(); 77 | } 78 | 79 | const int64 elapsed_ns = current_time_ns - fill_time_ns_; 80 | fill_time_ns_ = current_time_ns; 81 | 82 | // Calculate the number of tokens we can add. Note elapsed is in ns while 83 | // fill_rate_ is in tokens per second, hence the scaling factor. 84 | // We can get a negative amount of tokens by calling TakeTokens. Make sure we 85 | // don't add more than the capacity of leaky bucket. 86 | fractional_tokens_ += 87 | std::min(elapsed_ns * (fill_rate_ / 1e9), static_cast(capacity_)); 88 | const int64 ideal_tokens_to_add = fractional_tokens_; 89 | 90 | const int64 max_tokens_to_add = capacity_ - available_tokens; 91 | int64 real_tokens_to_add; 92 | if (max_tokens_to_add < ideal_tokens_to_add) { 93 | fractional_tokens_ = 0.0; 94 | real_tokens_to_add = max_tokens_to_add; 95 | } else { 96 | real_tokens_to_add = ideal_tokens_to_add; 97 | fractional_tokens_ -= real_tokens_to_add; 98 | } 99 | 100 | return AtomicIncrementTokens(real_tokens_to_add); 101 | } 102 | 103 | 104 | void LeakyBucket::TakeTokens(int64 tokens) { 105 | const int64 remaining = AtomicIncrementTokens(-tokens); 106 | 107 | if (remaining < 0) { 108 | // (Try to) refill the bucket. If we don't do this, we could just 109 | // keep decreasing forever without refilling. We need to be 110 | // refilling at least as frequently as every capacity_ / 111 | // fill_rate_ seconds. Otherwise, we waste tokens. 112 | const int64 current_time_ns = NowInNanoseconds(); 113 | 114 | std::lock_guard lock(mu_); 115 | RefillBucket(remaining, current_time_ns); 116 | } 117 | } 118 | 119 | } // namespace cdbg 120 | } // namespace devtools 121 | -------------------------------------------------------------------------------- /tracepointdebug/broker/broker_message_callback.py: -------------------------------------------------------------------------------- 1 | import json 2 | from tracepointdebug.probe.dynamicConfig.dynamic_config_manager import DynamicConfigManager 3 | 4 | from tracepointdebug.probe.encoder import to_json 5 | from tracepointdebug.probe.handler import ( DisableTracePointRequestHandler, 6 | EnableTracePointRequestHandler, PutTracePointRequestHandler, RemoveTracePointRequestHandler, 7 | UpdateTracePointRequestHandler, FilterTracePointsResponseHandler, DisableLogPointRequestHandler, 8 | EnableLogPointRequestHandler, PutLogPointRequestHandler, RemoveLogPointRequestHandler, UpdateLogPointRequestHandler, 9 | FilterLogPointsResponseHandler, EnableProbeTagRequestHandler, DisableProbeTagRequestHandler, GetConfigResponseHandler, 10 | AttachRequestHandler, DetachRequestHandler, UpdateConfigRequestHandler, RemoveProbeTagRequestHandler) 11 | from tracepointdebug.utils import debug_logger 12 | 13 | MESSAGE_REQUEST_TYPE = "Request" 14 | MESSAGE_RESPONSE_TYPE = "Response" 15 | 16 | REQUEST_HANDLER_MAP = { 17 | "DisableTracePointRequest": DisableTracePointRequestHandler, 18 | "EnableTracePointRequest": EnableTracePointRequestHandler, 19 | "PutTracePointRequest": PutTracePointRequestHandler, 20 | "RemoveTracePointRequest": RemoveTracePointRequestHandler, 21 | "UpdateTracePointRequest": UpdateTracePointRequestHandler, 22 | 23 | "DisableLogPointRequest": DisableLogPointRequestHandler, 24 | "EnableLogPointRequest": EnableLogPointRequestHandler, 25 | "PutLogPointRequest": PutLogPointRequestHandler, 26 | "RemoveLogPointRequest": RemoveLogPointRequestHandler, 27 | "UpdateLogPointRequest": UpdateLogPointRequestHandler, 28 | 29 | "EnableProbeTagRequest": EnableProbeTagRequestHandler, 30 | "DisableProbeTagRequest": DisableProbeTagRequestHandler, 31 | "RemoveProveTagRequest": RemoveProbeTagRequestHandler, 32 | 33 | "UpdateConfigRequest": UpdateConfigRequestHandler, 34 | "AttachRequest": AttachRequestHandler, 35 | "DetachRequest": DetachRequestHandler 36 | } 37 | 38 | RESPONSE_HANDLER_MAP = { 39 | "FilterTracePointsResponse": FilterTracePointsResponseHandler, 40 | "FilterLogPointsResponse": FilterLogPointsResponseHandler, 41 | "GetConfigResponse": GetConfigResponseHandler 42 | } 43 | 44 | 45 | class BrokerMessageCallback(object): 46 | 47 | def on_message(self, broker_client, message): 48 | try: 49 | dynamic_config_manager = DynamicConfigManager.instance() 50 | attached = dynamic_config_manager.attached 51 | message = json.loads(message) 52 | 53 | message_type = message.get("type", None) 54 | if attached: 55 | if message_type == MESSAGE_REQUEST_TYPE and message.get("name") != "AttachRequest": 56 | self._handle_requests(message, broker_client) 57 | elif message_type == MESSAGE_RESPONSE_TYPE: 58 | self._handle_responses(message) 59 | else: 60 | if message_type == MESSAGE_REQUEST_TYPE and message.get("name") == "AttachRequest": 61 | self._handle_requests(message, broker_client) 62 | else: 63 | return 64 | except Exception as e: 65 | debug_logger(e) 66 | 67 | def _handle_requests(self, message, broker_client): 68 | handler = REQUEST_HANDLER_MAP.get(message.get("name")) 69 | if handler is not None: 70 | request = handler.get_request_cls()(message) 71 | response = handler.handle_request(request) 72 | serialized = to_json(response) 73 | broker_client.send(serialized) 74 | else: 75 | debug_logger("No request handler could be found for message with name {}: {}".format(message.get("name"), 76 | message)) 77 | 78 | def _handle_responses(self, message): 79 | handler = RESPONSE_HANDLER_MAP.get(message.get("name")) 80 | if handler is not None: 81 | response = handler.get_response_cls()(**message) 82 | handler.handle_response(response) 83 | else: 84 | debug_logger("No response handler could be found for message with name {}: {}".format(message.get("name"), 85 | message)) --------------------------------------------------------------------------------