def test_default_cert_path(monkeypatch, system_certs_available): if system_certs_available: cert_file = "foo" else: cert_file = None class DefaultVerifyPaths(object): cafile = cert_file def __init__(self, *args, **kwargs): pass monkeypatch.setattr(ssl, "DefaultVerifyPaths", DefaultVerifyPaths) internal_metrics = CustomMetrics() with InternalTraceContext(internal_metrics): client = HttpClient("localhost", ca_bundle_path=None) internal_metrics = dict(internal_metrics.metrics()) cert_metric = "Supportability/Python/Certificate/BundleRequired" if system_certs_available: assert "ca_certs" not in client._connection_kwargs assert cert_metric not in internal_metrics else: assert client._connection_kwargs["ca_certs"] == certs.where() assert internal_metrics[cert_metric][-3:-1] == [1, 1]
def test_status_code_exceptions(status_code, expected_exc, log_level, caplog): caplog.set_level(logging.INFO) HttpClientRecorder.STATUS_CODE = status_code settings = finalize_application_settings({ "license_key": "123LICENSEKEY", }) protocol = AgentProtocol(settings, client_cls=HttpClientRecorder) internal_metrics = CustomMetrics() with InternalTraceContext(internal_metrics): with pytest.raises(expected_exc): protocol.send("analytic_event_data") internal_metrics = dict(internal_metrics.metrics()) if status_code == 413: assert internal_metrics[ "Supportability/Python/Collector/MaxPayloadSizeLimit/analytic_event_data"] == [ 1, 0, 0, 0, 0, 0 ] else: assert ( "Supportability/Python/Collector/MaxPayloadSizeLimit/analytic_event_data" not in internal_metrics) assert len(HttpClientRecorder.SENT) == 1 request = HttpClientRecorder.SENT[0] assert request.params["method"] == "analytic_event_data" assert len(caplog.records) == 1 assert caplog.records[0].levelname == log_level message = caplog.records[0].getMessage() assert "123LICENSEKEY" not in message
def test_audit_logging(server, insecure_server, client_cls, proxy_host, exception): audit_log_fp = StringIO() params = {"method": "metric_data"} prefix = getattr(client_cls, "PREFIX_SCHEME", "https://") if exception: port = MockExternalHTTPServer.get_open_port() elif prefix == "https://": port = server.port else: port = insecure_server.port internal_metrics = CustomMetrics() with client_cls( "localhost", port, proxy_scheme="https", proxy_host=proxy_host, proxy_port=server.port if not exception else port, audit_log_fp=audit_log_fp, disable_certificate_validation=True, ) as client: with InternalTraceContext(internal_metrics): try: client.send_request(params=params) exc = "" except Exception as e: exc = callable_name(type(e.args[0])) internal_metrics = dict(internal_metrics.metrics()) if exception and client_cls is ApplicationModeClient: if proxy_host: connection = "https-proxy" else: connection = "direct" assert internal_metrics == { "Supportability/Python/Collector/Failures": [1, 0, 0, 0, 0, 0], "Supportability/Python/Collector/Failures/%s" % connection: [1, 0, 0, 0, 0, 0], "Supportability/Python/Collector/Exception/%s" % exc: [1, 0, 0, 0, 0, 0], } else: assert not internal_metrics # Verify the audit log isn't empty assert audit_log_fp.tell() audit_log_fp.seek(0) audit_log_contents = audit_log_fp.read() assert prefix in audit_log_contents
def test_non_ok_response(client_cls, server): internal_metrics = CustomMetrics() with client_cls( "localhost", server.port, disable_certificate_validation=True ) as client: with InternalTraceContext(internal_metrics): status, _ = client.send_request(method="PUT") assert status != 200 internal_metrics = dict(internal_metrics.metrics()) if client_cls is ApplicationModeClient: assert internal_metrics == { "Supportability/Python/Collector/Failures": [1, 0, 0, 0, 0, 0], "Supportability/Python/Collector/Failures/direct": [1, 0, 0, 0, 0, 0], "Supportability/Python/Collector/HTTPError/%d" % status: [1, 0, 0, 0, 0, 0], } else: assert not internal_metrics
def __init__(self, application, enabled=None): self._application = application self.thread_id = transaction_cache().current_thread_id() self._transaction_id = id(self) self._transaction_lock = threading.Lock() self._dead = False self._state = self.STATE_PENDING self._settings = None self._priority = 0 self._group = None self._name = None self._frameworks = set() self._frozen_path = None self._node_stack = [] self._request_uri = None self.queue_start = 0.0 self.start_time = 0.0 self.end_time = 0.0 self.stopped = False self._trace_node_count = 0 self._errors = [] self._slow_sql = [] self._stack_trace_count = 0 self._explain_plan_count = 0 self._string_cache = {} self._custom_params = {} self._request_params = {} self._utilization_tracker = None self._thread_utilization_start = None self._thread_utilization_end = None self._thread_utilization_value = None self._cpu_user_time_start = None self._cpu_user_time_end = None self._cpu_user_time_value = 0.0 self._read_length = None self._read_start = None self._read_end = None self._sent_start = None self._sent_end = None self._bytes_read = 0 self._bytes_sent = 0 self._calls_read = 0 self._calls_readline = 0 self._calls_readlines = 0 self._calls_write = 0 self._calls_yield = 0 self._request_environment = {} self._response_properties = {} self._transaction_metrics = {} self.background_task = False self.enabled = False self.autorum_disabled = False self.ignore_transaction = False self.suppress_apdex = False self.suppress_transaction_trace = False self.capture_params = False self.ignored_params = [] self.response_code = 0 self.apdex = 0 self.rum_token = None self.rum_trace = False # 16-digit random hex. Padded with zeros in the front. self.guid = '%016x' % random.getrandbits(64) self.client_cross_process_id = None self.client_account_id = None self.client_application_id = None self.referring_transaction_guid = None self.record_tt = False self._trip_id = None self._referring_path_hash = None self._alternate_path_hashes = {} self.is_part_of_cat = False self.synthetics_resource_id = None self.synthetics_job_id = None self.synthetics_monitor_id = None self.synthetics_header = None self._custom_metrics = CustomMetrics() self._profile_samples = deque() self._profile_frames = {} self._profile_skip = 1 self._profile_count = 0 global_settings = application.global_settings if global_settings.enabled: if enabled or (enabled is None and application.enabled): self._settings = application.settings if not self._settings: application.activate() # We see again if the settings is now valid # in case startup timeout had been specified # and registration had been started and # completed within the timeout. self._settings = application.settings if self._settings: self.enabled = True
def __init__(self, settings, environ): self.gc_time_metrics = CustomMetrics() self.start_time = 0.0 self.previous_stats = {} self.pid = os.getpid()
def test_http_payload_compression(server, client_cls, method, threshold): payload = b"*" * 20 internal_metrics = CustomMetrics() with client_cls( "localhost", server.port, disable_certificate_validation=True, compression_method=method, compression_threshold=threshold, ) as client: with InternalTraceContext(internal_metrics): status, data = client.send_request( payload=payload, params={"method": "test"} ) assert status == 200 data = data.split(b"\n") sent_payload = data[-1] payload_byte_len = len(sent_payload) internal_metrics = dict(internal_metrics.metrics()) if client_cls is ApplicationModeClient: assert internal_metrics["Supportability/Python/Collector/Output/Bytes/test"][ :2 ] == [1, payload_byte_len,] if threshold < 20: # Verify compression time is recorded assert ( internal_metrics["Supportability/Python/Collector/ZLIB/Compress/test"][ 0 ] == 1 ) assert ( internal_metrics["Supportability/Python/Collector/ZLIB/Compress/test"][ 1 ] > 0 ) # Verify the original payload length is recorded assert internal_metrics["Supportability/Python/Collector/ZLIB/Bytes/test"][ :2 ] == [1, len(payload)] assert len(internal_metrics) == 3 else: # Verify no ZLIB compression metrics were sent assert len(internal_metrics) == 1 else: assert not internal_metrics if threshold < 20: expected_content_encoding = method.encode("utf-8") assert sent_payload != payload if method == "deflate": sent_payload = zlib.decompress(sent_payload) elif method == "gzip": decompressor = zlib.decompressobj(31) sent_payload = decompressor.decompress(sent_payload) sent_payload += decompressor.flush() else: expected_content_encoding = b"Identity" for header in data[1:-1]: if header.lower().startswith(b"content-encoding"): _, content_encoding = header.split(b":", 1) content_encoding = content_encoding.strip() break else: assert False, "Missing content-encoding header" assert content_encoding == expected_content_encoding assert sent_payload == payload
def transaction_node(request): default_capacity = SampledDataSet().capacity num_events = default_capacity + 1 custom_events = SampledDataSet(capacity=num_events) for _ in range(num_events): event = create_custom_event("Custom", {}) custom_events.add(event) error = ErrorNode( timestamp=0, type="foo:bar", message="oh no! your foo had a bar", expected=False, span_id=None, stack_trace="", custom_params={}, file_name=None, line_number=None, source=None, ) errors = tuple(error for _ in range(num_events)) function = FunctionNode( group="Function", name="foo", children=(), start_time=0, end_time=1, duration=1, exclusive=1, label=None, params=None, rollup=None, guid="GUID", agent_attributes={}, user_attributes={}, ) children = tuple(function for _ in range(num_events)) root = RootNode( name="Function/main", children=children, start_time=1524764430.0, end_time=1524764430.1, duration=0.1, exclusive=0.1, guid=None, agent_attributes={}, user_attributes={}, path="OtherTransaction/Function/main", trusted_parent_span=None, tracing_vendors=None, ) node = TransactionNode( settings=finalize_application_settings({"agent_run_id": "1234567"}), path="OtherTransaction/Function/main", type="OtherTransaction", group="Function", base_name="main", name_for_metric="Function/main", port=None, request_uri=None, queue_start=0.0, start_time=1524764430.0, end_time=1524764430.1, last_byte_time=0.0, total_time=0.1, response_time=0.1, duration=0.1, exclusive=0.1, root=root, errors=errors, slow_sql=(), custom_events=custom_events, apdex_t=0.5, suppress_apdex=False, custom_metrics=CustomMetrics(), guid="4485b89db608aece", cpu_time=0.0, suppress_transaction_trace=False, client_cross_process_id=None, referring_transaction_guid=None, record_tt=False, synthetics_resource_id=None, synthetics_job_id=None, synthetics_monitor_id=None, synthetics_header=None, is_part_of_cat=False, trip_id="4485b89db608aece", path_hash=None, referring_path_hash=None, alternate_path_hashes=[], trace_intrinsics={}, distributed_trace_intrinsics={}, agent_attributes=[], user_attributes=[], priority=1.0, parent_transport_duration=None, parent_span=None, parent_type=None, parent_account=None, parent_app=None, parent_tx=None, parent_transport_type=None, sampled=True, root_span_guid=None, trace_id="4485b89db608aece", loop_time=0.0, ) return node