diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md index 7f3e594ccd44..38b856901f16 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md @@ -21,7 +21,7 @@ To use this package, you must have: * Azure subscription - [Create a free account][azure_sub] * Azure Monitor - [How to use application insights][application_insights_namespace] * Opentelemetry SDK - [Opentelemtry SDK for Python][ot_sdk_python] -* Python 3.5 or later - [Install Python][python] +* Python 3.6 or later - [Install Python][python] ### Instantiate the client diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 732fe0caa160..73b1e714d5ae 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -6,6 +6,8 @@ from typing import Sequence, Any from urllib.parse import urlparse +from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv.trace import DbSystemValues, SpanAttributes from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult from opentelemetry.sdk.util import ns_to_iso_str from opentelemetry.trace import Span, SpanKind @@ -91,9 +93,9 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: time=ns_to_iso_str(span.start_time), ) if span.resource and span.resource.attributes: - service_name = span.resource.attributes.get("service.name") - service_namespace = span.resource.attributes.get("service.namespace") - service_instance_id = span.resource.attributes.get("service.instance.id") + service_name = span.resource.attributes.get(ResourceAttributes.SERVICE_NAME) + service_namespace = span.resource.attributes.get(ResourceAttributes.SERVICE_NAMESPACE) + service_instance_id = span.resource.attributes.get(ResourceAttributes.SERVICE_INSTANCE_ID) if service_name: if service_namespace: envelope.tags["ai.cloud.role"] = service_namespace + \ @@ -106,8 +108,8 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: envelope.tags["ai.cloud.roleInstance"] = platform.node() # hostname default envelope.tags["ai.internal.nodeName"] = envelope.tags["ai.cloud.roleInstance"] envelope.tags["ai.operation.id"] = "{:032x}".format(span.context.trace_id) - if "enduser.id" in span.attributes: - envelope.tags["ai.user.id"] = span.attributes["enduser.id"] + if SpanAttributes.ENDUSER_ID in span.attributes: + envelope.tags["ai.user.id"] = span.attributes[SpanAttributes.ENDUSER_ID] if span.parent and span.parent.span_id: envelope.tags["ai.operation.parentId"] = "{:016x}".format( span.parent.span_id @@ -116,7 +118,7 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: if span.kind in (SpanKind.CONSUMER, SpanKind.SERVER): envelope.name = "Microsoft.ApplicationInsights.Request" data = RequestData( - name=span.name[:1024], # Breeze max length + name=span.name, id="{:016x}".format(span.context.span_id), duration=_utils.ns_to_duration(span.end_time - span.start_time), response_code="0", @@ -124,86 +126,105 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: properties={}, ) envelope.data = MonitorBase(base_data=data, base_type="RequestData") - if "http.method" in span.attributes: # HTTP - envelope.tags["ai.operation.name"] = "{} {}".format( - span.attributes["http.method"], - span.name, - ) - data.properties["request.name"] = data.name + if SpanAttributes.HTTP_METHOD in span.attributes: # HTTP url = "" - if "http.user_agent" in span.attributes: + path = "" + if SpanAttributes.HTTP_USER_AGENT in span.attributes: # TODO: Not exposed in Swagger, need to update def - envelope.tags["ai.user.userAgent"] = span.attributes["http.user_agent"] - if "http.client_ip" in span.attributes: - envelope.tags["ai.location.ip"] = span.attributes["http.client_ip"] - elif "net.peer.ip" in span.attributes: - envelope.tags["ai.location.ip"] = span.attributes["net.peer.ip"] + envelope.tags["ai.user.userAgent"] = span.attributes[SpanAttributes.HTTP_USER_AGENT] + if SpanAttributes.HTTP_CLIENT_IP in span.attributes: + envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.HTTP_CLIENT_IP] + elif SpanAttributes.NET_PEER_IP in span.attributes: + envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP] # url - if "http.url" in span.attributes: - url = span.attributes["http.url"] - elif "http.scheme" in span.attributes and "http.target" in span.attributes: - scheme = span.attributes["http.scheme"] - http_target = span.attributes["http.target"] - if "http.host" in span.attributes: + if SpanAttributes.HTTP_URL in span.attributes: + url = span.attributes[SpanAttributes.HTTP_URL] + elif SpanAttributes.HTTP_SCHEME in span.attributes and SpanAttributes.HTTP_TARGET in span.attributes: + scheme = span.attributes[SpanAttributes.HTTP_SCHEME] + http_target = span.attributes[SpanAttributes.HTTP_TARGET] + if SpanAttributes.HTTP_HOST in span.attributes: url = "{}://{}{}".format( scheme, - span.attributes["http.host"], + span.attributes[SpanAttributes.HTTP_HOST], http_target, ) - elif "net.host.port" in span.attributes: - host_port = span.attributes["net.host.port"] - if "http.server_name" in span.attributes: - server_name = span.attributes["http.server_name"] + elif SpanAttributes.NET_HOST_PORT in span.attributes: + host_port = span.attributes[SpanAttributes.NET_HOST_PORT] + if SpanAttributes.HTTP_SERVER_NAME in span.attributes: + server_name = span.attributes[SpanAttributes.HTTP_SERVER_NAME] url = "{}://{}:{}{}".format( scheme, server_name, host_port, http_target, ) - elif "net.host.name" in span.attributes: - host_name = span.attributes["net.host.name"] + elif SpanAttributes.NET_HOST_NAME in span.attributes: + host_name = span.attributes[SpanAttributes.NET_HOST_NAME] url = "{}://{}:{}{}".format( scheme, host_name, host_port, http_target, ) - if url: - url = url[:2048] # Breeze max length data.url = url - data.properties["request.url"] = url - if "http.status_code" in span.attributes: - status_code = span.attributes["http.status_code"] + # Http specific logic for ai.operation.name + if SpanAttributes.HTTP_ROUTE in span.attributes: + envelope.tags["ai.operation.name"] = "{} {}".format( + span.attributes[SpanAttributes.HTTP_METHOD], + span.attributes[SpanAttributes.HTTP_ROUTE], + ) + elif url: + try: + parse_url = urlparse(url) + path = parse_url.path + if not path: + path = "/" + envelope.tags["ai.operation.name"] = "{} {}".format( + span.attributes[SpanAttributes.HTTP_METHOD], + path, + ) + except Exception: # pylint: disable=broad-except + pass + else: + envelope.tags["ai.operation.name"] = span.name + if SpanAttributes.HTTP_STATUS_CODE in span.attributes: + status_code = span.attributes[SpanAttributes.HTTP_STATUS_CODE] data.response_code = str(status_code) - elif "messaging.system" in span.attributes: # Messaging + elif SpanAttributes.MESSAGING_SYSTEM in span.attributes: # Messaging envelope.tags["ai.operation.name"] = span.name - if "net.peer.ip" in span.attributes: - envelope.tags["ai.location.ip"] = span.attributes["net.peer.ip"] - if "messaging.destination" in span.attributes: - if "net.peer.name" in span.attributes: + if SpanAttributes.NET_PEER_IP in span.attributes: + envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP] + if SpanAttributes.MESSAGING_DESTINATION in span.attributes: + if SpanAttributes.NET_PEER_NAME in span.attributes: data.properties["source"] = "{}/{}".format( - span.attributes["net.peer.name"], - span.attributes["messaging.destination"], + span.attributes[SpanAttributes.NET_PEER_NAME], + span.attributes[SpanAttributes.MESSAGING_DESTINATION], ) - elif "net.peer.ip" in span.attributes: + elif SpanAttributes.NET_PEER_IP in span.attributes: data.properties["source"] = "{}/{}".format( - span.attributes["net.peer.ip"], - span.attributes["messaging.destination"], + span.attributes[SpanAttributes.NET_PEER_IP], + span.attributes[SpanAttributes.MESSAGING_DESTINATION], ) else: - data.properties["source"] = span.attributes["messaging.destination"] + data.properties["source"] = span.attributes[SpanAttributes.MESSAGING_DESTINATION] else: # Other envelope.tags["ai.operation.name"] = span.name - if "net.peer.ip" in span.attributes: - envelope.tags["ai.location.ip"] = span.attributes["net.peer.ip"] - data.response_code = data.response_code[:1024] # Breeze max length + if SpanAttributes.NET_PEER_IP in span.attributes: + envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP] + # Apply truncation + if data.url: + data.url = data.url[:2048] # Breeze max length + if data.response_code: + data.response_code = data.response_code[:1024] # Breeze max length + if envelope.tags["ai.operation.name"]: + data.name = envelope.tags["ai.operation.name"][:1024] # Breeze max length else: # INTERNAL, CLIENT, PRODUCER envelope.name = "Microsoft.ApplicationInsights.RemoteDependency" # TODO: ai.operation.name for non-server spans data = RemoteDependencyData( - name=span.name[:1024], # Breeze max length + name=span.name, id="{:016x}".format(span.context.span_id), - result_code=str(span.status.status_code.value), + result_code="0", duration=_utils.ns_to_duration(span.end_time - span.start_time), success=span.status.is_ok, properties={}, @@ -212,110 +233,123 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: base_data=data, base_type="RemoteDependencyData" ) target = None - if "peer.service" in span.attributes: - target = span.attributes["peer.service"] + if SpanAttributes.PEER_SERVICE in span.attributes: + target = span.attributes[SpanAttributes.PEER_SERVICE] else: - if "net.peer.name" in span.attributes: - target = span.attributes["net.peer.name"] - elif "net.peer.ip" in span.attributes: - target = span.attributes["net.peer.ip"] - if "net.peer.port" in span.attributes: - port = span.attributes["net.peer.port"] + if SpanAttributes.NET_PEER_NAME in span.attributes: + target = span.attributes[SpanAttributes.NET_PEER_NAME] + elif SpanAttributes.NET_PEER_IP in span.attributes: + target = span.attributes[SpanAttributes.NET_PEER_IP] + if SpanAttributes.NET_PEER_PORT in span.attributes: + port = span.attributes[SpanAttributes.NET_PEER_PORT] # TODO: check default port for rpc # This logic assumes default ports never conflict across dependency types - if port != _get_default_port_http(span.attributes.get("http.scheme")) and \ - port != _get_default_port_db(span.attributes.get("db.system")): + if port != _get_default_port_http(span.attributes.get(SpanAttributes.HTTP_SCHEME)) and \ + port != _get_default_port_db(span.attributes.get(SpanAttributes.DB_SYSTEM)): target = "{}:{}".format(target, port) if span.kind is SpanKind.CLIENT: - if "http.method" in span.attributes: # HTTP + if SpanAttributes.HTTP_METHOD in span.attributes: # HTTP data.type = "HTTP" - if "http.user_agent" in span.attributes: + if SpanAttributes.HTTP_USER_AGENT in span.attributes: # TODO: Not exposed in Swagger, need to update def - envelope.tags["ai.user.userAgent"] = span.attributes["http.user_agent"] - scheme = span.attributes.get("http.scheme") - url = "" - # Target - if "http.url" in span.attributes: - url = span.attributes["http.url"] - # http specific logic for target - if "peer.service" not in span.attributes: - try: - parse_url = urlparse(url) - if parse_url.port == _get_default_port_http(scheme): - target = parse_url.hostname - else: - target = parse_url.netloc - except Exception: # pylint: disable=broad-except - logger.warning("Error while parsing url.") - # http specific logic for target - if "peer.service" not in span.attributes and "http.host" in span.attributes: - host = span.attributes["http.host"] - try: - # urlparse insists on absolute URLs starting with "//" - # This logic assumes host does not include a "//" - host_name = urlparse("//" + host) - if host_name.port == _get_default_port_http(scheme): - target = host_name.hostname - else: - target = host - except Exception: # pylint: disable=broad-except - logger.warning("Error while parsing hostname.") + envelope.tags["ai.user.userAgent"] = span.attributes[SpanAttributes.HTTP_USER_AGENT] + scheme = span.attributes.get(SpanAttributes.HTTP_SCHEME) # url - if not url: - if scheme and "http.target" in span.attributes: - http_target = span.attributes["http.target"] - if "http.host" in span.attributes: - url = "{}://{}{}".format( + url = "" + if SpanAttributes.HTTP_URL in span.attributes: + url = span.attributes[SpanAttributes.HTTP_URL] + elif scheme and SpanAttributes.HTTP_TARGET in span.attributes: + http_target = span.attributes[SpanAttributes.HTTP_TARGET] + if SpanAttributes.HTTP_HOST in span.attributes: + url = "{}://{}{}".format( + scheme, + span.attributes[SpanAttributes.HTTP_HOST], + http_target, + ) + elif SpanAttributes.NET_PEER_PORT in span.attributes: + peer_port = span.attributes[SpanAttributes.NET_PEER_PORT] + if SpanAttributes.NET_PEER_NAME in span.attributes: + peer_name = span.attributes[SpanAttributes.NET_PEER_NAME] + url = "{}://{}:{}{}".format( scheme, - span.attributes["http.host"], + peer_name, + peer_port, http_target, ) - elif "net.peer.port" in span.attributes: - peer_port = span.attributes["net.peer.port"] - if "net.peer.name" in span.attributes: - peer_name = span.attributes["net.peer.name"] - url = "{}://{}:{}{}".format( - scheme, - peer_name, - peer_port, - http_target, - ) - elif "net.peer.ip" in span.attributes: - peer_ip = span.attributes["net.peer.ip"] - url = "{}://{}:{}{}".format( - scheme, - peer_ip, - peer_port, - http_target, - ) + elif SpanAttributes.NET_PEER_IP in span.attributes: + peer_ip = span.attributes[SpanAttributes.NET_PEER_IP] + url = "{}://{}:{}{}".format( + scheme, + peer_ip, + peer_port, + http_target, + ) + target_from_url = "" + path = "" + if url: + try: + parse_url = urlparse(url) + path = parse_url.path + if not path: + path = "/" + if parse_url.port == _get_default_port_http(scheme): + target_from_url = parse_url.hostname + else: + target_from_url = parse_url.netloc + except Exception: # pylint: disable=broad-except + pass + # http specific logic for name + if path: + data.name = "{} {}".format( + span.attributes[SpanAttributes.HTTP_METHOD], + path, + ) + # http specific logic for target + if SpanAttributes.PEER_SERVICE not in span.attributes: + if SpanAttributes.HTTP_HOST in span.attributes: + host = span.attributes[SpanAttributes.HTTP_HOST] + try: + # urlparse insists on absolute URLs starting with "//" + # This logic assumes host does not include a "//" + host_name = urlparse("//" + host) + if host_name.port == _get_default_port_http(scheme): + target = host_name.hostname + else: + target = host + except Exception: # pylint: disable=broad-except + logger.warning("Error while parsing hostname.") + elif target_from_url: + target = target_from_url # data is url data.data = url - if "http.status_code" in span.attributes: - status_code = span.attributes["http.status_code"] + if SpanAttributes.HTTP_STATUS_CODE in span.attributes: + status_code = span.attributes[SpanAttributes.HTTP_STATUS_CODE] data.result_code = str(status_code) - elif "db.system" in span.attributes: # Database - db_system = span.attributes["db.system"] - if _is_relational_db(db_system): - data.type = "SQL" - else: + elif SpanAttributes.DB_SYSTEM in span.attributes: # Database + db_system = span.attributes[SpanAttributes.DB_SYSTEM] + if not _is_sql_db(db_system): data.type = db_system - # data is the full statement - if "db.statement" in span.attributes: - data.data = span.attributes["db.statement"] + else: + data.type = "SQL" + # data is the full statement or operation + if SpanAttributes.DB_STATEMENT in span.attributes: + data.data = span.attributes[SpanAttributes.DB_STATEMENT] + elif SpanAttributes.DB_OPERATION in span.attributes: + data.data = span.attributes[SpanAttributes.DB_OPERATION] # db specific logic for target - if "db.name" in span.attributes: - db_name = span.attributes["db.name"] + if SpanAttributes.DB_NAME in span.attributes: + db_name = span.attributes[SpanAttributes.DB_NAME] if target is None: target = db_name else: - target = "{}/{}".format(target, db_name) + target = "{}|{}".format(target, db_name) if target is None: target = db_system - elif "rpc.system" in span.attributes: # Rpc - data.type = "rpc.system" + elif SpanAttributes.RPC_SYSTEM in span.attributes: # Rpc + data.type = SpanAttributes.RPC_SYSTEM # TODO: data.data for rpc if target is None: - target = span.attributes["rpc.system"] + target = span.attributes[SpanAttributes.RPC_SYSTEM] else: # TODO: Azure specific types data.type = "N/A" @@ -334,6 +368,8 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: data.data = data.data[:8192] if target: data.target = target[:1024] + if data.name: + data.name = data.name[:1024] for key, val in span.attributes.items(): # Remove Opentelemetry related span attributes from custom dimensions if key.startswith("http.") or \ @@ -361,16 +397,28 @@ def _convert_span_to_envelope(span: Span) -> TelemetryItem: return envelope +# pylint:disable=too-many-return-statements def _get_default_port_db(dbsystem): - if dbsystem == "postgresql": + if dbsystem == DbSystemValues.POSTGRESQL.value: return 5432 - if dbsystem == "mysql": + if dbsystem == DbSystemValues.CASSANDRA.value: + return 9042 + if dbsystem in (DbSystemValues.MARIADB.value, DbSystemValues.MYSQL.value): return 3306 + if dbsystem == DbSystemValues.MSSQL.value: + return 1433 + # TODO: Add in memcached if dbsystem == "memcached": return 11211 - if dbsystem == "mongodb": - return 27017 - if dbsystem == "redis": + if dbsystem == DbSystemValues.DB2.value: + return 50000 + if dbsystem == DbSystemValues.ORACLE.value: + return 1521 + if dbsystem == DbSystemValues.H2.value: + return 8082 + if dbsystem == DbSystemValues.DERBY.value: + return 1527 + if dbsystem == DbSystemValues.REDIS.value: return 6379 return 0 @@ -383,5 +431,15 @@ def _get_default_port_http(scheme): return 0 -def _is_relational_db(dbsystem): - return dbsystem in ["postgresql", "mysql"] +def _is_sql_db(dbsystem): + return dbsystem in ( + DbSystemValues.DB2.value, + DbSystemValues.DERBY.value, + DbSystemValues.MARIADB.value, + DbSystemValues.MSSQL.value, + DbSystemValues.ORACLE.value, + DbSystemValues.SQLITE.value, + DbSystemValues.OTHER_SQL.value, + DbSystemValues.HSQLDB.value, + DbSystemValues.H2.value, + ) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py index cf58f037345b..3bc7ffc523a6 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py @@ -243,7 +243,7 @@ def test_span_to_envelope_client_http(self): envelope.name, "Microsoft.ApplicationInsights.RemoteDependency" ) self.assertEqual(envelope.time, "2019-12-04T21:18:36.027613Z") - self.assertEqual(envelope.data.base_data.name, "test") + self.assertEqual(envelope.data.base_data.name, "GET /wiki/Rabbit") self.assertEqual(envelope.data.base_data.id, "a6f5d48acb4d31d9") self.assertEqual(envelope.data.base_data.duration, "0.00:00:01.001") self.assertTrue(envelope.data.base_data.success) @@ -258,6 +258,15 @@ def test_span_to_envelope_client_http(self): self.assertEqual(envelope.data.base_data.result_code, "200") self.assertEqual(envelope.tags["ai.user.userAgent"], "agent") + # Name empty + span._attributes = { + "http.method": "GET", + "http.scheme": "https", + "http.url": "https://www.example.com", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.data.base_data.name, "GET /") + # Target span._attributes = { "http.method": "GET", @@ -339,7 +348,7 @@ def test_span_to_envelope_client_db(self): attributes={ "db.system": "postgresql", "peer.service": "service", - "db.statement": "SELECT", + "db.statement": "SELECT * from test", }, kind=SpanKind.CLIENT, ) @@ -358,10 +367,19 @@ def test_span_to_envelope_client_db(self): self.assertTrue(envelope.data.base_data.success) self.assertEqual(envelope.data.base_type, "RemoteDependencyData") - self.assertEqual(envelope.data.base_data.type, "SQL") + self.assertEqual(envelope.data.base_data.type, "postgresql") self.assertEqual(envelope.data.base_data.target, "service") + self.assertEqual(envelope.data.base_data.data, "SELECT * from test") + self.assertEqual(envelope.data.base_data.result_code, "0") + + # data + span._attributes = { + "db.system": "postgresql", + "peer.service": "service", + "db.operation": "SELECT", + } + envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.data, "SELECT") - self.assertEqual(envelope.data.base_data.result_code, "1") # Target span._attributes = { @@ -371,7 +389,7 @@ def test_span_to_envelope_client_db(self): "peer.service": "service", } envelope = exporter._span_to_envelope(span) - self.assertEqual(envelope.data.base_data.target, "service/testDb") + self.assertEqual(envelope.data.base_data.target, "service|testDb") span._attributes = { "db.system": "postgresql", @@ -387,6 +405,16 @@ def test_span_to_envelope_client_db(self): envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.target, "postgresql") + # Type + span._attributes = { + "db.system": "mssql", + "db.statement": "SELECT", + "db.name": "testDb", + "peer.service": "service", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.data.base_data.type, "SQL") + def test_span_to_envelope_client_rpc(self): exporter = self._exporter start_time = 1575494316027613500 @@ -435,7 +463,7 @@ def test_span_to_envelope_client_rpc(self): # TODO: data.data # self.assertEqual(envelope.data.base_data.data, "SELECT") - self.assertEqual(envelope.data.base_data.result_code, "1") + self.assertEqual(envelope.data.base_data.result_code, "0") def test_span_to_envelope_producer_messaging(self): exporter = self._exporter @@ -477,7 +505,7 @@ def test_span_to_envelope_producer_messaging(self): # self.assertEqual(envelope.data.base_data.target, "rpc") # TODO: data.data # self.assertEqual(envelope.data.base_data.data, "SELECT") - self.assertEqual(envelope.data.base_data.result_code, "1") + self.assertEqual(envelope.data.base_data.result_code, "0") def test_span_to_envelope_internal(self): exporter = self._exporter @@ -513,7 +541,7 @@ def test_span_to_envelope_internal(self): self.assertEqual(envelope.data.base_type, "RemoteDependencyData") self.assertEqual(envelope.data.base_data.type, "InProc") - self.assertEqual(envelope.data.base_data.result_code, "1") + self.assertEqual(envelope.data.base_data.result_code, "0") # type span._parent = None @@ -552,18 +580,16 @@ def test_span_envelope_server_http(self): envelope.name, "Microsoft.ApplicationInsights.Request" ) self.assertEqual(envelope.data.base_type, "RequestData") - self.assertEqual(envelope.data.base_data.name, "test") + self.assertEqual(envelope.data.base_data.name, "GET /wiki/Rabbit") self.assertEqual(envelope.data.base_data.id, "a6f5d48acb4d31d9") self.assertEqual(envelope.data.base_data.duration, "0.00:00:01.001") self.assertEqual(envelope.data.base_data.response_code, "200") self.assertTrue(envelope.data.base_data.success) - self.assertEqual(envelope.tags["ai.operation.name"], "GET test") + self.assertEqual(envelope.tags["ai.operation.name"], "GET /wiki/Rabbit") self.assertEqual(envelope.tags["ai.user.userAgent"], "agent") self.assertEqual(envelope.tags["ai.location.ip"], "client_ip") self.assertEqual(envelope.data.base_data.url, "https://www.wikipedia.org/wiki/Rabbit") - self.assertEqual(envelope.data.base_data.properties["request.name"], "test") - self.assertEqual(envelope.data.base_data.properties["request.url"], "https://www.wikipedia.org/wiki/Rabbit") # location span._attributes = { @@ -603,6 +629,22 @@ def test_span_envelope_server_http(self): envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.url, "https://localhost:35555/path") + # ai.operation.name + span._attributes = { + "http.method": "GET", + "http.url": "https://www.wikipedia.org/wiki/Rabbit/test", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.tags["ai.operation.name"], "GET /wiki/Rabbit/test") + self.assertEqual(envelope.data.base_data.name, "GET /wiki/Rabbit/test") + + span._attributes = { + "http.method": "GET", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.tags["ai.operation.name"], "test") + self.assertEqual(envelope.data.base_data.name, "test") + def test_span_envelope_server_messaging(self): exporter = self._exporter start_time = 1575494316027613500